package game

import (
	"World/common"
	pb "World/pb"
	"bytes"
	"common/logger"
	"encoding/binary"
	"net"
	"time"

	"github.com/golang/protobuf/proto"
)

func SendMessage(player *common.GamePlayer, conn net.Conn, header pb.MessageHeader, msgid pb.MSGID, msg interface{}) bool {
	if conn == nil {
		logger.Notic("send message failed with nil conn, playerid:%v msgid:%v", header.PlayerID, msgid)
		return false
	}
	tmp, err := proto.Marshal(msg.(proto.Message))
	if err != nil {
		logger.Notic("marshal msgid:%v response body error:%v", msgid, err)
		return false
	}

	if player != nil {
		if !common.IsPlayerInPlayerMap(player.UID) {
			return false
		}
	}
	
	logger.Info("send message response uid:%v msgid:%+v", header.PlayerID, pb.MSGID(msgid))
	
	total_len := len(tmp) + int(common.Min_Message_Size)
	bys := new(bytes.Buffer)
	binary.Write(bys, binary.BigEndian, uint16(total_len))
	binary.Write(bys, binary.BigEndian, uint16(msgid))
	binary.Write(bys, binary.BigEndian, uint32(header.Seq))
	binary.Write(bys, binary.BigEndian, uint32(header.PlayerID))
	binary.Write(bys, binary.BigEndian, uint32(header.RoomID))
	buf := append(bys.Bytes(), tmp...)
	if player != nil {
		select {
		case player.OutChannel <- buf:
			break
		case <-time.After(time.Millisecond * 20):
			logger.Notic("send response to uid:%v roomid:%v timeout, channel full", header.PlayerID, header.RoomID)
			return false
		}
	} else {
		//WriteMessage2Conn(player.UID, conn, buf)
		conn.SetWriteDeadline(time.Now().Add(1 * time.Second))
		_, err := conn.Write(buf)
		if err != nil {
			logger.Notic("send socket messeage error:%v ip:%v", err, conn.RemoteAddr().String)
		}
	}

	return true
}

func CheckCreateClubLimit(player *common.GamePlayer, params pb.ClubParams) common.ErrorType {
	return common.Error_OK
}

func CheckCreateClubParams(player *common.GamePlayer, params pb.ClubParams) common.ErrorType {

	//检查创建俱乐部各个参数合法性
	var err common.ErrorType
	err = common.Error_CreateClub_Params_Invalid

	for {

		err = common.Error_OK
		break
	}

	return err
}

func ConnWriter(player *common.GamePlayer) {
	if player == nil {
		logger.Info("conn writer routine start failed with nil player")
		return
	}
	logger.Info("conn writer routine start uid:%v seq:%v", player.UID, player.ConnSeq)
	
	for {
		select {
		case data := <-player.OutChannel:
			//todo send data to conn
			player.ConnLocker.Lock()
			conn := player.Conn
			player.ConnLocker.Unlock()

			WriteMessage2Conn(player.UID, conn, data)

		case _ = <-player.OutDone:
			logger.Info("conn writer routine end 2 uid:%v seq:%v", player.UID, player.ConnSeq)
			return
		}
	}
	logger.Info("conn writer routine end uid:%v seq:%v", player.UID, player.ConnSeq)
}

func WriteMessage2Conn(uid int, conn net.Conn, data []byte) {
	if conn == nil {
		return
	}
	conn.SetWriteDeadline(time.Now().Add(1 * time.Second))
	_, err := conn.Write(data)
	if err != nil {
		logger.Notic("send socket messeage error:%v uid:%v ip:%v", err, uid, conn.RemoteAddr().String)
	}else{
		logger.Info("send socket message success for uid:%v data:%s", uid, conn.RemoteAddr().String())
	}
}
