package com.robot;

import java.util.List;
import java.util.Map;

import com.data.bean.AccountBean;
import com.data.cache.AccountCache;
import com.data.cache.GroupMemberCache;
import com.data.util.ErrorCode;
import com.robot.data.JoinRoomData;
import com.robot.data.Player;
import com.robot.data.Room;
import com.robot.player.state.PlayerInitState;
import com.robot.player.state.PlayerReadyState;
import com.robot.room.state.RoomDestoryGameState;
import com.taurus.core.entity.ITArray;
import com.taurus.core.entity.ITObject;
import com.taurus.core.entity.TArray;
import com.taurus.core.entity.TObject;
import com.taurus.core.plugin.redis.Redis;
import com.taurus.core.plugin.redis.RedisLock;
import com.taurus.core.routes.ActionKey;
import com.taurus.core.routes.IController;
import com.taurus.core.util.StringUtil;
import com.taurus.permanent.data.Session;

import redis.clients.jedis.Jedis;

/**
 * 基本游戏控制器
 * 
 */
public class GameController implements IController{


	/**
	 * 聊天
	 */
	@ActionKey(Router.GAME_INTERACTION)
	public void routerChat(Session sender, ITObject params, int gid, Player owner) {
		owner.room.broadCastToClient(0, Router.GAME_EVT_INTERACTION, params);
	}

	/**
	 * 请求准备
	 *
	 */
	@ActionKey(Router.GAME_READY)
	public void routerReady(Session sender,ITObject params,int gid,Player owner) {
		owner.stateMachine.execute(ActionEvent.EVENT_READY, gid, params);
	}

	/**
	 * 请求准备
	 *
	 */
	@ActionKey(Router.GAME_READY_AND_XIPAI)
	public void routerReadyAndXiPai(Session sender,ITObject params,int gid,Player owner) {
		owner.stateMachine.execute(ActionEvent.EVENT_READY_AND_XIPAI, gid, params);
	}
	

	/**
	 * 请求开始游戏
	 */
	@ActionKey(Router.GAME_START)
	public void routerStartGame(Session sender,ITObject params,int gid,Player owner) {
		owner.room.stateMachine.execute(ActionEvent.EVENT_START_GAME, gid, params);
	}

	@ActionKey(Router.GAME_XIPAI)
	public void RouterXiPai(Session sender,ITObject params,int gid,Player owner) {
		owner.stateMachine.execute(ActionEvent.EVENT_XIPAI, 0, params);
		owner.room.stateMachine.execute(ActionEvent.EVENT_XIPAI, 0, params);
	}
	

	/**
	 * 托管
	 * 
	 */
	@ActionKey(Router.GAME_ENTRUST)
	@SuppressWarnings("unchecked")
	public void routerEntrust(Session sender,ITObject params,int gid,Player owner) {


		if (owner.room.status == Constant.ROOM_STATUS_PLAYING && owner.room.isEntrust()) {
			owner.entrust = params.getBoolean("ok");
			Global.gameCtr.updatePlayerEntrust(owner);
			Global.logger.info(owner + " manual " + (owner.entrust ? "entrust" : "quitEntrust"));
			if (owner.entrust) {
				owner.setEntrustData(params);
				owner.stateMachine.curState.execute(owner, ActionEvent.EVENT_ENTRUST, gid, params);
			} else {
				owner.exitEntrust();
			}
		}
	}

	@ActionKey(value=Router.ROBOT_JOIN_ROOM,validate = GameInterceptor.NOT_PLAYER)
	public void routerRobotJoinRoom(Session sender, ITObject params, int gid) {
		String session_id = params.getUtfString("session");
		// String sessionToken = Utils.getUniqueSessionToken(sender);

		System.out.println("robot 加人房间 ");

		String token = null;
		if (StringUtil.isEmpty(session_id)) {
			Global.logger.info("---------------参数session为null，参数params：{}",params);
			session_id="";
		}
		else {
			String[] sourceStrArray = session_id.split(",");
			if (sourceStrArray.length == 2)
			{
				session_id = sourceStrArray[0];
				token = sourceStrArray[1];
			}

			if (StringUtil.isNotEmpty(token) && StringUtil.isNotEmpty(session_id))
			{
				String token_session = Redis.use("group1_db0").hget(token, "user");
				if (StringUtil.isEmpty(token_session))
				{
					MainServer.instance.sendResponse(gid, ErrorCode._NO_SESSION, null, sender);
					return;
				}
				else {
					if (!token_session.equals(session_id))
					{
						MainServer.instance.sendResponse(gid, ErrorCode._NO_SESSION, null, sender);
						return;
					}
				}
			}
			else {
				MainServer.instance.sendResponse(gid, ErrorCode._NO_SESSION, null, sender);
				return;
			}
		}
		sender.setHashId(session_id);
		String pos = params.getUtfString("pos");
		Global.roomMgr.joinRoom(sender, session_id, gid, pos);
	}


	/**
	 * 请求进入房间
	 */
	@ActionKey(value=Router.GAME_JOIN_ROOM,validate = GameInterceptor.NOT_PLAYER)
	public void routerJoinRoom(Session sender, ITObject params, int gid) {
		String session_id = params.getUtfString("session");
		// String sessionToken = Utils.getUniqueSessionToken(sender);
		String token = null;
		if (StringUtil.isEmpty(session_id)) {
			Global.logger.info("---------------参数session为null，参数params：{}",params);
			session_id="";
		}
		else {
			String[] sourceStrArray = session_id.split(",");
			if (sourceStrArray.length == 2)
			{
				session_id = sourceStrArray[0];
				token = sourceStrArray[1];
			}

			if (StringUtil.isNotEmpty(token) && StringUtil.isNotEmpty(session_id))
			{
				String token_session = Redis.use("group1_db0").hget(token, "user");
				if (StringUtil.isEmpty(token_session))
				{
					MainServer.instance.sendResponse(gid, ErrorCode._NO_SESSION, null, sender);
					return;
				}
				else {
					if (!token_session.equals(session_id))
					{
						MainServer.instance.sendResponse(gid, ErrorCode._NO_SESSION, null, sender);
						return;
					}
				}
			}
			else {
				MainServer.instance.sendResponse(gid, ErrorCode._NO_SESSION, null, sender);
				return;
			}
		}
		sender.setHashId(session_id);
		String pos = params.getUtfString("pos");
		Global.roomMgr.joinRoom(sender, session_id, gid, pos);
	}

	/**
	 * 自动出牌
	 */
	@ActionKey(Router.GAME_AUTO_CARD)
	public void routerAutoCard(Session sender,ITObject params,int gid,Player owner) {
		owner.manualAutoCard = params.getBoolean("autoCard");

		if (owner.manualAutoCard) {
			if (!owner.room.openEntrust){
				owner.manualAutoCard = false;
				return;
			}
		}

		owner.entrust = owner.manualAutoCard;

		Global.gameCtr.updatePlayerEntrust(owner);
		Global.logger.info(owner + " manualAutoCard " + (owner.entrust ? "entrust" : "quitEntrust"));

		if (owner.manualAutoCard) {
			owner.stateMachine.curState.execute(owner, ActionEvent.EVENT_ENTRUST, gid, params);
		} else {
			owner.exitEntrust();
		}
	}


	/**
	 * 请求删除解散房间（外部)
	 *
	 */
	@ActionKey(value=Router.GAME_REMOVE_ROOM,validate = GameInterceptor.NOT_PLAYER)
	public void routerRemoveRoom(Session sender, ITObject params, int gid) {
		try {
			String roomid = params.getUtfString("room");
			// Global.logger.info(" ower del room : " + roomid);
			// if (Global.roomMgr.removeRoom(roomid)) {
			Global.logger.info(roomid + " is destroy!");
			MainServer.instance.sendResponse(gid, 0, null, sender);
			// } else {
			// MainServer.instance.sendResponse(gid, 1, null, sender);
			// }
		} catch (Exception e) {
			Global.logger.error(e);
			MainServer.instance.sendResponse(gid, 1, null, sender);
		}
	}


	/**
	 * 请求退出房间
	 */
	@ActionKey(Router.GAME_EXIT_ROOM)
	public void routerExitRoom(Session sender,ITObject params,int gid,Player owner) {
		owner.stateMachine.execute(ActionEvent.EVENT_EXIT_ROOM, gid, params);
	}
	

	/**
	 * 请求解散房间
	 */
	@ActionKey(Router.GAME_ASK_DISMISS_ROOM)
	public void routerAskDismiss(Session sender,ITObject params,int gid,Player owner) {
		owner.room.dismissRunable.askDismiss(owner, gid);
	}
	

	/**
	 * 房间解散投票请求
	 */
	@ActionKey(Router.GAME_DISMISS_ROOM_VOTE)
	public void routerDismissRoomVote(Session sender,ITObject params,int gid,Player owner) {
		boolean agree = params.getBoolean("result");
		owner.room.dismissRunable.responseDismiss(owner, agree);
	}

	

	/**
	 * 请求更新GPS位置
	 *
	 */
	@ActionKey(Router.GAME_UPDATE_POS)
	public void routerUpdatePos(Session sender,ITObject params,int gid,Player owner) {
		owner.gps_pos = params.getUtfString("pos");
		updatePlayerPos(owner);
	}
	

	/**
	 * 入座
	 */
	@ActionKey(Router.GAME_JOIN_SEAT)
	public void routerJoinSeat(Session sender,ITObject params,int gid,Player owner) {
		Global.gameCtr.joinSeat(owner, gid);
	}
	

	/**
	 * 进入房间
	 * @param parm
	 * @param gid
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public int joinRoom(JoinRoomData parm, int gid) {
		Room owner = parm.room;
		String session_key = parm.session_key;
		Session sender = parm.sender;
		String gps_pos = parm.gps_pos;
		AccountBean acc = AccountCache.getAccount(session_key);
		int playerid = acc.id;

		boolean full = owner.playerMapBySeat.size() >= owner.maxPlayers;
		boolean reload = owner.status == Constant.ROOM_STATUS_PLAYING;
		
		String ip = acc.ip;
		if(StringUtil.isEmpty(ip)) {
			ip = sender.getAddress();
		}
		
		Player player = null;
		boolean new_player = false;
		if (owner.playerMapById.containsKey(playerid)) {
			player = owner.playerMapById.get(playerid);
			if (player.isReload) {
				player.isReload = false;
				player.stateMachine.changeState(Global.getState(PlayerInitState.class));
			}
			player.setSender(sender);
			Global.gameCtr.playerNetState(player);
			Global.gameCtr.updatePlayerPos(player);
		} else {
			if (full) {
				sender.setHashId(null);
				delRoomSeat(session_key, owner.room_key);
				return ErrorCode.ROOM_CLOSE;
			}
			// 检测是否打开GPS 、IP检测
			boolean openGps = owner.isOpenGPSCheck(), openIP = owner.isOpenIPCheck();
			if (openGps || openIP) {
				int errResult = 0;
				if (openGps) {
					Global.warn("room:{},playid:{},gps:{}", owner.room_key, playerid, gps_pos);
					// 开了检测GPS 但是未获取到位置、或未打开
					if (!GPSUtil.isOpenGPS(gps_pos)) {
						errResult = 55;
					}
					// 距离过近
					if (errResult == 0 && owner.checkGps(gps_pos)) {
						errResult = 54;
					}
				}
				if (openIP) {
					// 相同IP
				
					if (errResult == 0 && owner.checkIp(ip)) {
						errResult = 53;
					}
				}
				if (errResult != 0) {
					delRoomSeat(session_key, owner.room_key);
					return errResult;
				}
			}
			boolean onseat = true;
			long cur_hp = 0;
			if (onseat && owner.hpData != null) {
				cur_hp = Util.readRedisHp(owner.groupId, playerid);
				if (!checkHplimitInRoom(owner, cur_hp)) {
					return ErrorCode.GROUP_LIMIT_NO_HP;
				}
			}
			player = MainServer.instance.newPlayer(playerid, owner, session_key);
			player.hp.cur_hp = cur_hp;
			
			owner.addPlayer(player, false, onseat);
			player.setSender(sender);
			player.stateMachine.changeState(Global.getState(PlayerInitState.class));
			new_player = true;
		}

		player.nick = acc.nick;
		player.portrait = acc.portrait;
		player.sex = acc.sex;
		player.ip = ip;
		if (StringUtil.isNotEmpty(gps_pos))
			player.gps_pos = gps_pos;

		ITObject data = new TObject();
		if (reload) {
			data.putTObject("reloadInfo", owner.getReloadInfo(player));
		}
		data.putBoolean("reload", reload);
		data.putInt("owner", owner.owner_id);
		data.putInt("agent", owner.agent ? 1 : 0);
		data.putInt("createTime", Integer.parseInt(owner.redis_room_map.get("create_time")));
		data.putTObject("tableInfo", owner.getRoomInfo());
		player.response(data, gid, 0);

		if (new_player && player.seat != 0) {
			owner.broadCastToClient(player.playerid, Router.GAME_EVT_PLAYER_JOIN, player.getInfo());
		}

		if (reload) {
			owner.join_player = player;
			owner.dismissRunable.reload(player);
			owner.stateMachine.curState.reload(owner);
			player.stateMachine.curState.reload(player);
			owner.join_player = null;
		}
		return 0;

	}

	/**
	 * 玩家不能进入房间，删除redis 玩家身上room、seat
	 * @param session_key
	 * @param owner
	 */
	public void delRoomSeat(String session_key, String room_key) {
		Jedis jedis0 = Redis.use("group1_db0").getJedis();
		RedisLock lock = new RedisLock(session_key, jedis0);
		try {
			lock.lock();
			String cur_room = jedis0.hget(session_key, "room");
			if (StringUtil.isNotEmpty(cur_room)) {
				if (cur_room.equals(room_key)) {
					jedis0.hdel(session_key, "room", "seat");
				}
			}
		} finally {
			lock.unlock();
		}
	}

	/**
	 * 检测加人房间限制
	 * @param owner
	 * @return
	 */
	public boolean checkHplimitInRoom(Room room, long cur_hp) {
		if (room.hpData != null) {
			int limitInRoom = room.hpData.getInt("limitInRoom");
			if (cur_hp < (long)limitInRoom) {
				return false;
			}
		}
		return true;
	}
	
	/**
	 * 检测加人房间限制
	 * @param owner
	 * @return
	 */
	public boolean checkHplimitPlay(Room room, int cur_hp) {
		if (room.hpData != null) {
			int limitInRoom = room.hpData.getInt("limitInRoom");
			if (cur_hp < limitInRoom) {
				return false;
			}
		}
		return true;
	}

	/**
	 * 坐下
	 * @param owner
	 * @param gid
	 */
	public void joinSeat(Player owner, int gid) {
		

	}

	/**
	 * 聊天转发
	 * @param owner
	 * @param params
	 */
	public void chat(Player owner, ITObject params) {
		owner.room.broadCastToClient(0, Router.GAME_EVT_INTERACTION, params);
	}

	/**
	 * 托管事件
	 * @param owner
	 */
	public void entrust(Player owner, int time) {
		ITObject broadParam = new TObject();
		broadParam.putInt("aid", owner.playerid);
		broadParam.putInt("time", time);
		owner.room.broadCastToClient(0, Router.GAME_EVT_READY_ENTRUST, broadParam);
		Global.info("{} Ready Entrust, left time:{}", owner.playerid, time);
	}

	/**
	 * 取消托管事件
	 * @param owner
	 */
	public void cancelEntrust(Player owner) {
		ITObject broadParam = new TObject();
		broadParam.putInt("aid", owner.playerid);
		owner.room.broadCastToClient(0, Router.GAME_EVT_CANCEL_READY_ENTRUST, broadParam);
		//Global.info("{} Cancel Ready Entrust", owner.playerid);
	}


	/**
	 * 准备事件
	 * @param owner
	 */
	public void ready(Player owner) {

		ITObject broadParam = new TObject();
		broadParam.putInt("aid", owner.playerid);
		long cur_hp = Util.readRedisHp(owner.room.groupId, owner.playerid);
		Global.logger.info(owner.playerid + " jefe ready");
		if (cur_hp < owner.hp.cur_hp)
		{
			Global.logger.error("cur hp:" + cur_hp + " < hp.cur_hp:" + owner.hp.cur_hp + " playerId:"+owner.playerid);
			if (owner.room.round == 0 && (!checkHplimitInRoom(owner.room, cur_hp) || cur_hp == 0)) {
				owner.room.saveMilitaryTotal(true);
				owner.room.stateMachine.changeState(Global.getState(RoomDestoryGameState.class));
				String gm_key = GroupMemberCache.genKey(owner.room.groupId, owner.playerid);
				Redis.use("group1_db10").hset(gm_key, "ban", "1");
				Redis.use("group1_db10").hset(gm_key, "group_ban", "1");
				return;
			}
		}
		owner.hp.cur_hp = cur_hp;

		boolean flag = true;
		if (owner.room.maxPlayers == owner.room.playerMapById.size()) {
			for (Map.Entry<Integer, Player> entry : owner.room.playerMapById.entrySet()) {
				if (entry.getValue().playerid != owner.playerid && !(entry.getValue().stateMachine.curState instanceof PlayerReadyState)) {
					flag = false;
					break;
				}
			}
		}
		else {
			flag = false;
		}


		if (flag)
		{
			for (Map.Entry<Integer, Player> entry : owner.room.playerMapById.entrySet()) {
				Player player = entry.getValue();
				Global.logger.info( " player.playerid :"+player.playerid );
				owner.room.redisUpdateAnchouPlayer(player);
			}
		//	owner.room.redisUpdateAnchouPlayer(owner);
			broadParam.putInt("start", 1);
		}
		else
		{
			broadParam.putInt("start", 0);
		}

		owner.room.broadCastToClient(0, Router.GAME_EVT_READY, broadParam);
		owner.stateMachine.changeState(Global.getState(PlayerReadyState.class));
	}


	/**
	 * 准备和洗牌事件
	 * @param owner
	 */
	public void readyAndXipai(Player owner) {
		Global.logger.info(owner.playerid + " jefe readyAndXipai");
		if (owner.xi_pai == false)
		{
			owner.xi_pai = true;
			owner.room.redisUpdateXiPaiPlayer(owner);
		}

		long cur_hp = Util.readRedisHp(owner.room.groupId, owner.playerid);
		if (cur_hp < owner.hp.cur_hp || cur_hp == 0)
		{
			Global.logger.error("cur hp:" + cur_hp + " < hp.cur_hp:" + owner.hp.cur_hp + " playerId:"+owner.playerid);
			if (owner.room.round == 0 && (!checkHplimitInRoom(owner.room, cur_hp) || cur_hp == 0)) {
				owner.room.saveMilitaryTotal(true);
				owner.room.stateMachine.changeState(Global.getState(RoomDestoryGameState.class));
				String gm_key = GroupMemberCache.genKey(owner.room.groupId, owner.playerid);
				Redis.use("group1_db10").hset(gm_key, "ban", "1");
				Redis.use("group1_db10").hset(gm_key, "group_ban", "1");
				return;
			}
		}
		owner.hp.cur_hp = cur_hp;
		ITObject broadParam = new TObject();
		broadParam.putInt("aid", owner.playerid);

		boolean flag = true;
		if (owner.room.maxPlayers == owner.room.playerMapById.size()) {
			for (Map.Entry<Integer, Player> entry : owner.room.playerMapById.entrySet()) {
				if (entry.getValue().playerid != owner.playerid && !(entry.getValue().stateMachine.curState instanceof PlayerReadyState)) {
					flag = false;
					break;
				}
			}
		}
		else {
			flag = false;
		}

		if (flag)
		{


			for (Map.Entry<Integer, Player> entry : owner.room.playerMapById.entrySet()) {
				Player player = entry.getValue();
				Global.logger.info( " player.playerid :"+player.playerid );
				owner.room.redisUpdateAnchouPlayer(player);
			}
			broadParam.putInt("start", 1);
		}
		else
		{
			broadParam.putInt("start", 0);
		}
		owner.room.broadCastToClient(0, Router.GAME_EVT_READY_AND_XIPAI, broadParam);
		owner.stateMachine.changeState(Global.getState(PlayerReadyState.class));
	}

	/**
	 * 解散房间通知
	 * @param askPlayer
	 * @param sender
	 * @param time
	 */
	public void dismissRoom(Player askPlayer, Player sender, List<Player> playerList, int time) {
		ITObject parm = TObject.newInstance();
		parm.putInt("req_aid", askPlayer.playerid);
		parm.putInt("time", time);
		ITArray list = TArray.newInstance();
		parm.putTArray("list", list);
		for (Player player : playerList) {
			ITObject tem = TObject.newInstance();
			tem.putInt("aid", player.playerid);
			tem.putInt("result", player.dismissState);
			list.addTObject(tem);
		}
		if (sender != null) {
			sender.sendEvent(Router.GAME_EVT_DISMISS_ROOM, parm);
		} else {
			askPlayer.room.broadCastToClient(0, Router.GAME_EVT_DISMISS_ROOM, parm);
		}
	}

	/**
	 * 观众席
	 * 
	 * @param owner
	 */
	public void joinSpectator(Player owner) {
		if (owner.room.exitSeat(owner)) {
			if (Global.loggerDebug) {
				Global.logger.info(owner + " exit seat!");
			}
			owner.seat = 0;
			ITObject data = new TObject();
			data.putInt("aid", owner.playerid);
			owner.room.broadCastToClient(0, Router.GAME_EVT_JOIN_SPECTATOR, data);
			owner.room.stateMachine.execute(ActionEvent.EVENT_READY, 0, null);
		}
	}

	/**
	 * 解散失败
	 * @param owner
	 */
	public void dismisRoomFail(Room owner) {
		owner.broadCastToClient(0, Router.GAME_EVT_DISMISS_ROOM_FAIL, null);
	}

	/**
	 * 退出房间
	 * @param owner
	 * @param gid
	 */
	public void exitRoom(Player owner, int gid, boolean kick) {
		if (kick) {
			owner.sendEvent(Router.GAME_EVT_KICK_PLAYER, null);
		} else {
			owner.response(null, gid, 0);
		}
		if (owner.room.status == Constant.ROOM_STATUS_NOBEGIN || owner.spectator) {
			int owner_id = owner.room.owner_id;
			if (!owner.room.agent && owner.playerid == owner_id) {
				owner.room.stateMachine.changeState(Global.getState(RoomDestoryGameState.class));
			} else {
				// 在座位上
				if (owner.room.playerMapBySeat.containsKey(owner.seat)) {
					ITObject data = new TObject();
					data.putInt("aid", owner.playerid);
					owner.room.broadCastToClient(owner.playerid, Router.GAME_EVT_PLAYER_EXIT, data);
				}
				owner.destroy(true);
			}
		}
	}

	/**
	 * 玩家网络状态通知
	 * @param owner
	 */
	public void playerNetState(Player owner) {
		ITObject param = new TObject();
		param.putInt("aid", owner.playerid);
		param.putInt("online", owner.isConnect ? 1 : 0);
		owner.room.updatePlayerOffline(owner);
		owner.room.broadCastToClient(owner.playerid, Router.GAME_EVT_PLAYER_NET_STATE, param);
	}

	/**
	 * 更新玩家GPS位置
	 * @param owner
	 */
	public void updatePlayerPos(Player owner) {
		ITObject param = new TObject();
		param.putInt("seat", owner.seat);
		param.putUtfString("pos", owner.gps_pos);
		owner.room.broadCastToClient(owner.playerid, Router.GAME_EVT_UPDATE_POS, param);
	}

	/**
	 * 更新玩家托管
	 * 
	 * @param owner
	 */
	public void updatePlayerEntrust(Player owner) {
		ITObject param = new TObject();
		param.putInt("aid", owner.playerid);
		param.putInt("type", 5);
		param.putBoolean("entrust", owner.entrust);
		owner.room.broadCastToClient(0, Router.GAME_EVT_UPDATE_PLAYERINFO, param);
	}
}
