/**
 * JDOM XMLモジュール使用例ScriptSocklet
 *
 * このスクリプトの利用・改変は自由に行ってかまいません。
 *
 * 通信にXMLを利用するルーム制チャットの作例です。
 * 部屋に入室する際は <ENTER room="部屋名" />
 * ユーザー属性を設定する場合は <SET 属性名="値" 属性名="値" />
 * ルーム属性を設定する場合は <SET 属性名="値" 属性名="値" />
 * それ以外のXML文にはid属性を付加して同室ユーザーに転送します。
 */
application.importSource("scripts/JDOM_XML.inc"); //XMLモジュール読み込み

/**
 * Socklet初期化処理
 */
function onInit(){
	// ID用カウンタリストを初期化
	idList = [""];
}

/**
 * ユーザー接続時処理
 */
function onConnect(client){
	//名前がnullなら切断
	if(client.getUserName()==null){
		client.send("-ERROR No user name");
		return false;
	}
	
	// idを取得・設定
	var id = -1;
	for(var i=0; i<idList.length; i++){
		if(idList[i] == undefined){
			id = i;
			break;
		}
	}
	if(id==-1){
		id = idList.length
	}
	idList[id]=client;
	client.setAttribute("id",id.toString());
	
	// 部屋をロビーに設定
	client.setAttribute("room", "lobby");
	
	// 接続成功
	client.send("+OK Welcome");
	
	// idをクライアントに通知
	var uid = new XML.Element("CONNECT").setAttribute("id", id);
	client.send(XML.output(uid));
	return true;
}

/**
 * ユーザー切断時処理
 */
function onDisconnect(client){
	// クライアントのIDと部屋を取得
	var id = client.getAttribute("id");
	var room = client.getAttribute("room");
	
	// 退出を通知
	var exit = new XML.Element("EXIT").setAttribute("id", id);
	application.sendToClients(XML.output(exit), "a.room==\"" + room + "\"");
	
	// idリストから削除
	idList[id] = undefined;
}

/**
 * コマンド受信時処理
 */
function onCommand(client,cmd){
	if(cmd.charAt(0)=="<"){
		// 入力されたコマンドXMLを解析
		var root = XML.parse(cmd);
		if(root!=null){ //XML解析成功なら
			// コマンドXMLから名前を取得
			var cmdName = root.getName();
			
			if(command[cmdName]){ // コマンド処理関数が定義されているなら
				//コマンド処理関数を呼び出し
				return command[cmdName](client, root);
			} else { // 未定義のコマンドなら
				// クライアントのIDと部屋を取得
				var id = client.getAttribute("id");
				var room = client.getAttribute("room");
				
				// id属性をコマンドXMLに追加
				root.setAttribute("id", id);
				
				// コマンドを同室のユーザーに送信
				application.sendToClients(XML.output(root), "a.room==\"" + room + "\"");
				return true;
			}
		} else { // XML解析失敗なら
			client.send("-invalid XML");
			return false;
		}
	}
	// コマンドが正常に処理されなかった場合は切断する
	return false;
}

/**
 * コマンドオブジェクト
 * このオブジェクトのメンバに関数を定義すると、同名のXMLタグを持つコマンド受信時に呼び出されます
 */
command = new Object();

/**
 * 入室処理
 */
command.ENTER = function(client, xml){
	// クライアントのIDと部屋を取得
	var id = client.getAttribute("id");
	var userName = client.getUserName();
	var room = client.getAttribute("room");
	//移動する部屋を取得
	var newRoom = xml.getAttributeValue("room");
	
	// 退出を通知
	var exit = new XML.Element("EXIT").setAttribute("id", id);
	application.sendToClients(XML.output(exit), "a.room==\"" + room + "\"&a.id!=\"" + id + "\"");
	
	// 参加をルーム内のユーザーに通知
	xml.setAttribute("name", userName.toString());
	var attributes = client.getAttributeKeys().toArray();
	for(var i=0; i<attributes.length; i++){
		if(attributes[i]!="room"){
			xml.setAttribute(attributes[i], client.getAttribute(attributes[i]));
		}
	}
	xml.removeAttribute("room");
	application.sendToClients(XML.output(xml), "a.room==\"" + newRoom + "\"&a.id!=\"" + id + "\"");
	
	// 部屋を変更
	client.setAttribute("room", newRoom);
	
	//ユーザーリストを作成して入室したユーザーに送信
	client.send(XML.output(getUserlist(newRoom)));
	
	return true;
}

/**
 * ユーザー属性セット
 */
command.SET = function(client, xml){
	// クライアントのIDと部屋を取得
	var id = client.getAttribute("id");
	var room = client.getAttribute("room");
	
	//属性値をセット
	var attributes = xml.getAttributes().toArray();
	for(var i=0; i<attributes.length; i++){
		var attName = attributes[i].getName();
		var attValue = attributes[i].getValue()
		if(attName!="room"&&attName!="id"){
			client.setAttribute(attName, attValue);
		}
	}
	
	//属性の変更を同室ユーザーに送信
	xml.setAttribute("id", id);
	application.sendToClients(XML.output(xml), "a.room==\"" + room + "\"");

	return true;
}

/**
 * ルーム属性セット
 */
command.RSET = function(client, xml){
	// クライアントのIDと部屋を取得
	var id = client.getAttribute("id");
	var room = client.getAttribute("room");
	
	//属性値をセット
	var roominfo = application.getAttribute(room);
	if(roominfo==null){
		roominfo = new Object();
	}
	var attributes = xml.getAttributes().toArray();
	for(var i=0; i<attributes.length; i++){
		if(attributes[i].getName()!="room"){
			roominfo[attributes[i].getName()] = attributes[i].getValue();
		}
	}
	application.setAttribute(room, roominfo);
	
	//属性の変更を同室ユーザーに送信
	xml.setAttribute("id", id);
	application.sendToClients(XML.output(xml), "a.room==\"" + room + "\"");

	return true;
}

//-----------------
// 内部使用メソッド
//-----------------

/**
 * ユーザー情報一覧をXML.Element型で返す
 * <ROOM><USER id="id" name="name"/><USER id="id" name="name"/></ROOM>
 */
function getUserlist(room){
	//ユーザー一覧を作成
	var users = new XML.Element("ROOM");
	users.setAttribute("room", room);
	
	//属性値をセット
	var roominfo = application.getAttribute(room);
	if(roominfo!=null){
		for(var key in roominfo){
			users.setAttribute(key, roominfo[key]);
		}
	}
	
	var userList = application.getClients("a.room==\"" + room + "\"").toArray();
	for(var i=0; i < userList.length; i++){
		//属性一覧を作成
		var user = new XML.Element("USER");
		user.setAttribute("name", userList[i].getUserName());
		var attributes = userList[i].getAttributeKeys().toArray();
		for(var j=0; j<attributes.length; j++){
			if(attributes[j]!="room"){
				user.setAttribute(attributes[j], userList[i].getAttribute(attributes[j]));
			}
		}
		users.addContent(user);
	}
	return users;

}