var Desktop=null;
var Taskbar=null;

function Break()
{
}

function Write(msg)
{
    OutputPanel.Write(msg);
}

function IsNull(val,alt)
{
    return (val==undefined || val==null)?alt:val;
}

function Exception(name,msg)
{
    this.Name=name;
    this.Message=msg;
    
    this.toString=function()
    {
        return name+":"+msg;
    }
}

function System_Ctor() 
{
    this.OnOutput=new Delegate();
    this.OnLoad=new Delegate();
    this.OnUnload=new Delegate();
    this.OnServerError=new Delegate();
    this.OnSessionRecover=new Delegate();

    var ua = navigator.userAgent.toLowerCase();

    var m_Browser="";
    if((/msie ([\d.]+)/).test(ua)) m_Browser="IE";
    else if ((/firefox\/([\d.]+)/).test(ua))  m_Browser="Firefox";
    else if ((/chrome\/([\d.]+)/).test(ua))  m_Browser="Chrome";

    var Debug=false;
    this.IsDebug=function(){return Debug;}

    var This=this;

    var m_Modules={};
    var m_ModulesArray=[];
    var m_Count=0;
    var m_BaseDate=new Date()
    var m_Applications=[];
    var m_Global={};
    
    var m_Log=[];

    var m_SpecialDirectory={
        Application:"",
        Library:"",
        Home:"",
        Config:"",
        Root:""
    };

    var m_User="";
    var m_UserInfo={};
    var m_SessionID="";

    var m_Language="zh-CHS";

    var m_ModuleCtorFormat=
        "\r\n"+
        "var Module=this;\r\n"+
        "Module.DirectoryName='{0}';\r\n"+
        "Module.FileName='{1}';\r\n"+
        "Module.GetResourceUrl=function(relativePath)\r\n"+
        "{\r\n"+
        "	return encodeURI('Users'+Module.DirectoryName+'/'+relativePath);\r\n"+
        "};\r\n"+
        "\r\n"+
        "{2}\r\n"+
        "Module.Initialize=(typeof(init)=='undefined'?null:init);\r\n"+
        "Module.Dispose=(typeof(dispose)=='undefined'?null:dispose);\r\n"+
        "Module.Application=(typeof(Application)=='undefined'?null:Application);\r\n";

    function TimeToString(date)
    {
        return String.format(
            "{0}:{1}:{2}",
            FormatNumber(date.getHours(),2),
            FormatNumber(date.getMinutes(),2),
            FormatNumber(date.getSeconds(),2)
        );
    }
    
    function DateToString(date)
    {
        return String.format(
            "{0}-{1}-{2} {3}:{4}:{5}",
            FormatNumber(date.getFullYear(),4),
            FormatNumber(date.getMonth()+1,2),
            FormatNumber(date.getDate(),2),
            FormatNumber(date.getHours(),2),
            FormatNumber(date.getMinutes(),2),
            FormatNumber(date.getSeconds(),2)
        );
    }
    
    var LogMaxSize=2*1024;
    var m_LogSize=0;
    
    function WriteLog(log)
    {
        var log_line=String.format("{0} {1}\r\n",TimeToString(new Date()),log);
        m_LogSize+=log_line.length;
        m_Log.push(log_line);
        
        if(m_LogSize>=LogMaxSize)
        {
            m_LogSize=0;
            var log_patial=m_Log;
            m_Log=[];
            
            var data=System.CreateServiceData(
                "FileService","SaveLog",{FileName:"/"+GetUser()+"/Session/C"+m_SessionID+".log",Content:log_patial.join("")}
            );
            
            System.SendCommand(function(){},function(){},data,false);
        }
    }

    function CreateHttpRequest()
    {
        var request=null;
        if(window.XMLHttpRequest) 
        {
            request=new XMLHttpRequest();
        }
        else if(window.ActiveXObject) 
        {
            request=new ActiveXObject("Microsoft.XMLHttp");
        }
        return request;
    }

    function FormatNumber(num,length)
    {
        var s=num.toString();
        var zero="";
        for(var i=0;i<length-s.length;i++) zero+="0";
        return zero+s;
    }

    function GenerateUniqueId()
    {
        var dt=new Date()
        m_Count++;
        return 'ID'+FormatNumber(m_Count,6);
    }

    function RequestText(callback,errorCallback,xmlUrl)
    {
        var request=CreateHttpRequest();
        if(request)
        {
            var url=xmlUrl;
            request.open("GET",url,true); 
            request.onreadystatechange=function()
            {
                if(request.readyState==4)
                {
                    try
                    {
                        switch(request.status)
                        {
                        case 200:
                            callback(request.responseText);
                            break;
                        default:
                            if(errorCallback) errorCallback(new Exception("Server Error",request.statusText));
                        }
                    }
                    catch(ex)
                    {
                        errorCallback(new Exception(ex.name,ex.message));
                    }
                    finally
                    {
                        request=null;
                    }
                }
            }
            request.send(null);
        }
    }

    function SendCommand(callback,errorCallback,data,queue)
    {
        if(queue==undefined) queue=true;
        if(CommandQueue!=null && queue)
        {
            CommandQueue.Push(data,callback,errorCallback);
        }
        else
        {
            var postData='<?xml version="1.0" encoding="utf-8" ?>\r\n';
            var id=GenerateUniqueId();
            postData+=String.format('<Command ID="{0}" SessionID=\"{1}">\r\n{2}\r\n</Command>\r\n',id,m_SessionID,data);
            var request=CreateHttpRequest();
            if(request)
            {
                request.open("POST","Command.aspx",true);
                request.setRequestHeader('Content-Type','text/xml')
                request.setRequestHeader("Cache-Control","no-cache")
                request.onreadystatechange=function()
                {
                    if(request.readyState==4)
                    {
                        try
                        {
                            switch(request.status)
                            {
                            case 200:
                                {
                                    var ret=eval(request.responseText);
                                    if(ret.IsSucceed)
                                    {
                                        System.WriteLog(String.format("CMD {0} S",id));
                                        callback(ret.Response);
                                    }
                                    else
                                    {
                                        System.WriteLog(String.format("CMD {0} E {1}",id,ret.Exception.Message));
                                        errorCallback(ret.Exception);
                                    }
                                    break;
                                }
                            default:
                                {
                                    if(errorCallback) errorCallback(new Exception("Server Error",request.statusText));
                                    System.WriteLog(String.format("CMD {0} E {1}",id,request.status));
                                }
                            }
                        }
                        finally
                        {
                            request=null;
                        }
                    }
                }
                System.WriteLog(String.format("CMD {0} R",id));
                request.send(postData);
            }
            return request;
        }
    }

    function Post(callback,errorCallback,url,data)
    {
        var request=CreateHttpRequest();
        if(request)
        {
            var dataStr='';
            if(data.constructor==Object)
            {
                for(var k in data)
                {
                    if(dataStr!="") dataStr+="&";
                    dataStr+=(k+"="+escape(data[k]));
                }
            }
            else
            {
                dataStr=data.toString();
            }
            request.open("POST",url,true); 
            request.setRequestHeader('Content-Type','application/x-www-form-urlencoded')
            request.setRequestHeader("Cache-Control","no-cache") 
            request.onreadystatechange=function()
            {
                if(request.readyState==4)
                {
                    try
                    {
                        switch(request.status)
                        {
                        case 200:
                            callback(request.responseXML);
                            break;
                        default:
                            if(errorCallback) errorCallback({status:request.status,statusText:request.statusText});
                        }
                    }
                    finally
                    {
                        request=null;
                    }
                }
            }
            request.send(dataStr);
        }
        return request;
    }

    function Link(rel,href,type)
    {
        var e=document.createElement("link");
        e.rel=rel
        e.type=type
        e.href=href;
        var hs=document.getElementsByTagName("head");
        if(hs.length>0) hs[0].appendChild(e);
        return e;
    }

    function GetServiceUrl(service)
    {
        return "Services/"+service;
    }

    function GetUrl(path)
    {
        if(path.substr(0,1)!='/') path=String.format("/{0}/{1}",m_User,path);
        return encodeURI("Users"+path);
    }
    
    function GetFullPath(path)
    {
        if(path.substr(0,1)!='/') path=String.format("/{0}/{1}",m_User,path);
        return path;
    }

    function GetDirectoryName(path)
    {
        var split=path.lastIndexOf("/");
        if(split==-1) split=0;
        return path.substring(0,split);
    }
        
    function LoadModules(completeCallback,errorCallback,paths,index)
    {
        function fail(ex)
        {
            WriteLog(String.format("Load {0} Fail",path));
            System.OnOutput.Call(
                String.format(
                    "<table style='width:100%;'>"+
                        "<tr><td class='text'>Load \"{0}\"</td><td class='fail'>[FAIL]</div></td></tr>"+
                        "<tr><td class='fail_msg' colspan='2'>{1}:{2}</td></tr>"+
                    "</table>",
                    path,ex.Name,ex.Message
                )
            );
            errorCallback(ex);
        }
        
        if(index==undefined) index=0;
        
        var path=paths[index];
        if(path.substr(0,1)!="/")
        {
            path=m_SpecialDirectory.Module+"/"+path;
        }
        var moduleId=path.toUpperCase();
        if(m_Modules[moduleId]==null)
        {
            RequestText(load,fail,GetUrl(path));
        }
        else
        {
            loadComplete();
        }
        function load(text)
        {
            var moudle_ctor=new Function(
                String.format(m_ModuleCtorFormat,GetDirectoryName(path),path,text)
            );
            var moudle=new moudle_ctor();
            if(moudle.Initialize!=null)
                moudle.Initialize(complete,fail);
            else
                complete();
            function complete()
            {
                if(m_Modules[moduleId]==null)
                {
                    m_Modules[moduleId]=moudle;
                    m_ModulesArray.push(moudle);
                }
                WriteLog(String.format("Load {0} Success",path));
                System.OnOutput.Call(String.format("<table cellspacing='0' style='width:100%;'><tr><td class='text'>Load \"{0}\"</td><td class='success'>[ OK ]</td></tr></table>",path));
                loadComplete();
            }
        }
        
        function loadComplete()
        {
            if(index==paths.length-1)
                completeCallback();
            else
                LoadModules(completeCallback,errorCallback,paths,index+1);
        }
    }

    function GetModule(path)
    {
        if(path.substr(0,1)!='/') path=m_SpecialDirectory.Module+"/"+path;
        var moduleId=path.toUpperCase();
        return m_Modules[moduleId];
    }

    function Exec(callback,errorCallback,path)
    {
        var args=[]
        var split=path.lastIndexOf("/");
        if(split==-1) split=0;
        args.push(path.substring(0,split));
        for(var index=3;index<arguments.length;index++)
        {
            args.push(arguments[index])
        }
        
        var task=null;
        if(GetModule(path)==null)
        {
            task=Taskbar.AddTask(null,"正在加载...");
            task.Shine(false);
        }
        
        LoadModules(complete,error,[path])
        
        function complete()
        {
            if(task!=null) Taskbar.RemoveTask(task);
            
            if(callback!=null) callback();
            var app=GetModule(path);
            if(app.Application!=null)
            {
                var instance=new Application(app.Application,path);
                try
                {
                    instance.Start.apply(instance,args);
                }
                catch(ex)
                {
                    alert(ex);
                }
            }
        }
        
        function error(msg)
        {
            if(task!=null) Taskbar.RemoveTask(task);
            errorCallback(msg);
        }
    }
    
    var m_EnvironmentVariable={
        SystemRoot:"",
        ThemesRoot:"",
        Version:""
    };
    
    function TranlateEnvironmentVariable(str)
    {
        return str.replace(
            /%[a-z,A-Z,_,1-9]+%/gi,
            function(val)
            {
                return m_EnvironmentVariable[val.substr(1,val.length-2)];
            }
        );
    }

    function Initialize(config)
    {
        if(m_Browser=="IE")
        {
            try
            {
                document.execCommand("BackgroundImageCache", false, true);
            }
            catch(ex)
            {
            }
        }
        document.oncontextmenu=function(evt)
        {
            if(evt==undefined) evt=event;
            var target=null;
            if(evt.target!=undefined) target=evt.target;
            else if(evt.srcElement!=undefined) target=evt.srcElement;
            if(target.tagName!=undefined && (target.tagName.toUpperCase()=='INPUT' ||  target.tagName.toUpperCase()=='TEXTAREA'))
            {
                return true;
            }
            else
            {
                return false;
            }
        }
        document.onselectstart=function(evt)
        {
            if(evt==undefined) evt=event;
            var target=null;
            if(evt.target!=undefined) target=evt.target;
            else if(evt.srcElement!=undefined) target=evt.srcElement;
            if(target.tagName!=undefined && target.tagName.toUpperCase()!='DIV')
            {
                return true;
            }
            else
            {
                return false;
            }
        }
        if(config.UserInfo!=undefined) m_User=config.UserInfo.Name;
        if(config.UserInfo!=undefined) m_UserInfo=config.UserInfo;
        if(config.Language!=undefined) m_Language=config.Language;
        if(config.Debug!=undefined) Debug=config.Debug;
        if(config.SessionID!=undefined) m_SessionID=config.SessionID;
        
        WriteLog(String.format("Start {0} {1}",m_SessionID,DateToString(new Date())));
        
        m_SpecialDirectory.Application=String.format("/{0}/System/{1}",m_User,Version);
        m_SpecialDirectory.Theme=String.format("/{0}/Themes/{1}/Default",m_User,Version);
        m_SpecialDirectory.Module=String.format("/{0}/System/{1}",m_User,Version);
        m_SpecialDirectory.System=String.format("/{0}/System/{1}",m_User,Version);
        m_SpecialDirectory.Home="/"+m_User+"/Home";
        m_SpecialDirectory.Config="/"+m_User+"/Config";
        m_SpecialDirectory.Groups="/"+m_User+"/Groups";
        m_SpecialDirectory.Root="/"+m_User
        m_SpecialDirectory.PublicImages="/"+m_User+"/Public/Images";
        
        m_EnvironmentVariable={
            SystemRoot:m_SpecialDirectory.System,
            ThemesRoot:m_SpecialDirectory.Theme,
            Version:Version
        };
        
        This.OnOutput.Attach(Write);
        
        This.LoadModules(
            function()
            {
                Desktop=System.GetModule("Desktop.js").Desktop;
                Taskbar=System.GetModule("Desktop.js").Taskbar;
                OutputPanel.Hide();
                CommandQueue.Start();
                ResponsesCache.Start();
                This.OnLoad.Call();
                if(InviteUser!="" && InviteCode!="")
                {
                    This.Exec(function(){},function(){},"IM.js",InviteUser);
                }
            },
            function(){},
            ["IO.js","Communication.js","Management.js","Controls.js","Window.js","CommonDialog.js","Desktop.js"]
        );
    }
    
    function GetThemeResourceUrl(relativePath)
    {
        return GetUrl(m_SpecialDirectory.Theme+(relativePath.substr(0,1)=="/"?relativePath:"/"+relativePath));
    }

    function GetSpecialDirectory(name)
    {
        return m_SpecialDirectory[name];
    }

    function RegisterGlobal(func)
    {
        var uniqueId=GenerateUniqueId();
        m_Global[uniqueId]=func;
        return uniqueId;
    }

    function RemoveGlobal(uniqueId)
    {
        delete m_Global[uniqueId];
    }

    function Application(base_ctor,fileName)
    {
        base_ctor.call(this);
            
        var id=m_Applications.length;
        m_Applications.push(this);
        
        this.Dispose=function()
        {
            m_Applications[id]=null;
        }
        
        this.GetResourceUrl=function(relativePath)
        {
            return Module.GetResourceUrl(relativePath);
        }
    }

    function Invoke(completeCallback,errorCallback,objs,asynMethod,continueIfError,completeOneCallback)
    {	
        function callOne(index)
        {
            var obj=objs[index];
            if(obj[asynMethod]!=null)
            {
                try
                {
                    obj[asynMethod].call(obj,complete,function(ex){error(ex,obj);});
                }
                catch(ex)
                {
                    error(ex,obj);
                }
            }
            else
                complete();
            function complete()
            {
                if(completeOneCallback!=undefined) completeOneCallback(obj);
                if(index==objs.length-1) completeCallback();else callOne(index+1);
            }
            function error(msg,o)
            {
                errorCallback(msg,o);
                if(!continueIfError || index==objs.length-1) completeCallback();else callOne(index+1);
            }
        }
        if(objs.length>0) callOne(0);else completeCallback();
    }

    function Call(completeCallback,errorCallback,funcs,caller,continueIfError,completeOneCallback)
    {
        function callOne(index)
        {
            var func=funcs[index];
            if(func!=null)
            {
                try
                {
                    func.call(caller,complete,error);
                }
                catch(ex)
                {
                    error(ex);
                }
            }
            else
                complete();
            function complete()
            {
                if(completeOneCallback!=undefined) completeOneCallback(obj);
                if(index==funcs.length-1) completeCallback();else callOne(index+1);
            }
            function error(msg)
            {
                errorCallback(msg);
                if(!continueIfError || index==funcs.length-1) completeCallback();else callOne(index+1);
            }
        }
        if(objs.length>0) callOne(0);else completeCallback();
    }

    function GetUser()
    {
        return m_User;
    }

    function GetLanguage()
    {
        return m_Language;
    }

    function GetGlobal(id)
    {
        return m_Global[id];
    }
    
    function GetBrowser()
    {
        return m_Browser;
    }
    
    function GetSessionID()
    {
        return m_SessionID;
    }
    
    function HandleException(ex)
    {
        alert(ex.Message);
    }

    function Dispose(completeCallback,errorCallback)
    {
        function fail(ex,m)
        {
            WriteLog(String.format("Dispose {0} Fail",m.FileName));
            System.OnOutput.Call(
                String.format(
                    "<table style='width:100%;'>"+
                        "<tr><td class='text'>Dispose \"{0}\"</td><td class='fail'>[FAIL]</div></td></tr>"+
                        "<tr><td class='fail_msg' colspan='2'>{1}:{2}</td></tr>"+
                    "</table>",
                    m.FileName,ex.Name,ex.Message
                )
            );
            errorCallback(ex);
        }
        
        var as=[];
        for(var i in m_Applications)
        {
            if(m_Applications[i]!=null) as.push(m_Applications[i]);
        }
        as.reverse();
        Invoke(completeDisposeApps,fail,as,"Terminate",true);
        
        function completeDisposeApps()
        {
            m_ModulesArray.reverse();
            Invoke(completeCallback,fail,m_ModulesArray,"Dispose",true,completeOneCallback);
            function completeOneCallback(m)
            {
                WriteLog(String.format("Dispose {0}",m.FileName));
                System.OnOutput.Call(String.format("<table cellspacing='0' style='width:100%;'><tr><td class='text'>Dispose \"{0}\"</td><td class='success'>[ OK ]</td></tr></table>",m.FileName));
            }
        }
    }
    
    function Logout(completeCallback)
    {
        Post(completeCallback,completeCallback,"System.aspx",{Command:"Logout"});
    }
    
    function Shutdown()
    {
        System.OnUnload.Call();
        CommandQueue.Stop();
        ResponsesCache.Stop();
        OutputPanel.Clear();
        OutputPanel.Show();
        Desktop.SetVisible(false);
        Taskbar.SetVisible(false);
        System.Dispose(Dispose_Complete,function(){});
    }
    
    function Dispose_Complete()
    {
        WriteLog(String.format("Shutdown {0}",m_SessionID));
            
        var data=System.CreateServiceData(
            "FileService","SaveLog",{FileName:"/"+GetUser()+"/Session/C"+m_SessionID+".log",Content:m_Log.join("")}
        );
        
        System.OnOutput.Call("Upload Log ...");
        System.SendCommand(SaveLog_Complete,SaveLog_Complete,data,false);
    }
    
    function SaveLog_Complete()
    {
        This.Logout(Logout_Complete);
    }
    
    function Logout_Complete()
    {
        System.OnOutput.Detach(Write);
        window.onbeforeunload=null;
        window.location="login.aspx";
    }
    
    function LoadImage(src)
    {
        var img=new Image();
        img.src=src;
        return img;
    }
    
    function RaisException(type)
    {
        window.onbeforeunload=null;
        window.location="Exception/"+type+".htm";
    }
    
    function GetUserInfo()
    {
        return System.Clone(m_UserInfo);
    }

    
    this.WriteLog=WriteLog;
    
    this.RaisException=RaisException;
    this.Logout=Logout;
    this.Shutdown=Shutdown;

    this.GetBrowser=GetBrowser;
    this.GetSessionID=GetSessionID;
    this.HandleException=HandleException

    this.RegisterGlobal=RegisterGlobal;
    this.RemoveGlobal=RemoveGlobal;
    this.GetGlobal=GetGlobal;

    this.CreateHttpRequest=CreateHttpRequest;
    this.RequestText=RequestText;
    this.Post=Post;

    this.GenerateUniqueId=GenerateUniqueId;
    this.GetUser=GetUser;
    this.GetUserInfo=GetUserInfo;
    this.GetLanguage=GetLanguage;
    this.GetUrl=GetUrl;
    this.GetFullPath=GetFullPath;
    this.GetServiceUrl=GetServiceUrl;
    this.GetSpecialDirectory=GetSpecialDirectory;
    this.Link=Link;
    this.Initialize=Initialize;
    this.SendCommand=SendCommand;

    this.Exec=Exec;
    this.LoadModules=LoadModules;
    this.GetModule=GetModule;
    this.Dispose=Dispose;

    this.Invoke=Invoke;
    this.Call=Call;
    
    this.GetThemeResourceUrl=GetThemeResourceUrl;
    this.LoadImage=LoadImage;
    
    this.TranlateEnvironmentVariable=TranlateEnvironmentVariable;
}

function Delegate()
{
    var all=[];
    
    var This=this;
    
    This.Call=function()
    {
        var ret=null;
        for(var index in all)
        {
            ret=all[index].apply(This,arguments);
        }
        return ret;
    }
    
    This.Attach=function(func)
    {
        all.push(func);
    }
    
    This.Detach=function(func)
    {
        var index=0;
        for(index in all) 
        {
            if(all[index]==func) break;
        }
        if(index<all.length)
        {
            delete all[index];
            all.splice(index,1);
        }
    }
}
String.format=function(fmt)
{
    var params=arguments;
    var pattern=/{{|{[1-9][0-9]*}|\x7B0\x7D/g;
    return fmt.replace(
        pattern,
        function(p)
        {
            if(p=="{{") return "{";
            return params[parseInt(p.substr(1,p.length-2),10)+1]
        }
    );
}

var System = new System_Ctor();
var CommandQueue = new CommandQueue_Ctor();
var ResponsesCache = new ResponsesCache_Ctor();

System.Object=function()
{
    this.GetType=function()
    {
        return "System.Object";
    }
    
    this.is=function(typeName)
    {
        return typeName==this.GetType();
    }
}

System.Clone=function(val)
{
    if(val==null)
    {
        return null
    }
    else if(val.constructor==Array)
    {
        var a=new Array()
        for(i in val)
        {
            a[i]=System.Clone(val[i])
        }
        return a
    }
    else if(val.constructor==Object)
    {
        var a=new Object()
        for(c in val)
        {
            a[c]=System.Clone(val[c])
        }
        return a
    }
    else if(val.constructor==Number)
    {
        return val
    }
    else if(val.constructor==String)
    {
        return val
    }
    else if(val.constructor==Date)
    {
        return val
    }
    else
        return val;
}

System.TransferCharForXML=function (str)
{
    var res=str.replace(
        /&|\x3E|\x3C|\x5E|\x22|\x27|[\x00-\x1F]|\t/g,
        function(s)
        {
            var ascii=s.charCodeAt(0)
            return "&#"+ascii.toString(10)+";";
        }
    )
    return res;
}

System.TransferCharForJavascript=function(s)
{
    var newStr=s.replace(
        /[\x26\x27\x3C\x3E\x0D\x0A]/g,
        function(c)
        {
            ascii=c.charCodeAt(0)
            return '\\u00'+(ascii<16?'0'+ascii.toString(16):ascii.toString(16))
        }
    );
    return newStr;
}

System.CreateServiceData=function(name,command,params)
{
    var lines=[];
    //lines.push('<?xml version="1.0" encoding="utf-8" ?>');
    lines.push(String.format('<{0} Command="{1}">',name,command));
    for(var key in params)
    {
        lines.push(String.format('<Param Name="{0}">{1}</Param>',key,System.TransferCharForXML(params[key].toString())));
    }
    lines.push(String.format("</{0}>",name));
    return lines.join("\r\n");
}

System.ToString=function(val)
{
    if(val==null)
    {
        return null
    }
    else if(val.constructor==Array)
    {
        var builder=[];
        builder.push("[");
        for(var index in val)
        {
            if(index>0) builder.push(",");
            builder.push(System.ToString(val[index]));
        }
        builder.push("]");
        return builder.join("");
    }
    else if(val.constructor==Object)
    {
        var builder=[];
        builder.push("{");
        var index=0;
        for(var key in val)
        {
            if(index>0) builder.push(",");
            builder.push(String.format("\"{0}\":{1}",key,System.ToString(val[key])));
            index++;
        }
        builder.push("}");
        return builder.join("");
    }
    else if(val.constructor==Number)
    {
        return val.toString();
    }
    else if(val.constructor==String)
    {
        return String.format('"{0}"',System.TransferCharForJavascript(val));
    }
    else if(val.constructor==Date)
    {
        return String.format(
            "new Date({0})",val.getTime()
        );
    }
    else if(val.ToString!=undefined)
    {
        return val.toString();
    }
}

System.DisableSelect=function(elem,disableChildren)
{
    if(disableChildren==undefined) disableChildren=false;
    
    if(System.GetBrowser()=="IE")
    {
        if(elem.setAttribute!=undefined) elem.setAttribute("unselectable","on");
        
        if(disableChildren)
        {
            for(var i=0;i<elem.childNodes.length;i++)
            {
                System.DisableSelect(elem.childNodes[i],true);
            }
        }
    }
}

System.EncodeUrl=function(url)
{
    var temp=[];
    for(var i = 0 ;i<url.length;i++)
    {
        var ascii=url.charCodeAt(i);
        temp.push("%");
        temp.push(acrii.toString(16));
    }
    return temp.join("");
}

System.AttachEvent=function(elem,evtName,handler)
{

    if(elem.attachEvent)
    {
        elem.attachEvent("on"+evtName,handler);
    }
    else if(elem.addEventListener)
    {
        elem.addEventListener(evtName,handler,false);
    }
}

var CommandHandler={};

System.RegisterCommandHandler=function(id,handler)
{
    CommandHandler[id]=handler;
}

System.RemoveCommandHandler=function(id)
{
    delete CommandHandler[id];
}

System.RegisterCommandHandler(
    "SystemCommand",
    function(param)
    {
        if(param.Command=="SessionRecover")
        {
            System.OnSessionRecover.Call(param.Data);
        }
    }
);

System.SYSTEM_MESSAGE_GUID = "6851D15B-041D-4AB8-B639-12DBC5C1059F";

System.Path=function()
{
}

System.Path.GetRelativePath=function(parent,sub)
{
    if(parent.length>sub.length) return null;
    
    parentPath=parent.toUpperCase();
    subPath=sub.toUpperCase();
    
    if(parentPath==subPath) return "";
    var index = subPath.indexOf(parentPath);
    if(index==0 && subPath.charAt(parentPath.length)=='/')
    {
        return sub.substr(parentPath.length+1,subPath.length-parentPath.length);			
    }
    else
    {
        return null;
    }
    
}

System.Path.GetFileName=function(fullName)
{
    var index=fullName.lastIndexOf("/")
    var name=(index==-1?fullName:fullName.substring(index+1,fullName.length));
    return name;
}

System.Path.GetFileExtension=function(fullName)
{
    var index=fullName.lastIndexOf(".")
    var ext=(index==-1?"":fullName.substring(index,fullName.length));
    return ext;
}

System.Path.GetDirectoryName=function(fullName)
{
    var index=fullName.lastIndexOf("/")
    switch(index)
    {
    case -1:
        return null;
    case 0:
        return "/";
    default:
        return fullName.substring(0,index);
    }
}

System.Path.GetFileNameNoExtention=function(fullName)
{
    var index=fullName.lastIndexOf("/")
    var name=(index==-1?fullName:fullName.substring(index+1,fullName.length));
    index=name.lastIndexOf(".");
    return index==-1?name:name.substring(0,index);
}

System.Path.Join=function()
{
    var path="";
    for(var i=0;i<arguments.length;i++)
    {
        if(arguments[i]!=undefined && arguments[i]!=null && arguments[i]!="")
        {
            if(arguments[i].charAt(arguments[i].length-1)!='/') path+='/';
            path+=arguments[i];
        }
    }
    return path;
}



function PostData(url,data,type,timeout,onsuccess,onerror,onabort)
{
    try
    {
        var request = null;
        
        if(window.XMLHttpRequest) 
        {
            request=new XMLHttpRequest();
        }
        else if(window.ActiveXObject) 
        {
            request=new ActiveXObject("Microsoft.XMLHttp");
        }
        
        request.onreadystatechange=function()
        {
            if(request.readyState==4)
            {
                try
                {
                    switch(request.status)
                    {
                    case 200:
                        {
                            if(request.responseText!="")
                                onsuccess(request);
                            else
                                onerror(new Exception("Server Error","Unknown"));
                            break;
                        }
                    default:
                        {
                            onerror(new Exception(request.status,request.statusText));
                            break;
                        }
                    }
                }
                catch(ex)
                {
                    onerror(new Exception(ex.mame,ex.message));
                }
                if(timer!=null) clearTimeout(timer);
                request=null;
                timer=null;
            }
        }
        var timer=null;
        if(timeout>0)
        {
            timer = setTimeout( 
                function()
                {
                    if(request!=null)
                    {
                        request.onreadystatechange=function(){};
                        request.abort();
                        request=null;
                        onabort();
                    }
                },
                timeout
            );
        }
        
        request.open("POST",url,true);
        request.setRequestHeader("Content-Type",type);
        request.send(data);
        return {
            Abort:function()
            {
                if(timer!=null) clearTimeout(timer);
                if(request!=null)
                {
                    request.onreadystatechange=function(){};
                    request.abort();
                    request=null;
                    onabort();
                }
                timer=null;
            }
        }
    }
    catch(ex)
    {
        onerror(new Exception(ex.name,ex.message));
    }
}

var CommandCallbackCache={};

function CommandQueue_Ctor()
{
    var m_Controler=null;
    var m_Stop=false;	
    var m_Cache=[];
    
    this.Push=function(cmd,callback,error)
    {
        var id=System.GenerateUniqueId();
        CommandCallbackCache[id]={
            ID:id,
            Callback:callback,
            ErrorCallback:error
        };
        m_Cache.push({ID:id,Data:cmd,ErrorCallback:error});
    }
    
    this.Start=function()
    {
        m_Stop=false;
        Send();
    }
    
    this.Stop=function()
    {
        m_Stop=true;
        if(m_Controler!=null) m_Controler.Abort();
    }	
    
    function CreateRequestData(msgs)
    {	
        var temp=[];
        temp.push('<?xml version="1.0" encoding="utf-8" ?>');
        temp.push(String.format('<Queue SessionID="{0}">',System.GetSessionID()));
        for(var i=0;i<msgs.length;i++)
        {
            System.WriteLog(String.format("CMD {0} R",msgs[i].ID));
            temp.push(String.format('<Command ID="{0}">\r\n{1}\r\n</Command>\r\n',msgs[i].ID,msgs[i].Data));
        }
        temp.push('</Queue>');
        return temp.join("\r\n");
    }
    
    function Send()
    {
        if(m_Stop) return;
        
        if(m_Cache.length>0)
        {
            var queueId=System.GenerateUniqueId();
            
            var msgs=m_Cache;
            m_Cache=[];
            var data=CreateRequestData(msgs);
            
            System.WriteLog(String.format("CQ {0} R",queueId));
            
            m_Controler = PostData(
                "CommandQueue.aspx?ID="+queueId,
                data,"text/xml",30*1000,
                function(request)//onsuccess
                {
                    var ret=eval(request.responseText);
                    if(ret.IsSucceed)
                    {
                        System.WriteLog(String.format("CQ {0} C",queueId));
                        for(var key in ret.Response.Fail)
                        {
                            try
                            {
                                CommandCallbackCache[key].ErrorCallback(ret.Response.Fail[key]);
                                delete CommandCallbackCache[key];
                            }
                            catch(ex)
                            {
                            }
                        } 
                        setTimeout(Send,100);
                    }
                    else
                    {
                        var error=ret.Exception;
                        System.WriteLog(String.format("CQ {0} E {1} {2}",queueId,error.Name,error.Message));
                        if(ret.Exception.Name=="SessionAbandonException")
                        {
                            This.Stop();
                        }
                        else if(ret.Exception.Name=="SessionShutdownException")
                        {
                            This.Stop();
                        }
                        else
                        {
                            setTimeout(Send,100);
                        }
                    }
                },
                function(error)//onerror
                {
                    for(var i in msgs)
                    {
                        try
                        {
                            var key=msgs[i].ID;
                            CommandCallbackCache[key].ErrorCallback(error);
                            delete CommandCallbackCache[key];
                        }
                        catch(ex)
                        {
                        }
                    } 
                    System.WriteLog(String.format("CQ {0} E {1} {2}",queueId,error.Name,error.Message));
                    setTimeout(Send,5000);
                },
                function()//onabort
                {
                    for(var i in msgs)
                    {
                        try
                        {
                            var key=msgs[i].ID;
                            CommandCallbackCache[key].ErrorCallback(new Exception("Error","连接超时!"));
                            delete CommandCallbackCache[key];
                        }
                        catch(ex)
                        {
                        }
                    } 
                    System.WriteLog(String.format("CQ {0} E Timeout",queueId));
                    setTimeout(Send,200);
                }
            );
        }
        else 
        {
            setTimeout(Send,1000);
        }
    }
}

var MaxSN=0;

function ResponsesCache_Ctor()
{
    var Timeout=DEBUG ? 30*1000 : 30*1000;
    
    var baseTime=new Date(2009,0,1);
    
    var m_Controler=null;
    var m_Stop=false;	
    
    this.Start=function()
    {
        m_Stop=false;
        Send();
    }
    
    this.Stop=function()
    {
        m_Stop=true;
        if(m_Controler!=null) m_Controler.Abort();
    }	
    
    function Send()
    {
        if(m_Stop) return;
        
        var RequestID=System.GenerateUniqueId();
        var data=String.format('RequestID={0}&SessionID={1}&SN={2}',RequestID,System.GetSessionID(),MaxSN);
                
        System.WriteLog(String.format("RR {0} R",RequestID));
        
        m_Controler = PostData(
            "ReceiveResponses.aspx?ID="+RequestID,
            data,'application/x-www-form-urlencoded',Timeout,
            function(request)//onsuccess
            {
                try
                {
                    var ret = eval(request.responseText);
                    if(ret.IsSucceed)
                    {
                        var responses = ret.Response;
                        
                        var log = String.format("RR {0} S ",RequestID);
                        for(var i in responses)
                        {
                            if(i>0) log+=",";
                            log+=responses[i].SN;			
                        }
                        System.WriteLog(log);
                        for(var i in responses)
                        {				
                            var cr=responses[i];
                            if(cr.SN>MaxSN) MaxSN = cr.SN;
                            
                            var ret=cr.Data;
                            var key=cr.ID;
                            if(ret.IsSucceed)
                            {
                                if(CommandHandler[key]!=undefined)
                                {
                                    CommandHandler[key](ret.Response);
                                }
                                if(CommandCallbackCache[key]!=undefined) 
                                {
                                    CommandCallbackCache[key].Callback(ret.Response);
                                }
                                System.WriteLog(String.format("CMD {0} S",key));
                            }
                            else
                            {
                                if(CommandCallbackCache[key]!=undefined) 
                                    CommandCallbackCache[key].ErrorCallback(ret.Exception);
                                System.WriteLog(String.format("CMD {0} E {1}",key,ret.Exception.Message));
                            }
                            delete CommandCallbackCache[key];
                        }
                    }
                    else
                    {
                        var error=ret.Exception;
                            
                        System.WriteLog(String.format("RR {0} E {1} {2}",RequestID,error.Name,error.Message));
                            
                        if(ret.Exception.Name=="SessionAbandonException")
                        {
                            System.RaisException("Abandon");
                            return;
                        }
                        else if(ret.Exception.Name=="SessionShutdownException")
                        {
                            System.Shutdown();
                            return;
                        }
                    }	
                }
                catch(ex)
                {
                }
                setTimeout(Send,10);
            },
            function(error)//onerror
            {
                var callbacks=CommandCallbackCache;
                CommandCallbackCache={};
                for(var key in callbacks)
                {
                    try
                    {
                        callbacks[key].ErrorCallback(error);
                    }
                    catch(ex)
                    {
                    }
                }
                System.OnServerError.Call(error);
                setTimeout(Send,5000);
            },
            function()//onabort
            {
                System.WriteLog(String.format("RR {0} Abort",RequestID));
                setTimeout(Send,10);
            }
        );
    }
}