/**
 * Created by anan on 15/7/8.
 */

window.console = ('console' in window)?console:{
    log:function(string){
    }
};

function ajax(args,undefined) {
    var request=new XMLHttpRequest();

    var url = args.url;
    var data = args.data || {};
    var dataType = args.dataType?args.dataType:'json';

    request.onreadystatechange=function(){
        if (request.readyState == 4) {
            if(request.status == 200){
                var data = null;
                if(/^json$/i.test(dataType)){
                    data = JSON.parse(request.responseText);
                }else if(/^text$/i.test(dataType)){
                    data = request.responseText;
                }
                try{
                    if (typeof args.success == 'function') {
                        args.success(data);
                    }
                } catch (e) {
                }
            }else{
                if (typeof args.error == 'function') {
                    args.error(request.status);
                }
            }
        }
    }
    if ('timeout' in args) {
        request.timeout = args.timeout;
    }
    request.onloadstart = function(){
        if (typeof args.loadstart == 'function') {
            args.loadstart();
        }
    }
    request.onprogress = function (event) {
        if (typeof args.progress == 'function') {
            args.progress(event);
        }
    }
    if ((args.type&&/^post$/gi.test(args.type))) {
        request.open("POST",url,true);
        request.setRequestHeader("Content-Type","application/x-www-form-urlencoded");
        var sp = '',content = '';
        for(var prop in data){
            content+= sp + prop + '=' + encodeURIComponent(data[prop]);
            sp = '&';
        }
        request.send(content);
    }else{
        var sp = /\?/.test(url)?'&':'?';
        for(var prop in data){
            url+= sp + prop + '=' + encodeURIComponent(data[prop]);
            sp = '&';
        }
        request.open("GET",url,true);
        request.send();
    }
}

window.gjjAjax = ajax;

function JobListener(project_path){
    this.project_path = project_path?project_path:'';
    this.path = '/g.php';
    this.job_sid = 0;
    this.duration = 3000;
}

JobListener.prototype = {
    start:function(job_sid,cb,failedCb){
        if (+this.job_sid) {
            return;
        }
        this.success = cb;
        this.failed = failedCb;
        this.startCheckStatus(job_sid);
    },
    trigger:function(func){
        if (typeof func == 'function') {
            func.apply(this,Array.prototype.slice.call(arguments,1));
        }
    },
    startCheckStatus : function (sid) {
        if (+this.job_sid) {
            return;
        }
        this.job_sid = sid;
        this.startTime = new Date().getTime();
        this.continueCheckStatus();
    },
    continueCheckStatus : function () {
        var self = this;
        var job_sid = this.job_sid;
        this.lastTime = new Date().getTime();
        if (this.timer) {
            clearTimeout(this.timer);
        }
        this.timer = 0;
        gjjAjax({
            url: this.project_path+this.path,
            data: {action:'getJobStatus',sid: job_sid},
            success: function (e) {
                if (self.job_sid==0) {
                    return;
                }
                var state = +e.state;
                switch (state) {
                    case -1:
                    case 2:
                        if (e.state == -1) {
                            self.trigger(self.failed,e.result);
                        } else if (e.state == 2){
                            self.trigger(self.success,e.result);
                        }
                        break;
                    default:
                        var curTime = new Date().getTime();
                        if (curTime - self.startTime >= 1000 * 60 * 2.5) {
                            self.trigger(self.failed,'请求超时');
                        }else{
                            var duration = self.duration;
                            if (curTime - self.lastTime >= duration) {
                                self.continueCheckStatus();
                                self.lastTime = curTime;
                            } else {
                                self.timer = setTimeout(function () {
                                    self.continueCheckStatus();
                                }, duration - (curTime - self.lastTime));
                                self.lastTime = self.lastTime + duration;
                            }
                        }
                        break;
                }

            },
            error: function(status){
                self.continueCheckStatus();
            }
        });
    }
}

function extendMethod (class_name,method_set) {
    for (var method_name in method_set) {
        class_name.prototype[method_name] = method_set[method_name];
    }
}

function EventListener(){
}

extendMethod(EventListener,{
    on : function(event,func) {
        if (typeof event === 'string' && typeof func === 'function') {
            var list = this['on'+event+'list'];
            if (list instanceof Array) {
                for (var i = 0; i < list.length; i++) {
                    if (list[i]===func) {
                        return this;
                    }
                }
                list.push(func);
            }else{
                this['on'+event+'list']=[func];
            }
            if(!this['on'+event]){
                this['on'+event]=function(){
                    var args = Array.prototype.slice.call(arguments, 0);
                    var result = null;
                    var list = this['on'+event+'list'];
                    var len = list instanceof Array?list.length:0
                    for (var i = 0; i < len; i++) {
                        result = list[i].apply(this,args);
                    }
                    return result;
                }
            }
        }
        return this;
    },

    off : function(event,func){
        var list = this['on'+event+'list'];
        if (list instanceof Array) {
            if (!func) {
                list.length && list.splice(0,list.length);
            }else{
                for (var i = 0; i < list.length; i++) {
                    if (list[i]===func) {
                        list.splice(i,1);
                        break;
                    }
                }
            }
        }
        return this;
    },

    trigger : function(event){
        var func = this['on'+event];
        if (typeof func == 'function') {
            var args = Array.prototype.slice.call(arguments, 0);
            args.shift();
            func.apply(this,args);
        }
    }
});

function GjjAddArgs(cid,data){
    this.cid = cid;
    this.data = data;
}

function GjjUpdateArgs(sid,data){
    this.sid = sid;
    this.data = data;
}

function RequestGJJ(project_path,socket_path){
    this.project_path = project_path?project_path:'';
    this.sid = 0;
    this.job_sid = 0;
    this.path = '/g.php';
    this.duration = 2*1000;
    this.timer = 0;
    this.disconnect_timer = 0;
    this.socket_path = socket_path;
    this.connection = null;
    this.debug = false;
    this.errors = {
        server:"\u670D\u52A1\u5668\u7E41\u5FD9\uFF0C\u8BF7\u7A0D\u540E\u518D\u8BD5",
        develop:"\u4E0D\u597D\u610F\u601D\uFF0C\u6211\u4EEC\u7684\u7A0B\u5E8F\u5458\u72AF\u9519\u4E86",
        network:"\u8BF7\u5148\u786E\u8BA4\u60A8\u7684\u8BBE\u5907\u8FDE\u63A5\u7F51\u7EDC"
    };
    this.initConnection();
}

RequestGJJ.prototype = new EventListener();
extendMethod(RequestGJJ,{
    busy: function(){
        return !!+this.job_sid;
    },
    end : function(){
        var self = this;
        this.log('job end');
        this.job_sid = 0;
        this.timer && clearTimeout(this.timer);
        this.timer = 0;
        this.connection && this.connection.readyState()!=0 && (this.disconnect_timer = setTimeout(function(){
            self.connection.stop();
            self.disconnect_timer= 0;
        },60*1000));
        this.trigger('end');
    },
    bind : function(sid){
        this.sid = +sid;
        return this;
    },
    abort: function(){
        this.job_sid = 0;
    },
    commit : function () {
        if (!!+this.job_sid) {
            return;
        }
        var self = this;
        var location_cid = 0;
        var data = null;
        var action = 'requestGjj';
        if (arguments.length>=3) {
            action = arguments[0];
            location_cid = arguments[1];
            data = arguments[2];
        }else if(arguments.length==2){
            data = arguments[1];
            if (data instanceof GjjAddArgs || data instanceof GjjUpdateArgs) {
                action = arguments[0];
            }else{
                location_cid = arguments[0];
            }
        }else if(arguments.length==1){
            data = arguments[0];
        }else{
            return;
        }
        if (data instanceof GjjAddArgs){
            location_cid = data.cid;
            data = data.data;
        }else if(data instanceof GjjUpdateArgs){
            this.sid = data.sid;
            data = data.data;
        }
        var params = {cid:+location_cid,action:action};
        if (typeof data === 'object') {
            for(var prop in data){
                if ('|phone_code|code|tag|'.indexOf('|'+prop+'|')>=0) {
                    params[prop]=data[prop];
                }else{
                    params['args['+prop+']']=data[prop];
                }
            }
        }
        if (this.sid>0) {
            params.sid = this.sid;
            delete params.cid;
        }
        var $_get = getURLParams(window.location.href);
        if ('from' in $_get) {
            params.from = $_get.from;
        }
        this.trigger('start');
        this.disconnect_timer && clearTimeout(this.disconnect_timer);
        this.disconnect_timer = 0;
        gjjAjax({
            url: this.project_path+this.path,
            data: params,
            type: 'post',
            success: function (e) {
                if (e.errmsg) {
                    self.trigger('failed',e.errmsg);
                    self.end();
                }else if (!!e.job_sid) {
                    self.log('job begin');
                    self.job_sid = e.job_sid;
                    if (self.connection) {
                        if (self.connection.readyState()==0) {
                            self.connection.start(e.stomp_headers);
                            return;
                        }
                    }
                    self.startCheckStatus(true);
                }
            },
            error:function (status){
                self.reportError(status);
            }
        });
        return this;
    },
    reportError: function(status){
        if (0 == status) {
            this.trigger('failed',this.errors.network);
        }else if(404 == status || 500 == status){
            this.trigger('failed',this.errors.develop);
        }else{
            this.trigger('failed',this.errors.server);
        }
        this.end();
    },
    startCheckStatus : function (delay) {
        if (!+this.job_sid) {
            return;
        }
        var self = this;
        this.startTime = new Date().getTime();
        this.clearTimer();
        if (!!delay) {
            this.timer = setTimeout(function () {
                self.continueCheckStatus(self.job_sid);
            }, this.duration);
        }else{
            this.continueCheckStatus(this.job_sid);
        }

    },
    clearTimer: function(){
        if (this.timer) {
            clearTimeout(this.timer);
            this.timer = 0;
        }
    },
    continueCheckStatus : function (job_sid) {
        var self = this;
        this.timer = 0;
        this.lastTime = new Date().getTime();
        gjjAjax({
            url: this.project_path+this.path,
            data: {action:'getJobStatus',sid: job_sid},
            success: function (e) {
                self.log("received http api:\n"+JSON.stringify(e));
                if (self.job_sid==0) {
                    return;
                }
                var state = +e.state;
                switch (state) {
                    case -1:
                    case 2:
                        if (e.state == -1) {
                            self.trigger('failed',e.result);
                        } else if (e.state == 2){
                            self.trigger('success', e.surname_sid, e);
                        }
                        self.end();
                        break;
                    default:
                        var curTime = new Date().getTime();
                        if (curTime - self.startTime >= 1000 * 60 * 2.5) {
                            self.trigger('failed','请求超时');
                            self.end();
                        }else{
                            var duration = self.duration;
                            if (curTime - self.lastTime >= duration) {
                                self.continueCheckStatus(job_sid);
                                self.lastTime = curTime;
                            } else {
                                self.timer = setTimeout(function () {
                                    self.continueCheckStatus(job_sid);
                                }, duration - (curTime - self.lastTime));
                                self.lastTime = self.lastTime + duration;
                            }
                        }
                        break;
                }

            },
            error: function(status){
                self.reportError(status);
            }
        });
    },
    initConnection: function(){
        var self = this;
        this.connection = this.socket_path && Connection.support ?new Connection((window.location.protocol=="https:"?"wss://":"ws://")+this.socket_path).on("message",function(e){
            self.log("received websocket notify:\n"+e.content);
            var data = JSON.parse(e.content);
            if(data.f=='getJobStatus' && data.params['job_sid']==self.job_sid){
                self.continueCheckStatus();
            }
        }).on("start",function(){
            self.duration = 15*1000;
            self.startCheckStatus(true);
            self.log("connection start");
        }).on("stop",function(){
            self.duration = 2*1000;
            self.log("connection stop");
        }).on("error",function(error){
            if (typeof error == 'string') {
                self.log(error);
            }else if (error instanceof Error) {
                self.log(error);
            }else if(error.headers){
                var msg = error.headers.message.replace(/\\c/gi,":").replace(/\\n/gi,"\n");
                self.log(msg);
            }
            self.startCheckStatus();
        }).on("log",function(message){
            self.log(message);
        }):null;
    },
    log:function(message){
        if (!!this.debug) {
            var timetag = this.formatDate(new Date(),'MM-dd hh:mm:ss.S');
            window.console && console.log && console.log(timetag+"\n"+message+"\n");
        }
    },
    formatDate:function (date,fmt) {
        var o = {
            "M+": date.getMonth() + 1,
            "d+": date.getDate(),
            "h+": date.getHours(),
            "m+": date.getMinutes(),
            "s+": date.getSeconds(),
            "q+": Math.floor((date.getMonth() + 3) / 3),
            "S": date.getMilliseconds()
        };
        if (/(y+)/.test(fmt)) fmt = fmt.replace(RegExp.$1, (date.getFullYear() + "").substr(4 - RegExp.$1.length));
        for (var k in o)
            if (new RegExp("(" + k + ")").test(fmt))fmt = fmt.replace(RegExp.$1, (RegExp.$1.length == 1) ? (o[k]) : (("00" + o[k]).substr(("" + o[k]).length)));
        return fmt;
    }
});

function Connection(host){
    //private
    var host = host;
    var readyState = 0;
    var observeBroadcast = false;
    var observer = {};
    var socket = null;
    var stompClient = null;
    var self = this;

    //public
    var proto = {
        debug : false,
        readyState:function(){
            return readyState;
        },

        setObserveBroadcast: function(b){
            return observeBroadcast = b,this;
        },

        start: function(headers){
            var self = this;
            var headers = headers instanceof Object?headers:{};
            if(readyState){
                return this;
            }
            readyState = 1;

            try{
                if ('WebSocket' in window) {
                    socket = new WebSocket(host);
                }else if ('MozWebSocket' in window) {
                    socket = new MozWebSocket(host);
                }else{
                    return self.trigger('error','sorry,your browser does not support websocket');
                }
            }catch(e){
                return self.trigger('error',e);
            }

            stompClient = Stomp.over(socket);

            stompClient.debug = function(message){
                self.trigger('log',message);
            };

            var connectCallback = function() {
                readyState = 2;
                self.trigger('start');
                var createOnMessage = function(isPublic){
                    return function(data){
                        var payload = null;
                        try{
                            payload = JSON.parse(data.body);
                        }catch(e){
                            console.log(e);
                            payload = {};
                        }
                        self.trigger('message',payload,isPublic);
                    }
                };
                if(observeBroadcast){
                    stompClient.subscribe('/app/notify', createOnMessage(true));
                }
                if (headers.login) {
                    stompClient.subscribe('/user/'+headers.login+'/notify', createOnMessage(false));
                }
            };
            var errorCallback = function(error) {
                return readyState = 0,self.trigger('stop'),self.trigger('error',error);
            };
            stompClient.connect(headers, connectCallback, errorCallback);
            return this;
        },

        action:function(name,params){
            if(readyState==2){
                stompClient.send("/app/action", {}, JSON.stringify({action:name,params:params}));
            }
            return this;
        },
        send:function(content){
            return readyState==2 && stompClient && stompClient.send("/app/message", {}, JSON.stringify({content:content})),this;
        },

        sendToUser:function(user,content){
            return readyState==2 && stompClient && stompClient.send("/app/message/"+user.replace(/\//gi,'%2F'), {}, content),this;
        },

        stop: function(){
            readyState==2 && socket && socket.close();
            readyState = 0;
            return this;
        }
    }

    for(var p in proto){
        Object.defineProperty(this, p, {
            value: proto[p],
            writable: typeof proto[p] != 'function'
        });
        // this[p]=proto[p];
    }
}

// if (Object.defineProperty) {
//     Object.defineProperty(Connection, 'support', {
//         value: 'WebSocket' in window || 'MozWebSocket' in window,
//         writable: false
//     });
// }else{
    Connection.support = 'WebSocket' in window || 'MozWebSocket' in window;
// }

Connection.prototype = new EventListener();
// Connection.support = false;

$.cookie = {
    set:function(name,value,time){
        time = +time || 30*24*60*60*1000;
        var Days = 30;
        var exp = new Date();
        exp.setTime(exp.getTime() + time);
        document.cookie = name + "="+ escape (''+value) + ";expires=" + exp.toGMTString();
    },
    get:function(name){
        var arr,reg=new RegExp("(^| )"+name+"=([^;]*)(;|$)");
        if(arr=document.cookie.match(reg))
        return unescape(arr[2]);
        else
        return null;
    },
    remove:function(name){
        this.set(name,'',-1);
    }
}