(function(){
	var WebSocketServer=require('ws').Server;
	var wss=new WebSocketServer({port:8080});
	var bannedKeys=[];
	var bannedIps=[];

	var rooms=[];
	var events=[];
	var clients={};
	var bannedKeyWords=[];
	var messages={
		create:function(key,nickname,avatar,config,mode){
			if(this.onlineKey!=key) return;
			this.nickname=util.getNickname(nickname);
			this.avatar=avatar;
			var room={};
			rooms.push(room);
			this.room=room;
			delete this.status;
			room.owner=this;
			room.key=key;
			this.sendl('createroom',key);
		},
		enter:function(key,nickname,avatar){
			this.nickname=util.getNickname(nickname);
			this.avatar=avatar;
			var room=false;
			for(var i of rooms){
				if(i.key==key){
					room=i;
					break;
				}
			}
			if(!room){
				this.sendl('enterroomfailed');
				return;
			}
			this.room=room;
			delete this.status;
			if(room.owner){
				if(room.servermode&&!room.owner._onconfig&&config&&mode){
					room.owner.sendl('createroom',index,config,mode);
					room.owner._onconfig=this;
					room.owner.nickname=util.getNickname(nickname);
					room.owner.avatar=avatar;
				}
				else if(!room.config||(room.config.gameStarted&&(!room.config.observe||!room.config.observeReady))){
					this.sendl('enterroomfailed');
				}
				else{
					this.owner=room.owner;
					this.owner.sendl('onconnection',this.wsid);
				}
				util.updaterooms();
			}
		},
		changeAvatar:function(nickname,avatar){
			this.nickname=util.getNickname(nickname);
			this.avatar=avatar;
			util.updateclients();
		},
		server:function(cfg){
			if(cfg){
				this.servermode=true;
				var room=rooms[cfg[0]];
				if(!room||room.owner){
					this.sendl('reloadroom',true);
				}
				else{
					room.owner=this;
					this.room=room;
					this.nickname=util.getNickname(cfg[1]);
					this.avatar=cfg[2];
					this.sendl('createroom',cfg[0],{},'auto')
				}
			}
			else{
				for(var i=0;i<rooms.length;i++){
					if(!rooms[i].owner){
						rooms[i].owner=this;
						rooms[i].servermode=true;
						this.room=rooms[i];
						this.servermode=true;
						break;
					}
				}
				util.updaterooms();
			}
		},
		key:function(id){
			if(!id||typeof id!='object'){
				this.sendl('denied','key');
				this.close();
				clearTimeout(this.keyCheck);
				delete this.keyCheck;
				return;
			}
			else if(bannedKeys.indexOf(id[0])!=-1){
				bannedIps.push(this._socket.remoteAddress);
				this.close();
			}
			this.onlineKey=id[0];
			clearTimeout(this.keyCheck);
			delete this.keyCheck;
		},
		events:function(cfg,id,type){
			if(bannedKeys.indexOf(id)!=-1||typeof id!='string'||this.onlineKey!=id){
				bannedIps.push(this._socket.remoteAddress);
				console.log(id, this._socket.remoteAddress);
				this.close();
				return;
			}
			var changed=false;
			var time=(new Date()).getTime();
			if(cfg&&id){
				if(typeof cfg=='string'){
					for(var i=0;i<events.length;i++){
						if(events[i].id==cfg){
							if(type=='join'){
								if(events[i].members.indexOf(id)==-1){
									events[i].members.push(id);
								}
								changed=true;
							}
							else if(type=='leave'){
								var index=events[i].members.indexOf(id);
								if(index!=-1){
									events[i].members.splice(index,1);
									if(events[i].members.length==0){
										events.splice(i--,1);
									}
								}
								changed=true;
							}
						}
					}
				}
				else if(cfg.hasOwnProperty('utc')&&
						cfg.hasOwnProperty('day')&&
						cfg.hasOwnProperty('hour')&&
						cfg.hasOwnProperty('content')){
					if(events.length>=20){
						this.sendl('eventsdenied','total');
					}
					else if(cfg.utc<=time){
						this.sendl('eventsdenied','time');
					}
					else if(util.isBanned(cfg.content)){
						this.sendl('eventsdenied','ban');
					}
					else{
						cfg.nickname=util.getNickname(cfg.nickname);
						cfg.avatar=cfg.nickname||'caocao';
						cfg.creator=id;
						cfg.id=util.getid();
						cfg.members=[id];
						events.unshift(cfg);
						changed=true;
					}
				}
			}
			if(changed){
				util.updateevents();
			}
		},
		config:function(config){
			var room=this.room;
			if(room&&room.owner==this){
				if(room.servermode){
					room.servermode=false;
					if(this._onconfig){
						if(clients[this._onconfig.wsid]){
							this._onconfig.owner=this;
							this.sendl('onconnection',this._onconfig.wsid);
						}
						delete this._onconfig;
					}
				}
				room.config=config;
			}
			util.updaterooms();
		},
		status:function(str){
			if(typeof str=='string'){
				this.status=str;
			}
			else{
				delete this.status;
			}
			util.updateclients();
		},
		send:function(id,message){
			if(clients[id]&&clients[id].owner==this){
				try{
					clients[id].send(message);
				}
				catch(e){
					clients[id].close();
				}
			}
		},
		close:function(id){
			if(clients[id]&&clients[id].owner==this){
				clients[id].close();
			}
		},
	};
	var util={
		getNickname:function(str){
			return typeof str=='string'?(str.slice(0,12)):'无名玩家';
		},
		isBanned:function(str){
			for(var i of bannedKeyWords){
				if(str.indexOf(i)!=-1) return true;
			}
			return false;
		},
		sendl:function(){
			var args=[];
			for(var i=0;i<arguments.length;i++){
				args.push(arguments[i]);
			}
			try{
				this.send(JSON.stringify(args));
			}
			catch(e){
				this.close();
			}
		},
		getid:function(){
			return (Math.floor(1000000000+9000000000*Math.random())).toString();
		},
		getroomlist:function(){
			var roomlist=[];
			for(var i=0;i<rooms.length;i++){
				rooms[i]._num=0;
			}
			for(var i in clients){
				if(clients[i].room&&!clients[i].servermode){
					clients[i].room._num++;
				}
			}
			for(var i=0;i<rooms.length;i++){
				if(rooms[i].servermode){
					roomlist[i]='server';
				}
				else if(rooms[i].owner&&rooms[i].config){
					if(rooms[i]._num==0){
						rooms[i].owner.sendl('reloadroom');
					}
					roomlist.push([rooms[i].owner.nickname,rooms[i].owner.avatar,
					rooms[i].config,rooms[i]._num,rooms[i].key]);
				}
				delete rooms[i]._num;
			}
			return roomlist;
		},
		getclientlist:function(){
			var clientlist=[];
			for(var i in clients){
				clientlist.push([clients[i].nickname,clients[i].avatar,!clients[i].room,clients[i].status,clients[i].wsid,clients[i].onlineKey]);
			}
			return clientlist;
		},
		updaterooms:function(){
			var roomlist=util.getroomlist();
			var clientlist=util.getclientlist();
			for(var i in clients){
				if(!clients[i].room){
					clients[i].sendl('updaterooms',roomlist,clientlist);
				}
			}
		},
		updateclients:function(){
			var clientlist=util.getclientlist();
			for(var i in clients){
				if(!clients[i].room){
					clients[i].sendl('updateclients',clientlist);
				}
			}
		},
		checkevents:function(){
			if(events.length){
				var time=(new Date()).getTime();
				for(var i=0;i<events.length;i++){
					if(events[i].utc<=time){
						events.splice(i--,1);
					}
				}
			}
			return events;
		},
		updateevents:function(){
			util.checkevents();
			for(var i in clients){
				if(!clients[i].room){
					clients[i].sendl('updateevents',events);
				}
			}
		}
	};
	wss.on('connection',function(ws){
		ws.sendl=util.sendl;
		if(bannedIps.indexOf(ws._socket.remoteAddress)!=-1){
			ws.sendl('denied','banned');
			setTimeout(function(){
				ws.close();
			},500);
			return;
		}
		ws.keyCheck=setTimeout(function(){
			ws.sendl('denied','key');
			setTimeout(function(){
				ws.close();
			},500);
		},2000);
		ws.wsid=util.getid();
		clients[ws.wsid]=ws;
		ws.sendl('roomlist',util.getroomlist(),util.checkevents(),util.getclientlist(ws),ws.wsid);
		ws.heartbeat=setInterval(function(){
			if(ws.beat){
				ws.close();
				clearInterval(ws.heartbeat);
			}
			else{
				ws.beat=true;
				try{
					ws.send('heartbeat');
				}
				catch(e){
					ws.close();
				}
			}
		},60000);
		ws.on('message',function(message){
			if(!clients[this.wsid]) return;
			if(message=='heartbeat'){
				this.beat=false;
			}
			else if(this.owner){
				this.owner.sendl('onmessage',this.wsid,message);
			}
			else{
				var arr;
				try{
					arr=JSON.parse(message);
					if(!Array.isArray(arr)){
						throw('err');
					}
				}
				catch(e){
					this.sendl('denied','banned');
					return;
				}
				if(arr.shift()=='server'){
					var type=arr.shift();
					if(messages[type]){
						messages[type].apply(this,arr);
					}
				}
			}
		});
		ws.on('close',function(){
			for(var i=0;i<rooms.length;i++){
				if(rooms[i].owner==this){
					for(var j in clients){
						if(clients[j].room==rooms[i]&&clients[j]!=this){
							clients[j].sendl('selfclose');
							// clients[j].close();
							// delete clients[j];
						}
					}
					rooms.splice(i--,1);
				}
			}
			if(clients[this.wsid]){
				if(this.owner){
					this.owner.sendl('onclose',this.wsid);
				}
				delete clients[this.wsid];
			}
			if(this.room) util.updaterooms();
			else util.updateclients();
		});
	});
}());