Function.prototype.parent = null; // parent is object that contain function

Function.prototype.delegate = function()
{
    var self = this;
    var args = Array.prototype.slice.call(arguments);
   
    return function()
    {
        return self.apply(self.parent, args);
    };
};

Function.prototype.run = function(skip)
{
    var my   = Array.prototype.slice.call(arguments);
    var args = Array.prototype.slice.call(arguments.callee.caller.arguments);
    
    if (skip != null)
    {
        for (var i = 0; i < skip && i < args.length; ++i)
        {
            args.shift();
        }
    }

    my.shift();

    for (var i = my.length - 1; i > -1; --i)
    {
        args.unshift(my[i]);
    }
    
    this.apply(this.parent, args);
};

Object.prototype.clone = function(obj)
{
    var newObject;
    var self = (obj == null)?this:obj;
    switch (typeof(self)) 
    {
        case "object":
            newObject = new self.constructor();
            for (var item in self) { newObject[item] = self.clone(self[item]);}
            break;
        default:
            newObject = self;
            break;
    }
    return newObject;
};

var fast = 
{
    version     : "1.0",
    d           : document,
    htmlTag     : null,
    headTag     : null,
    bodyTag     : null,
    isInited    : false,
    Class       : "time",
    spliter     : "¦",
    isOpera     : navigator.appVersion.indexOf("Opera")     != -1,
    isIE        : navigator.appVersion.indexOf("MSIE")      != -1,
    isFirefox   : navigator.appVersion.indexOf("Firefox")   != -1,
    htmlNS      : "http://www.w3.org/1999/xhtml",
    svgNS       : "http://www.w3.org/2000/svg",
    timeNS      : "urn:schemas-microsoft-com:time",
    vmlNS       : "urn:schemas-microsoft-com:vml",
    isFirst     : true,
    
    init : function()
    {
        if (this.isInited) return;
        
        this.htmlTag = this.d.getElementsByTagName("html")[0];
        this.headTag = this.d.getElementsByTagName("head")[0];
        this.bodyTag = this.d.body;
        
        if (fast.fx != null) fast.fx.init();
        if (fast.pages.master != null) fast.pages.master.init();

        this.isInited = true;
        
        fast.process(fast);
    },
    
    initPage : function()
    {
        fast.init();
        
        if (this.isFirst == true)
        {
            this.isFirst = false;
            
            var d = fast.$("fastdata");
            if (d.value != "") 
            {
                val = d.value;
                d.value = "";
            }
        }
        
        fast.pages.master.initPage.run();
    },
    
    process : function(cfg)
    {
        for (var p in cfg)
        {
            if (cfg[p] == null)
            {
                continue;
            }
            else if (typeof cfg[p] == "function")
            {
                cfg[p].parent = cfg;
            }
            else if (typeof cfg[p] == "object" && cfg[p].nodeName == null)
            {//debugger;
                fast.process(cfg[p]);
            }
        }
    },
        
    createStyle : function(style)
    {
        var el = this.d.createElement("<style>" + style + "</style>");
    },
    
    createElement : function(tag, to, xmlns)
    {
        var el = null;
        
        if (xmlns == null)
        {
            el = this.d.createElement(tag);
        }
        else
        {
            el = this.d.createElementNS(xmlns, tag);
        }
        
        if (to != null) to.appendChild(el);
        
        return el;
    },
    
    getobj  : function(obj)
    {
        if (typeof obj == 'object')
        {
            return obj;
        }
        
        return this.d.getElementById(obj);
    },
    
    $  : function(id)
    {
        if (typeof id == 'string') return this.d.getElementById(id);
        
        return id;
    },
    
    $set : function(obj, prop, val)
    {
        if (obj.namespaceURI == fast.svgNS)
        {
            if (prop == "className") prop = "class";
            obj.setAttribute(prop, val);
        }
        else
        {
           obj[prop] = val; 
        }
    },
    
    startRequest : function(params, async, callback, objback)
    { 
        var obj = this.createRequestObject();

        obj.open("GET", params, async);
        obj.onreadystatechange = this.handleStateChange(obj, callback, objback);
        obj.send(null);
          
        return obj;
    },

    createRequestObject : function()
    {
        if (window.XMLHttpRequest) 
        {
            return new XMLHttpRequest();
        } 
        else if (window.ActiveXObject) 
        {
            return new ActiveXObject('Msxml2.XMLHTTP');
        }
    },
    
    handleStateChange : function(xmlHttp, callback, objback)  
    { 
        return function change()
        {
            if(xmlHttp.readyState == 4)  
            { 
                if(xmlHttp.status == 200)  
                {   
                    var str = xmlHttp.responseText;
                    xmlHttp.abort();
                    if (callback != null) callback.run(0, str, objback);
   	            }
            }
        }
    },
    
    insertParentCfg : function(par, obj)
    {
        var prop = null;
        
        if (obj.parent != null && obj.parentProp != null)
        {
            obj.parent[obj.parentProp] = par;
            par.parent = obj.parent;
            par.parentProp = obj.parentProp;
        }

        prop = fast.getPropName();
        par[prop] = obj;
        obj.parent = par;
        obj.parentProp = prop;
    },
    
    setParent : function(par, obj)
    {
        if (obj.parent != null && obj.parentProp != null)
        {
            obj.parent[obj.parentProp] = null;
            obj.parent = null;
            obj.parentProp = null;
        }
        
        var prop = fast.getPropName();
        obj.parent = par;
        obj.parentProp = prop;
        par[prop] = obj;
    },
    
    validate : function(cfg, root)
    {
        if (fast.fx.mode == "svg" && !(cfg instanceof Array))
        {
            var tmp = null;
        
            if (fast.v[cfg.tag] != null)
            {
                cfg.xmlns = fast.svgNS;
            
                if (cfg.parent != null && fast.v[cfg.parent.tag] != null)
                {
                    if (cfg.parent.tag != "g")
                    {
                        var tmp2 = {tag : "g", xmlns : fast.svgNS};
                        
                        if (cfg.parent.parent != null && cfg.parent.parent.tag == "g") 
                        {
                            tmp2 = cfg.parent.parent;
                        }
                        else
                        {
                            fast.insertParentCfg(tmp2, cfg.parent);
                        }

                        var prop = fast.getPropName();                                                
                        cfg.parent[cfg.parentProp] = null;
                        cfg.parent = tmp2;
                        cfg.parentProp = prop;
                        tmp2[prop] = cfg;
                    }
                }
                else
                {
                    if (cfg.tag != "svg") tmp = {tag : "svg", xmlns : fast.svgNS, width : "100%", height : "100%"};
                }
            }
            else
            {
                if (cfg.parent != null && fast.v[cfg.parent.tag] != null && cfg.parent.tag != "foreignObject")
                {
                    cfg.xmlns = fast.htmlNS;
                    var sp = cfg.parent.spacing;
                    
                    if (sp == null) sp = 0;
                    
                    var tmp2 = 
                    {   
                        tag     : "foreignObject", 
                        xmlns   : fast.svgNS, 
                        x       : fast.parseInt(cfg.parent.x, sp), 
                        y       : fast.parseInt(cfg.parent.y, sp),
                        width   : fast.parseInt(cfg.parent.width, - 2 * sp),
                        height  : fast.parseInt(cfg.parent.height, - 2 * sp)
                    };
                    
                    var par = cfg;
                    
                    while (par.parent != null && par.tag != "svg")
                    {
                        par = par.parent;
                    }
                    
                    fast.setParent(par, cfg);
                    
                    fast.insertParentCfg(tmp2, cfg);
                }
            }
                        
            if (tmp != null) fast.insertParentCfg(tmp, cfg);
        }
    
        if (fast.v[cfg.tag] != null)
        {
            if (cfg.tag == "ellipse")
            {
                fast.fx.ellipse(cfg);
            }
            else if (cfg.tag == "rect")
            {
                fast.fx.rect(cfg);
            }
        }
                
        for (var p in cfg)
        {
            if (cfg[p] != null && p != "parent")
            {
                if (cfg[p] instanceof Array) continue;
                
                if (typeof cfg[p] == "object" && cfg[p].tag != null)
                {   
                    cfg[p].parent     = cfg;
                    cfg[p].parentProp = p;
                    this.validate(cfg[p], true)
                }
//                else if (cfg[p] instanceof Array)
//                {
//                    cfg[p].parent     = cfg;
//                    cfg[p].parentProp = p;
//                    var svgCount = 0;
//                    
//                    for (var i = 0; i < cfg[p].length; ++i)
//                    {   
//                        var obj = cfg[p][i];
//                        
////                        if (fast.fx.mode == "svg")
////                        {
////                            if (fast.v[obj.tag] != null && i < cfg[p].length - 1)
////                            {
////                                svgCount++;
////                            }
////                            else
////                            {
////                                if (fast.v[obj.tag] != null && i == cfg[p].length - 1) svgCount++;
////                            
////                                if (svgCount > 1)
////                                {
////                                    var tmp = {tag : "svg", xmlns : fast.svgNS};
////                                    var n = i - 1;
////                                    var c = i - svgCount;
////                                                                        
////                                    for (var j = n; j > c; j--)
////                                    {
////                                        tmp[j] = cfg[p][j];
////                                        cfg[p][j] = null;
////                                    }
////                                    
////                                    cfg[p][n] = tmp;
////                                }
////                                
////                                svgCount = 0;
////                            }
////                        }
//                        
//                        if (typeof obj == "object" && obj.tag != null)
//                        {
//                            obj.parent     = cfg[p];
//                            obj.parentProp = i;
//                            this.validate(obj, true)
//                        }
//                    }
//                }
            }
        }
                
        if (root != true)
        {
            while (cfg.parent != null)
            {
                var p = cfg.parent;
                cfg.parent     = null;
                cfg.parentProp = null;
                cfg = p;
            }
        }

        cfg.parent     = null;
        cfg.parentProp = null;

        return cfg;
    },
    
    create : function(cfg, to, clear)
    {
        if (cfg != null && cfg.tag != null)
        {
            cfg = this.validate(cfg);
        }
        
        return this.createEx(cfg, to, clear);
    },
    
    createEx : function(cfg, to, clear)
    {   
        if (cfg == null)
        { 
            return;
        }
        else if (cfg instanceof Array)
        {
            var ar = new Array(cfg.length);
            
            for (var i = 0; i < cfg.length; ++i)
            {   
                cfg[i].parentProp = i;
                ar[i] = this.createEx(cfg[i]);
            }
            
            if (to != null) this.append(to, ar, clear);
            
            return ar;
        }
        else if (typeof cfg == "string")
        {
            return this.createEx({tag : "span", innerHTML : cfg}, to, clear);
        }
                
        var tag = cfg.tag;
        var obj = null;
        

        if (fast.e[cfg.tag] != null)
        {
            return fast.effect.create(cfg, to);
        }
                
        if (tag == "grid")
        {
            var grid = new fast.grid(cfg, to);
            return grid;
        }
        else
        {
            obj = fast.createElement(tag, null, cfg.xmlns);
            for (var p in cfg)
            {   
                var prop = cfg[p];
                
                if (prop == null || p == "parent" || p == "parentProp") continue;
                
                if (prop instanceof Array)
                {
                    this.createEx(prop, obj);
                }
                else if (typeof prop == "object")
                {
                    if (prop.tag != null)
                    {
                        this.createEx(prop, obj);
                    }
                    else if (obj[p] != null)
                    {   
                        this.setprops(prop, obj[p]);
                    }
                    else
                    {
                        fast.$set(obj, p, prop);
                    }
                }
                else if (p != "tag")
                {
                   fast.$set(obj, p, prop);
                }
            }
        }
        
        if (to != null) this.append(to, obj, clear);
        
        return obj;
    },
    
    setprops :  function(obj, to)
    {
        for (var p in obj)
        {
            if (obj[p] != null) fast.$set(to, p, obj[p]);
        };
    },
    
    setStyleProps :  function(obj, to)
    {
        for (var p in obj)
        {
            if (obj[p] != null) to.style[p] = obj[p];
        };
    },
    
    append : function(to, obj, clear)
    {
        if (to == null) return;
        to = fast.$(to);
        if (clear == true)to.innerHTML = "";
                
        if (obj instanceof Array)
        {
            for (var i = 0; i < obj.length; ++i)
            {
                if (obj[i] != null) this.append(to, obj[i], clear);
            }            
        }
        else
        {
            if (obj != null) to.appendChild(obj);
        }
    },
    
    remove : function(parent, obj)
    {
        parent.removeChild(obj);
    },
    
    findProp : function(obj, prop)
    {
        for (var p in obj)
        {
            if (obj[p] == prop) return p;
        };
        
        return null
    },
    
    getElementRectange : function(el)
    {
        var obj = this.getobj(el);
    	
        var w = obj.offsetWidth;
        var h = obj.offsetHeight;
    	
        var l = 0;
        var t = 0;
    	
        while (obj)
        {
            l += obj.offsetLeft;
            t += obj.offsetTop;
            obj = obj.offsetParent;
        }

        return {left:l, top:t, width: w, height:h};
    },
    
    message : function(mes)
    {
        alert(mes);
    },
    
    getRect : function(id)
    {
        var obj  = fast.$(id);
        
        var tmp =
        {
            left    : obj.offsetLeft + "px",
            top     : obj.offsetTop + "px",
            width   : obj.offsetWidth + "px",
            height  : obj.offsetHeight + "px"
        };
        
        return tmp;
    },
    
    delegate : function(func, arg)
    {
        var args = Array.prototype.slice.call(arguments);
        args.shift();
        
        if (typeof func == "string")
        {
            var str = func + "(";
            for (var i = 0; i < args.length; ++i)
            {
                if (typeof args[i] == "string")
                {
                    str += "\"" + args[i] + "\"";
                }
                else
                {
                    str += args[i];
                }
                
                if (i < args.length - 1) str += ",";
            } 
            str += ");"

            return function(){ eval(str); };
        }
        else
        {
            return function(){ func.apply(null, args); };
        }    
    },
    
    _id : 0,
    
    getPropName : function()
    {
        this._id++; return "obj" + this._id;
    },
    
    parseInt : function(val, sp)
    {
        if (typeof val == "string")
        {
            if (val.indexOf("%") != -1)
            {
                return val;
            }
            else
            {
                return parseInt(val) + sp;
            }
        }
        
        return val + sp;
    },
    
    parseRequest : function(data)
    {
        var spl = data.charAt(0);
        var str = data.split(spl);
        str.shift();
        
        return str;
    },
    
    parseRequestEx : function(data, cols)
    {
        if (typeof data == "string")
        {
            data = fast.parseRequest(data);
        }
        
        var ar = [];
        
        for (var i = 0; i < data.length; i += cols.length)
        {
            var obj = {};
            
            for (var j = 0; j < cols.length; ++j)
            {
                if (data[i + j] == "True" ) data[i + j] = true;
                if (data[i + j] == "False") data[i + j] = false;
                obj[cols[j]] = data[i + j];
            }
            
            ar.push(obj);
        }
        
        return ar;
    }
};

fast.event = 
{
    getInitPage : function(name, val)
    {
        return fast.initPage;
    }
};

fast.pages = {};

fast.images = 
{
    add : function(name, path)
    {
        this[name] = new Image();
        this[name].src = path;
    },
    put : function(name)
    {
        if (fast.isIE)
        {
            return function(){event.srcElement.src = fast.images[name].src;};
        }
        else
        {
            return function(event){event.target.src = fast.images[name].src;};
        }
    }
};