package com.mgr.group.data;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Queue;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

import com.data.bean.GroupBean;
import com.data.bean.GroupPlayBean;
import com.data.cache.AccountCache;
import com.data.cache.GroupCache;
import com.data.cache.GroupPlayCache;
import com.mgr.group.Global;
import com.mgr.group.Router;
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.util.StringUtil;
import com.taurus.core.util.Utils;
import com.taurus.permanent.TPServer;
import com.taurus.permanent.data.Session;

import redis.clients.jedis.Jedis;
import redis.clients.jedis.Pipeline;

public class Group implements Runnable {
	public int							id;
	public String						group_key			= "";
	/**
	 * 圈主
	 */
	public int							owner;
	/**
	 * 圈主session
	 */
	public String						owner_session;
	/**
	 * 圈主钻石
	 */
	public int							owner_diamo;
	/**
	 * 是否被激活
	 */
	public volatile boolean				isActive			= false;
	/**
	 * 是否被销毁
	 */
	public volatile boolean				isDestroy			= false;
	private Thread						updateThread;
	public volatile long							lastTime;
	final Queue<Runnable>				updateHandleList	= new LinkedList<Runnable>();
	public ConcurrentMap<Integer, User>	userMap;
	public GroupPlayCache				playCache;
	public RoomCache					roomCache;
	public Map<String,CommandData>		cmdMap = new HashMap<>();
	private long lastSendTime;
//	private long lastUpdateOnline;
	
	public Group(int id) {
		this.userMap = new ConcurrentHashMap<>();
		this.id = id;
		this.group_key = GroupCache.genKey(id);
		String pay_type = Redis.use("group1_db11").hget(group_key, "pay_type");
		this.playCache = new GroupPlayCache(id, Integer.parseInt(pay_type));
		this.roomCache = new RoomCache(id);
	}

	public synchronized void start() {
		if (isActive || isDestroy)
			return;
		isActive = true;
		GroupBean gb = GroupCache.getGroup(id);
		this.owner = gb.owner;
		this.owner_session = AccountCache.genKey(owner);
		String _diamo = Redis.use("group1_db0").hget(owner_session, "diamo");
		if(StringUtil.isNotEmpty(_diamo)) {
			owner_diamo = Integer.parseInt(_diamo);
		}
		updateThread = new Thread(this, this.group_key);
		updateThread.start();
		lastTime = System.currentTimeMillis();
	}

	private void handleTask(Runnable tem) {
		if (isDestroy) {
			return;
		}

		try {
			tem.run();
		} catch (Throwable t) {
			Global.logger.error("[" + id + "] exception!", t);
		}

		handleBroadcast();
	}

	public void handleBroadcast()
	{
		long curTime = System.currentTimeMillis();
		if(curTime - lastSendTime >=2000) {
			try {
				if (cmdMap.size()>0) {
					List<Session> list = this.getSessionList();
					if(list.size()>0) {
						ITArray arr = TArray.newInstance();
						ITObject param = TObject.newInstance();
						param.putTArray("cmds", arr);
						for (Entry<String,CommandData> entry : cmdMap.entrySet()) {
							CommandData cmd = entry.getValue();
							arr.addTObject(cmd.param);
						}
						Global.logger.info("[" + list + "] !"+ param+"--"+list);

						TPServer.me().getController().sendEvent(Router.FGMGR_EVT_UPDATE_ROOM, 0, param, list);
					}
				}
				List<User> u_list = null;
				synchronized (userMap) {
					u_list = new ArrayList<User>(userMap.values());
				}
				List<Object> r_list = null;
				Jedis jedis = Redis.use("group1_db10").getJedis();
				try {
					Pipeline pip = jedis.pipelined();
					for (User user : u_list) {
						pip.hget(user.gm_key, "hp");
					}
					r_list =  pip.syncAndReturnAll();

				}finally {
					jedis.close();
				}

				for(int i=0;i<u_list.size();++i) {
					User user = u_list.get(i);
					Object obj = r_list.get(i);

					if(StringUtil.isNotEmpty((String)obj)) {
						if(!user.isConnect)continue;

						ITObject param = TObject.newInstance();
						param.putInt("type", 1);
						try {
							long cur_hp = Long.parseLong((String)obj);
							if(cur_hp == user.hp) {
								continue;
							}
							user.hp = cur_hp;
							param.putLong("value",cur_hp);
						}
						catch(Exception e)
						{
							Global.logger.error("user:"+user.sender+" hp:"+obj);
							param.putLong("value",user.hp);
						}
						TPServer.me().getController().sendEvent(Router.FGMGR_EVT_UPDATE_MEMBER, user.uid, param, user.sender);
					}
				}
			}
			catch(Exception e) {
				Global.logger.error("[" + id + "] exception!", e);
			}

			cmdMap.clear();
			lastSendTime = System.currentTimeMillis();
		}
	}

	public void run() {
		while (isActive && !isDestroy) {
			try {
				if (updateHandleList.size() > 0) {
					this.lastTime = System.currentTimeMillis();
					Runnable tem = null;
					synchronized (updateHandleList) {
						tem = updateHandleList.poll();
					}
					if (tem != null){
						try {
							handleTask(tem);
						} catch (Throwable t) {
							Global.logger.error("[" + id + "] exception!", t);
						}
					}
				}

				handleBroadcast();

				if (isDestroy)
					continue;
				Thread.sleep(5);
			} catch (InterruptedException e) {
				isActive = false;
				Global.logger.error("[" + id + "] thread interrupted!");
			} catch (Throwable t) {
				//isActive = false;
				Global.logger.error("[" + id + "] exception!", t);
			}
		}
	}

	public void enqueueRunnable(Runnable runnable) {
		if (runnable == null)
			return;
		synchronized (updateHandleList) {
			updateHandleList.add(runnable);
		}
	}

	public void addRoomCommand(String roomid,int type,ITObject param) {
		CommandData cmd = cmdMap.get(roomid);
		if(cmd==null) {
			cmd = new CommandData();
			cmdMap.put(roomid, cmd);
		}
		cmd.setData(type, param);
	}
	
	public ITObject getInfo(int lev,int uid) {
		ITObject info = TObject.newInstance();

		GroupBean gb = GroupCache.getGroup(this.group_key);
		info.putBoolean("ban", gb.ban == 1 ? true : false);
		String joins_key = GroupCache.genJoinsKey(id);
		int joins = Redis.use("group1_db11").scard(joins_key).intValue();
		info.putInt("joins", joins);
		info.putInt("diamo", owner_diamo);
		info.putInt("dissolve_opt", gb.dissolve_opt);
		info.putInt("kick_opt", gb.kick_opt);
		info.putBoolean("ban_chat1", gb.ban_chat1);
		info.putBoolean("ban_chat2", gb.ban_chat2);
		info.putInt("ban_apply", gb.ban_apply);
		info.putInt("exit_opt", gb.exit_opt);
		info.putInt("option", gb.option);
		ITArray rooms = this.roomCache.getRoomList();
		info.putTArray("rooms", rooms);
		ITArray arrPlayList = TArray.newInstance();
		Utils.arrayCopy(this.playCache.getPlayList(lev,uid), arrPlayList);
		info.putTArray("play_list", arrPlayList);
		return info;
	}

	public boolean delRoom(String roomid) {
		String key = "room:" + roomid;
		boolean result =false;
		
		if (this.roomCache.delBean(key)) {
			this.roomCache.updateRoom();
			result = true;
		}
		String grooms_key = GroupCache.genRoomsKey(id);
		Redis.use("group1_db11").zrem(grooms_key, key);
		return result;
	}

	public Room updateRoom(String roomid) {
		String key = "room:" + roomid;
		String grooms_key = GroupCache.genRoomsKey(id);
		Room room = this.roomCache.getBean(key);
		this.roomCache.updateRoom();
		if (room == null) {
			Redis.use("group1_db11").zrem(grooms_key, key);
		} else {
			Redis.use("group1_db11").zadd(grooms_key, room.priorityValue, key);
		}

		return room;
	}

	public Room addRoom(String roomid) {
		String key = "room:" + roomid;
		String grooms_key = GroupCache.genRoomsKey(id);
		Room room = this.roomCache.getBean(key);

		this.roomCache.updateRoom();
		if (room == null) {
			Redis.use("group1_db11").zrem(grooms_key, key);
		} else {
			Redis.use("group1_db11").zadd(grooms_key, room.priorityValue, key);
		}
		return room;
	}

	public GroupPlayBean addPlay(int pid) {
		GroupPlayBean gp = this.playCache.getBean(pid);
		this.playCache.updatePlay();
		return gp;
	}

	public boolean delPlay(int pid) {
		boolean del = this.playCache.delBean(pid);
		this.playCache.updatePlay();
		return del;
	}

	/**
	 * 广播消息到客户端
	 * 
	 * @param cmd				 协议指令
	 * @param param				 协议数据
	 */
	public void broadCastToClient(String cmd, ITObject param) {
		if (!isActive)
			return;
		List<Session> list = getSessionList();
		if (list == null || list.size() == 0)
			return;
		TPServer.me().getController().sendEvent(cmd, param, list);
	}

	public List<Session> getSessionList() {
		List<Session> list = new ArrayList<Session>();
		List<User> tem = null;
		synchronized (userMap) {
			tem = new ArrayList<User>(userMap.values());
		}

		for (User user : tem) {
			if (user.isConnect) {
				list.add(user.sender);
			}
		}
		return list;
	}

	public List<Session> getSessionListByMgr() {
		List<Session> list = new ArrayList<Session>();
		List<User> tem = null;
		synchronized (userMap) {
			tem = new ArrayList<User>(userMap.values());
		}

		for (User user : tem) {
			if (user.isConnect && user.lev < 3) {
				list.add(user.sender);
			}
		}
		return list;
	}

	public void destroy() {
		if (this.isDestroy)
			return;
		this.isDestroy = true;
		Global.groupMap.remove(id);
		Collection<User> tem = userMap.values();
		for (User user : tem) {
			if (user.isConnect) {
				TPServer.me().getController().disconnect(user.sender);
			}
		}
	}

}
