(function(fw){
	
	var inited = false;
	
	var cookie = Library.cookie;
	var socket = null;
	var reachability = fw.reachability;
	var config = fw.config;
	var netMessage = fw.netMessage;
	var myrsa = fw.myrsa;
	var writeBuffer_ = fw.writeBuffer_;
	
	
    if(!cookie.getCookie('clientId')){
        cookie.addCookie('clientId',sumeru.utils.randomStr(12) , 24*365*20);
    }
    
    if(!cookie.getCookie('OPEN_STICKY_SESSION')){
        cookie.addCookie('OPEN_STICKY_SESSION',1);
    }
    
    netMessage.addOutFilter(function(msg){
        msg.sessionId = cookie.getCookie('sessionId');
        msg.clientId = cookie.getCookie('clientId');
        msg.passportType = cookie.getCookie('passportType');
        return msg;
    },0);
    
	var __socketInit = function(counter,callback){
	    
	    var socketId = fw.__random();
	    
	    // 如果开启rsa,将在每次建立连接的时候同步加密信息,所以将config状态放在每次初始化连接的时候.
    	var rsa_enable = config.get("rsa_enable");
    	
    	// 除非当前是断线状态,否则绝不建立连接
	    if(reachability.getStatus() != reachability.STATUS_OFFLINE){
	        fw.dev('Another connection still open, stop connect');
	        return;
	    }

        if( ( counter = counter || 0 ) > 500){ //70次是(1+70) * 70 / 2 = 41分钟重连时间
            throw "Fail to connect to network";
        }
	    
		var clientSocketServer;
		
		if (config.get('httpServerPort') && config.get('httpServerPort') != "80" && location.hostname.indexOf('.duapp.com')==-1){
			clientSocketServer = location.hostname + ':' + config.get('httpServerPort') + '/socket/';
		}else{
			clientSocketServer = location.hostname + '/socket/';
		}
		//for bae long connection
		clientSocketServer = clientSocketServer.replace('.duapp.com', '.sx.duapp.com');
		//创建一个Socket通道
		fw.dev("OPEN : " +  clientSocketServer);
		reachability.setStatus_(reachability.STATUS_CONNECTING);
		
		socket = new SockJS("http://" + clientSocketServer, undefined, {
		    protocols_whitelist : config.get('protocols_whitelist')
		});
		
		socket.onmessage = function(e){
		    //FIXME RSA client
		    netMessage.onData( rsa_enable ? myrsa.decrypt(e.data) :  e.data);
		};
		
		socket.onopen = function(){
		    reachability.setStatus_(reachability.STATUS_CONNECTED);
		    
			//发送链接标示符
			var identifier = {};
			var SUMERU_APP_UUID = 'sumeru_app_uuid';
			
			if (!rsa_enable) {//默认
			    identifier = {
                    socketId : socketId,
                    uuid    :   SUMERU_APP_UUID
                };
			}else{
			    
                if ( counter === 0 ) { //第一次初始化直接从config的js中下载，同时生成客户端的密钥对
                    myrsa.setPk2( config.get("rsa_pk") );//先设置server的pk，马上本地会重新生成
                    myrsa.generate();
                } else {//断线重连的时候，server端的公钥私钥可能已经发生变化，要重新拉取。
                    identifier.swappk = myrsa.getPk();//有此标识，通讯信息不会加密
                    myrsa.setPk2('');//删除原有pk2，重新获取pk2
                }
                
                identifier.socketId = socketId;
                identifier.uuid = SUMERU_APP_UUID;
                identifier.pk   = myrsa.getPk();
           }
			
			fw.dev("ON OPEN : " + socket.readyState + " : " + JSON.stringify(identifier));
			
			netMessage.sendMessage(identifier, 'echo');
		};
		
		socket.onclose = function(reason){
		    var reconnectTimer = null;
		    
		    fw.log("Socket has been closed : " , reason.reason);
		    reachability.setStatus_(reachability.STATUS_OFFLINE);
		    
		    // 正常关闭时不重连
	        if(reason.code == 1000){
	            return;
	        }
	        
            reconnectTimer = setTimeout(function(){
                // 只有在在线的情况下发生断线,才进行重连,否则交收online事件触发重连..
                // 断开之后在重建之前,检查在线状态,如果不在线,则不重连,并将重连交给online事件.
                if(navigator.onLine === true){
                    __socketInit(++counter);  
                }else{
                    clearTimeout(reconnectTimer);
                }
            }, 1000);
		};
		
		//FIXME RSA,this is client
		var sendMessage = function(data,onerror,onsuccess){
		    
		    if(socket.readyState === 0){
                setTimeout(function(){
                    sendMessage(data,onerror,onsuccess);
                }, 50);
                return;
            }
            
            var data2;
            if ( !rsa_enable || data.match(/"target":"echo"/) !== null ) {
                data2 = data;
            }else{
                data2 = myrsa.encrypt(data);
            }
            
            try {
		        socket.send(data2);
            } catch (e) {
                // TODO: handle exception
                fw.log("error : "+socket.readyState + " " + data);
                onerror && onerror(e);
            }
            
            onsuccess && onsuccess();
		};
		
	    netMessage.setReceiver({
	        onLocalMessage:{
	            target : ['after_echo_from_server'],
	            handle : function(){
	                fw.auth.init(function(){
	                    inited = true;
	                    callback && callback();
	                    
	                    writeBuffer_.resume();
	                                                    
	                    if(counter > 0){
	                        counter = 0;
	                        fw.pubsub.__load('_redoAllSubscribe')();
	                    }
	                });                            
	            }
	        }
	    });
		
	    writeBuffer_.setOutput(sendMessage);
		netMessage.setOutput(writeBuffer_.write);
        
		return;
	};
	
	fw.init = function(callback){
		if(!inited){
			__socketInit(0, callback);
		}else{
		    callback && callback();
		}
		fw.transition._init();
		//fw.Controller.__load('_load').apply(this, arguments);
	};
	
	fw.reconnect = function(){
        __socketInit(1);
    };
    
    fw.closeConnect = function(){
        socket && socket.close();
    };
	
})(sumeru);