﻿
var Global =
{

host: "econera.com",

root: "/",

imgDir: "/img/",

aspNetPath: "a/",

userDir: "User/",

fullUserDir: null,

aspDir: null,

getAspDir: function()
{
    if (!$g.aspDir)
    {
        $g.aspDir = "http://" + $g.host + $g.root + $g.aspNetPath;
    }

    return $g.aspDir;
},

getFullUserDir: function()
{
    if (!$g.fullUserDir)
    {
        $g.fullUserDir = $g.getAspDir() + $g.userDir;
    }
    
    return $g.fullUserDir;
},

getUserUrl: function(userPage)
{
    if (!userPage) userPage = "home";

    var res = $g.getFullUserDir() + userPage + ".aspx";
    
    return res;
},

getImgUrl: function(img)
{
    var res = $g.imgDir + img;
    return res;
}

};

var $g = Global;
function StringTool()
{
}

StringTool.padIntWithZeroes = function(n, width)
{
    var pad = "000000000000000000000000000000";
    var s = n.toString();
    
    if (s.length < width)
    {
        s = pad.substring(0, width - s.length) + s;
    }
    
    return s;
}

StringTool.formatFloat = function(val, prec)
{
    // todo: support negative values
    
    var res;
    
    if (prec > 0)
    {
        var multi = MathTool.intPow(10, prec);
        var multiZeros = multi.toString().substr(1);
        
        res = (Math.round(val * multi) / multi).toString();
        
        // deal with '.'
        var dotPos = res.indexOf(".");
        if (dotPos == -1)
        {
            res += "." + multiZeros;
        }
        else
        {
            var fracLen = res.length - (dotPos + 1);
            res += multiZeros.substr(fracLen);
        }
    }
    else
    {
        res = Math.round(val).toString();
    }

    return res;
}

StringTool.format = function (formatString)
{
    var args = new Array();
    for (var i=1; i<arguments.length; i++)
    {
        args.push(arguments[i]);
    }
    
    var str = StringTool.formatArray(formatString, args);

    return str;
}

StringTool.formatArray = function(formatString, paramsArray)
{
    var str = formatString;
    var regexp = new RegExp("{([0-9])+(?::([0-9]+))?}", "g");
    var patterns = [];
    
    do
    {
        var res = regexp.exec(str);
        if ((res) && (res.length > 0))
        {
            var index = Number(res[1]);
            
            if (res[2])
            {
                var prec = res[2];
                var param = paramsArray[index].toString();
                param = param.formatFloat(prec);
                res.parameter = param;
            }
            else
            {
                res.parameter = paramsArray[index];
            }
            patterns.push(res);
        }
    }
    while (res != null)
    
    for (var i=0; i<patterns.length; i++)
    {
        var pattern = patterns[i];
        while(true)
        {
            var tmpStr = str.replace(pattern[0], pattern.parameter);
            if (tmpStr == str) break;
            str = tmpStr;
        }
    }
    
    return str;

}

// <String> class modifying

String.prototype.contains = function(s)
{
    return this.indexOf(s) >= 0;
}

String.prototype.startsWith = function(s, ignoreCase)
{   
    if (this.length < s.length) return false;
    
    var res;
    
    if (!ignoreCase)
    {
        res = this.substr(0, s.length) == s;
    }
    else
    {
        res = this.toLowerCase().substr(0, s.length) == s.toLowerCase();
    }
    
    return res;
}

String.prototype.endsWith = function(s, ignoreCase)
{
    var pos = this.length - s.length;
    var sub = this.substr(pos);
    var res;
    if (ignoreCase)
    {
        res = sub == s;
    }
    else
    {
        res = sub.toLowerCase() == s.toLowerCase();
    }
    
    return res;
}

String.prototype.trim = function()
{   
    var i;
    for (i = 0; i <= this.length; ++i)
    {
        if (i < this.length && this.charCodeAt(i) > 32) break;
    }
    
    if (i == this.length) return "";
    var beg = i;
    
    for (i = this.length - 1; i >= beg; --i)
    {
        if (this.charCodeAt(i) > 32) break;
    }
    var end = i;
    
    return this.substring(beg, end + 1);
}

String.prototype.htmlUnescape = function()
{
    var res = this;
    
    res = res.replace(/&nbsp;/gi, " ");
    res = res.replace(/&gt;/gi, ">");
    res = res.replace(/&lt;/gi, "<");
    res = res.replace(/&amp;/gi, "&");
    
    return res;
}

String.prototype.htmlEscape = function(escapeSpaces)
{
    var res = this;    
    res = res.replace(/&/gi, "&amp;");
    res = res.replace(/>/gi, "&gt;");
    res = res.replace(/</gi, "&lt;");
    if (escapeSpaces) res = res.replace(/ /gi, "&nbsp;");
    return res;
}

String.prototype.formatFloat = function(prec)
{
    return StringTool.formatFloat(this, prec);
}

// todo: buggy. will return false on valid floats like 1.2e-20
String.prototype.isFloat = function()
{
    var res = /^-?\d{1,20}(\.\d{1,20})?$/.test(this);
    return res;
}

String.prototype.isInt = function()
{
    var res = /^-?\d{1,10}$/.test(this);
    return res;
}

String.prototype.toInt = function()
{
    if (!this.isInt()) return null;
    return Number(this);
}

String.prototype.isEmail = function()
{
    var regexp = "^(?:[A-Za-z0-9_.]+)@(?:(?:[A-Za-z0-9_]+).)+[a-zA-Z]+$";
    var res = (this.match(regexp) != null);
    
    return res;
}

var _format = StringTool.format;
var UrlTool = {

PAGE_VERB_PARAM_NAME : "pageverb",

lastUserPageInfo : null,

parametrizeUrl : function(url, paramNames, paramValues)
{
    var res = url;
    
    do
    {
        if (!paramNames) break;
        
        var addedCount = 0;
        
        for (var i = 0; i < paramNames.length; ++i)
        {
            var name = paramNames[i];
            var val = paramValues[i];
            
            if (!name || !val || val == "") continue;
            
            res += (addedCount > 0) ? "&" : "?";            
            res += name + "=" + val;
                        
            ++addedCount;
        }
    }
    while(0);
    
    return res;
},

makeUserPageLink : function(userDirUrl, id, actionVerb, paramNames, paramValues)
{
    var res = null;
    
    do    
    {
        var g = Global;
    
        if (!userDirUrl) userDirUrl = StringTool.format(
             "http://{0}{1}{2}user/",
             g.host,
             g.root,
             g.aspNetPath);
    
        // form url (http://site.com/Foo.aspx)
        if (!id) break;
        res = userDirUrl + id + ".aspx";
        
        // params
        if (!paramNames) paramNames = [];
        if (!paramValues) paramValues = [];
        
        var allParamNames = paramNames.concat(UrlTool.PAGE_VERB_PARAM_NAME);            
        var allParamValues = paramValues.concat(actionVerb);

        res = UrlTool.parametrizeUrl(res, allParamNames, allParamValues);
    }    
    while(0);
    
    return res;
},

parseParams: function(paramsString)
{
    // delete <#>
    var sharpPos = paramsString.indexOf("#");
    
    if (sharpPos != -1)
    {
        paramsString = paramsString.substr(0, sharpPos);
    }

    var params = [];
    params.obj = {};
    
    do
    {
        if (!paramsString) break;
        
        var pairs = paramsString.split("&");
        if (!pairs) break;
        
        for (var i = 0; i < pairs.length; ++i)
        {
            var pair = pairs[i];
            if (!pair) continue;
            
            var tokens = pair.split("=");
            if (tokens && tokens[0] && tokens[1])
            {
                var p = {name: tokens[0], value: tokens[1]};
                params.push(p);
                params.obj[p.name] = p.value;
            }
        }
    }
    while(0);
    
    return params;
},

getRequestParams: function(url)
{
    if (!url) url = location.href;

    var params = [];
    params.obj = {};

    do
    {
        var beg = url.indexOf("?");
        if (beg < 0) break;
        
        paramStr = url.substr(beg + 1);
        if (!paramStr) break;
        
        params = UrlTool.parseParams(paramStr);
    }
    while(0);
    
    return params;
},

getUserPageInfo : function()
{
    var res = UrlTool.lastUserPageInfo;
    if (res) return res;
    
    var fullUrl = location.href;

    var questMarkPos = fullUrl.indexOf("?");
    if (questMarkPos < 0)
    {   
        var lastSlashPos = fullUrl.lastIndexOf("/");
        var dotPos = fullUrl.indexOf(".", lastSlashPos);
        var id = fullUrl.substring(lastSlashPos + 1, dotPos);
        
        res = {
            userDirUrl: fullUrl.substr(0, lastSlashPos + 1),
            id: id,
            actionVerb: ""
        };
    }
    else
    {
        var lastSlashPos = fullUrl.lastIndexOf("/");
        var dotPos = fullUrl.indexOf(".", lastSlashPos);
        var id = fullUrl.substring(lastSlashPos + 1, dotPos);
        
        var paramsStr = fullUrl.substr(questMarkPos + 1);
        var params = UrlTool.parseParams(paramsStr);
        
        var actionVerb = params.obj[UrlTool.PAGE_VERB_PARAM_NAME];
        
        res = {
            userDirUrl: fullUrl.substr(0, lastSlashPos + 1),
            id: id,
            actionVerb: actionVerb ? actionVerb : ""
        };
    }
    
    UrlTool.lastUserPageInfo = res;
    return res;
},

goUserPage : function(userDirUrl, id, actionVerb, paramNames, paramValues)
{
    var url = UrlTool.makeUserPageLink(userDirUrl, id, actionVerb, paramNames, paramValues);
    location.href = url;
},

makeCommonPageLink: function(id, actionVerb)
{
    var _g = Global;
    
    var url = _format("http://{0}{1}{2}{3}.aspx", _g.host, _g.root, _g.aspNetPath, id);
    
    if (actionVerb)
    {
        url += _format("?{0}={1}", UrlTool.PAGE_VERB_PARAM_NAME, actionVerb)
    }
    
    return url;
},

goCommonPage: function(id, actionVerb)
{
    var url = UrlTool.makeCommonPageLink(id, actionVerb).toLowerCase();
    location.href = url;
}

};


var DomTool =
{

/*** color ***/
isValidColor: function(col)
{
    try
    {
        var r1 = /^[0-9a-f]{3}$/i;
        var r2 = /^[0-9a-f]{6}$/i;
        
        return r1.test(col) || r2.test(col);
    }
    catch(ex)
    {
        return false;
    }
},

hexDigits: ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d", "e", "f"],

randomColor: function()
{
    var res = "";
    for (var i = 0; i < 6; ++i)
    {
        var idx = MathTool.intRandom(1000) % 16;
        res += DomTool.hexDigits[idx];
    }
    
    return res;
},

makeFullColor: function(col)
{
    var res = null;
    
    try
    {
        col = col.toString().toLowerCase();
        
        if (!DomTool.isValidColor(col)) throw 0;
        
        if (col.length == 3)
        {
            var col2 = "";
            for (var i = 0; i < 3; ++i)
            {
                var ch = col.charAt(i);
                col2 += "" + ch + ch;
            }
            
            col = col2;            
        }
        
        return col;
    }
    catch(ex)
    {
        return null;
    }
},

/*** misc ***/
clearSelection: function()
{
    if(document.selection && document.selection.empty)
    {
        document.selection.empty();
    }
    else if(window.getSelection)
    {
        var sel = window.getSelection();
        if (sel && sel.removeAllRanges) sel.removeAllRanges();
    }
},

assignProps: function(el, obj)
{
    var childs = el.childNodes;
    if (!childs) return;
    for (var i = 0; i < childs.length; ++i)
    {
        var chld = childs[i];
        if (chld.nodeType != 1) continue; // not an ELEMENT
        
        var id = chld.id;        
        if (id) obj[id.toString()] = chld;
        chld._obj = obj;
        
        DomTool.assignProps(chld, obj);
    }
},

assignGlobalProps: function(el)
{
    if (!el) el = DomTool.getBody();
    
    var childs = el.childNodes;
    for (var i = 0; i < childs.length; ++i)
    {
        var ch = childs[i];
        if (ch.nodeType != 1) continue;
        
        var id = ch.id;
        
        if (id)
        {
            if (id.startsWith("g_"))
            {
                window[id] = ch;
            }
        }

        DomTool.assignGlobalProps(ch);
    }    
},

/*** Coordinates & Sizes ***/
pxToEmRatio: null, // 1px = ?em
emToPxRatio: null, // 1em = ?px

pxToEm: function(px, addSuffix)
{
    var res = px * DomTool.getPxToEmRatio();
    res = Math.floor(res * 10000) / 10000;
    if (addSuffix) res += "em";
    return res;
},

emToPx: function(em, addSuffix)
{
    var res = em * DomTool.getEmToPxRatio();
    res = Math.floor(res * 10000) / 10000;
    if (addSuffix) res += "px";
    return res;
},

emAddPx: function(em, dpx, addSuffix)
{
    var px = DomTool.emToPx(em);
    px += dpx;
    return DomTool.pxToEm(px, addSuffix);
},

getPxToEmRatio: function()
{
    if (DomTool.pxToEmRatio) return DomTool.pxToEmRatio;
    DomTool.retrieveRatios();
    return DomTool.pxToEmRatio;
},

getEmToPxRatio: function()
{
    if (DomTool.emToPxRatio) return DomTool.emToPxRatio;
    DomTool.retrieveRatios();
    return DomTool.emToPxRatio;
},

retrieveRatios: function()
{
    var d = DomTool.makeDiv(null, null);
    with (d.style)
    {
        position = "absolute";
        width = "1000em";
        height = "1em";
        left = "0em";
        top = "0em";
    }
    DomTool.getBody().appendChild(d);
    var r = DomTool.getRect(d);
    DomTool.getBody().removeChild(d);
    
    DomTool.pxToEmRatio = 1000 / r.w;
    DomTool.emToPxRatio = r.w / 1000;
},

inRect: function (pt, rect)
{
    var res =
        pt.x >= rect.x1 && 
        pt.x <= rect.x2 &&
        pt.y >= rect.y1 &&
        pt.y <= rect.y2;
        
    return res;
},

getCoords: function(elem)
{
    if(typeof(elem.offsetParent) != 'undefined')
    {
        for(var posX = 0, posY = 0; elem; elem = elem.offsetParent)
        {
            posX += elem.offsetLeft;
            posY += elem.offsetTop;
        }
        
        return {x: posX, y: posY};
    }
    else
    {
        return {x: elem.x, y: elem.y};
    }
},

getSizes: function(elem)
{
    var width = elem.offsetWidth;
    var height = elem.offsetHeight;
    
    return {w: width, h: height};
},

makeBar: function(x1, y1, w, h, suffix)
{
    var x2 = x1 + w;
    var y2 = y1 + h;
    return DomTool.makeRect(x1, y1, x2, y2, suffix);
},

makeRect: function(x1, y1, x2, y2, suffix)
{
    var s = suffix ? suffix : "";

    var xr2 = Math.max(x1, x2);
    var xr1 = Math.min(x1, x2);
    
    var yr2 = Math.max(y1, y2);
    var yr1 = Math.min(y1, y2);
    
    var res = 
    {
        x1: xr1 + s,
        y1: yr1 + s,
        x2: xr2 + s,
        y2: yr2 + s,
        w: (xr2 - xr1) + s,
        h: (yr2 - yr1) + s
    };
    
    return res;
},

ofsRect: function(r, dx, dy)
{
    r.x1 += dx;
    r.x2 += dx;
    r.y1 += dy;
    r.y2 += dy;
},

getRect: function(elem)
{
    var pos = DomTool.getCoords(elem);
    var sizes = DomTool.getSizes(elem);
    
    var res = {
        x1: pos.x,
        y1: pos.y,
        x2: pos.x + sizes.w,
        y2: pos.y + sizes.h,
        w: sizes.w,
        h: sizes.h};
        
    return res;
},

getRectById: function(id)
{
    return DomTool.getRect(DomTool.getElem(id));
},

moveElem: function(elem, x, y)
{
    if (x || x === 0)
    {
        var xs = "" + x;
        if (xs.isInt()) xs += "px";
        elem.style.left = xs;
    }
    
    if (y || y === 0)
    {
        var ys = "" + y;
        if (ys.isInt()) ys += "px";
        elem.style.top = ys;
    }
},

resizeElem: function(elem, w, h)
{
    if (w)
    {
        var ws = "" + w;
        if (ws.isInt()) ws += "px";
        try
        {
            elem.style.width = ws;
        }
        catch(ex1)
        {
        }
    }
    
    if (h)
    {
        var hs = "" + h;
        if (hs.isInt()) hs += "px";        
        try
        {
            elem.style.height = hs;
        }
        catch(ex2)
        {
        }
    }
},

getClient: function()
{
    var w = document.compatMode=='CSS1Compat' && !window.opera?document.documentElement.clientWidth:document.body.clientWidth;
    var h = document.compatMode=='CSS1Compat' && !window.opera?document.documentElement.clientHeight:document.body.clientHeight;
    
    return {w: w, h: h};
},

/*** Mouse ***/

getMouse: function(e)
{
    var xm = -1488;
    var ym = -1488;
    var okm = false;

    if (e)
    {
        xm = e.pageX;
        ym = e.pageY;
        okm = true;
    }
    else if (window.event)
    {
        xm = event.x;
        ym = event.y;
        okm = true;
    }
    
    return {ok: okm, x: xm, y: ym};
},

mouseInRect: function(e, rect)
{
    var m = DomTool.getMouse(e);
    return DomTool.inRect(m, rect);
},

mouseOver: function(e, elem)
{
    return DomTool.mouseInRect(e, DomTool.getRect(elem));
},

mouseOverId: function(e, id)
{
    return DomTool.mouseInRect(e, DomTool.getRect(DomTool.getElem(id)));
},

/*** DOM elements ***/

// DOM elements getters

testChild: function(chld, par)
{
    var testPar = chld.parentNode;
    while (1)    
    {
        if (!testPar) return false;
        if (testPar == par) return true;
        
        testPar = testPar.parentNode;
    }
},

getGrandParent: function(elem, depth)
{
    var curr = elem;
    
    for (var i = 0; i < depth; ++i)
    {
        curr = curr.parentNode;
    }
    
    return curr;
},

getElem: function(id)
{
    var elem = document.getElementById(id);
    return elem;
},

getTbody: function(tableId)
{
    return DomTool.getElem(tableId).tBodies[0];
},

docBody: null,
getBody: function()
{
    if (!DomTool.docBody)
    {
        DomTool.docBody = document.getElementsByTagName("body")[0];
    }
    
    return DomTool.docBody;
},

// DOM nodes makers

makeText: function(txt)
{
    var node = document.createTextNode(txt);
    return node;
},

addText: function(par, txt)
{
    return par.appendChild(DomTool.makeText(txt));
},

makeElem: function(tag, htm, css)
{
    var elem = document.createElement(tag);
    if (css) elem.className = css;
    if (htm || htm === 0) elem.innerHTML = htm;

    return elem;
},

makeDiv: function(htm, css)
{
    return DomTool.makeElem("div", htm, css);
},

makeSpan: function(htm, css)
{
    return DomTool.makeElem("span", htm, css);
},

makeImg: function(src, css)
{
    var img = DomTool.makeElem("img", null, css);
    img.src = src;
    return img;
},

// DOM elements adders

clearFloat: function(par)
{
    var clr = DomTool.addDiv(par);
    clr.style.clear = "both";
},

clearFloatSpan: function(par)
{
    var clr = DomTool.addSpan(par);
    clr.style.display = "block";
    clr.style.clear = "both";
},

addElem: function(par, tag, htm, css)
{
    var elem = DomTool.makeElem(tag, htm, css);
    if (par) par.appendChild(elem);
    
    return elem;
},

addDiv: function(par, htm, css)
{
    return DomTool.addElem(par, "div", htm, css);
},

addSpan: function(par, htm, css)
{
    return DomTool.addElem(par, "span", htm, css);
},

addTable: function(par, css, noTBody)
{
    var tab = DomTool.addElem(par, "table", null, css);
    if (!noTBody)
    {
        var tbody = DomTool.addTBody(tab);
        tab._tbody = tbody;
    }
    return tab;
},

addA: function(par, href, htm, css)
{
    var a = DomTool.addElem(par, "a", htm, css);
    if (href) a.href = href;
    return a;
},

addImg: function(par, src, css)
{
    var img = DomTool.addElem(par, "img", null, css);
    if (src) img.src = src;
    return img;
},

addInput: function(par, type, val, css)
{   
    var inp = DomTool.makeElem("input", null, css);
    inp.type = type;
    if (val) inp.value = val;
    if (par) par.appendChild(inp);
    
    return inp;
},

addButton: function(parent, val, css, onclick)
{
    var but = DomTool.addInput(parent, "button", val, css);    
    but.onclick = onclick ? onclick : null;
    return but;
},

addEdit: function(parent, val, css)
{
    return DomTool.addInput(parent, "text", val, css);
},

addCheck: function(par, checked, id, labelText, checkCss, labelCss)
{
    var ch = DomTool.addInput(par, "checkbox", null, checkCss);
    if (checked) ch.checked = "checked";
    if (id) ch.id = id;
    if (labelText) DomTool.addLabel(par, ch, labelText, labelCss);
    return ch;
},

addRadio: function(par, checked, id, name, labelText, radioCss, labelCss)
{
    var ra = DomTool.addInput(par, "radio", null, radioCss);
    if (checked) ra.checked = "checked";
    if (id) ra.id = id;
    if (name) ra.name = name;
    if (labelText) DomTool.addLabel(par, ra, labelText, labelCss);
    return ra;
},

addLabel: function(par, forElem, htm, css)
{
    var lbl = DomTool.addElem(par, "label", htm, css);
    if (forElem && forElem.id) lbl.htmlFor = forElem.id;
    return lbl;
},

addSelect: function(par, css)
{
    return DomTool.addElem(par, "select", null, css);
},

// adding to known parent
addElemWithCheck: function(par, parTag, tag, htm, css)
{
    if (par.tagName.toLowerCase() != parTag.toLowerCase()) return null;
    return DomTool.addElem(par, tag, htm, css);
},

addTBody: function(parentTable)
{
    return DomTool.addElemWithCheck(parentTable, "table", "tbody");
},

addTr: function(parentTbody, css)
{
    return DomTool.addElemWithCheck(parentTbody, "tbody", "tr", null, css);
},

addTd: function(parentTr, htm, css, ignoreEmpty)
{
    if (!htm && !(htm === 0) && !ignoreEmpty) htm = "&nbsp;";
    var td = DomTool.addElemWithCheck(parentTr, "tr", "td", htm, css);
    
    return td;
},

addOption: function(parentSelect, htm, css, ignoreEmpty)
{
    if (!htm && !(htm === 0) && !ignoreEmpty) htm = "&nbsp;";
    var opt = DomTool.addElemWithCheck(parentSelect, "select", "option", htm, css);
    
    return opt;
},

addOptionEx: function(parentSelect, htm, val, css, ignoreEmpty)
{
    if (!htm && !(htm === 0) && !ignoreEmpty) htm = "&nbsp;";
    var opt = DomTool.addElemWithCheck(parentSelect, "select", "option", htm, css);
    opt.value = val;
    opt.name = val;
    
    return opt;
},

/*** html ***/
makeImgHtm: function(img, style)
{
    if (!style) style = "";
    var htm = StringTool.format("<img src='{0}' style='{1}'/>", Global.getImgUrl(img), style);
    return htm;
}

};

var JsonTool = 
{
copyArgs : function(argsObj, start)
{
    var res = [];
    
    for (var i = start; i < argsObj.length; ++i) res.push(argsObj[i]);
    
    return res;
},

each : function(arr, func /*, arg1, ... , argN */)
{
    var args = JsonTool.copyArgs(arguments, 2);
    
    for (var i = 0; i < arr.length; ++i)
    {
        func.apply(arr[i], args);
    }
},

each_expr: function(arr, expr)
{
    for (var i = 0; i < arr.length; ++i)
    {
        var instance = arr[i];
        eval(expr);
    }
},

first : function(arr, pred)
{
    var args = JsonTool.copyArgs(arguments, 2);
    args.unshift(1488);
    
    for (var i = 0; i < arr.length; ++i)
    {
        args[0] = arr[i];
    
        if (pred.apply(this, args)) return arr[i];
    }
},

propMatcher: function(obj, propName, propVal)
{
    return obj[propName] == propVal;
},

firstProp: function(arr, propName, propVal)
{
    return JsonTool.first(arr, JsonTool.propMatcher, propName, propVal);
}

};
var EvTool = 
{

truer: function()
{
    return true;    
},

falser: function()
{
    return false;
},

nuller: function()
{
    return null;
},

dummy: function()
{
},

getEvObj: function(e)
{
    if (!e) e = window.event;
    return e;
},

focusLater: function(el, select, timeout)
{
    try
    {
        if (!timeout) timeout = 50;
        EvTool.tmpEl = el;
        setTimeout("try{EvTool.tmpEl.focus()}catch(ex){}", timeout);
        if (select) el.select();
    }
    catch (ex)
    {
    }
},

applyMethodLater: function(obj, method, args, timeout)
{
    try
    {
        if (!timeout) timeout = 50;
        if (!args) args = [];
        
        EvTool.tmpObj = obj;
        EvTool.tmpMethod = method;
        EvTool.tmpArgs = args;
        
        setTimeout("EvTool.tmpMethod.apply(EvTool.tmpObj, EvTool.tmpArgs)", timeout);
    }
    catch (ex)
    {
    }
},

getKey: function(e)
{
    var key = null;
    
    if (e = EvTool.getEvObj(e))
    {
        if (e.keyCode) key = e.keyCode;
        else if (e.which) key = e.which;
    }
    
    return key;
},

docPropStacks: [],

// backup <document> handler
// type: <document> handler type ("onclick", "onmouseup", etc)
// (val === newHandler): new <document> handler of type <type>
backupDocProp: function(name, val)
{
    var ps = EvTool.docPropStacks;
    if (!ps[name]) ps[name] = [];
    
    var stack = ps[name];
    
    stack.push(document[name]);
    document[name] = val;
},

restoreDocProp: function(name)
{
    var val = EvTool.docPropStacks[name].pop();
    document[name] = val ? val : null;
    
    return val;
},

testDocProp: function(name)
{
    var stk = EvTool.docPropStacks[name];
    var val = stk[stk.length - 1];
    
    return val;
}

   
};

var XmlTool = 
{

ELEMENT_NODE: 1,

getSingleChildElem: function(elem, childElemTag, ignoreCase)
{
    var res = null;
    var tag2 = childElemTag;
    if (ignoreCase)
    {
        tag2 = childElemTag.toLowerCase();
    }
    
    do
    {
        var chlds = elem.childNodes;
        if (!chlds) break;
        
        for (var i = 0; i < chlds.length; ++i)
        {
            var ch = chlds[i];
            
            if (ch.nodeType != 1) continue;
            
            var nameEq = ignoreCase ? (ch.tagName.toLowerCase() == tag2) : (ch.tagName == childElemTag);
            
            if (nameEq)
            {
                res = ch;
                break;
            }
        }
    }
    while(0);
    
    return res;
},

getChildElems: function(elem, childElemTag, ignoreCase)
{
    var res = [];
    var tag2 = childElemTag;
    if (ignoreCase)
    {
        tag2 = childElemTag.toLowerCase();
    }
    
    do
    {
        var chlds = elem.childNodes;
        
        if (!chlds) break;

        for (var i = 0; i < chlds.length; ++i)
        {
            var ch = chlds[i];            
            if (ch.nodeType != 1) continue;
            
            var nameEq = ignoreCase ? (ch.tagName.toLowerCase() == tag2) : (ch.tagName == childElemTag);
            
            if (nameEq)
            {
                res.push(ch);
            }
        }
    }
    while(0);
    
    return res;
},

createDocument: function()
{
    var doc = null;
    
    if (document.implementation && document.implementation.createDocument)
    {
        doc = document.implementation.createDocument("", "", null);
    }
    else if (typeof ActiveXObject != "undefined")
    {
        var msXmlDoc = null;
        try
        {
            msXmlDoc = new ActiveXObject("Msxml2.DOMDocument");
        }
        catch(e)
        {
            msXmlDoc = new ActiveXObject("Msxml.DOMDocument");
        }
        
        doc = msXmlDoc;
    }

    return doc;
},

addObjAttrs: function(el, obj)
{
    for (var k in obj) el.setAttribute(k, obj[k]);
},

attrsAsObj: function(el)
{
    var res = {};
    
    var attrs = el.attributes;
    
    for (var i = 0; i < attrs.length; ++i)
    {
        var a = attrs[i];
        res[a.nodeName] = a.nodeValue;
    }
    
    return res;
}

};
function AjaxException(elem)
{
    this.id = elem.getAttribute("Id");
    this.message = elem.getAttribute("Message");
    
    // props
    this.props = [];
    this.namedProps = [];
    
    var propsElem = XmlTool.getSingleChildElem(elem, "Props");
    if (propsElem)
    {
        var propElems = XmlTool.getChildElems(propsElem, "Prop");
        
        for (var i = 0; i < propElems.length; ++i)
        {
            var propElem = propElems[i];
            
            var name = propElem.getAttribute("Name");
            var val = propElem.getAttribute("Value");
            
            var prop = {name: name, value: val};
            this.props.push(prop);
            
            this.namedProps[name] = val;
        }
    }
    
    // inner
    var inner = null;
    var innerExElem = XmlTool.getSingleChildElem(elem, "InnerException");
    if (innerExElem)
    {
        inner = new AjaxException(innerExElem);
    }
    
    this.innerException = inner;
}

// id - числовой идентификатор (int).
// reqType - "GET" или "POST"
// verb - действие (например: "deleteFoo", "submitFoo"
// paramNames - иассив имен параметров. Пример: ["fooId", "gooId"]. Может быть null
// handler - функция - обработчик ответа сервера

function AjaxAction(id, reqType, verb, paramNames, handler, isExtended)
{
    this.id = id;
    this.reqType = reqType.toLowerCase() == "get" ? "GET" : "POST";
    this.verb = verb;
    this.paramNames = paramNames;
    this.handler = handler;
    
    this.isExtended = isExtended;
    
    this.listener = this.isExtended ? AjaxAction.makeListenerEx(this.id) : AjaxAction.makeListener(this.id);
    
}

AjaxAction.url = Global.root + Global.aspNetPath + "DoAjaxAction.ashx";
AjaxAction.verbParam = "jacverb";
AjaxAction.actions = [];
AjaxAction.actionsInProgress = 0;

// executes AJAX request and returns the <XMLHttpRequest> object has been created
AjaxAction.prototype.exec = function(params, doc)
{
    //_trace(this.verb);
    
    AjaxAction.beforeExec();
    

    if (!this.inProgress)
    {
        AjaxAction.actionsInProgress++;
        this.inProgress = true;
        AjaxAction.onActionsInProgressChange();
    }
    
    var ajx = this;

    ajx.reqObj = AjaxAction.createXmlHttp();
    ajx.reqObj.onreadystatechange = ajx.listener;

    var url = AjaxAction.url + "?" + AjaxAction.verbParam + "=" + ajx.verb;
    
    var paramString = null;
    
    if (ajx.paramNames && params && ajx.paramNames.length == params.length)
    {
        paramString = "";
        var len = ajx.paramNames.length;
        
        for (var i = 0; i < len; ++i)
        {
            var parVal = params[i];
            if (!parVal) parVal = "";
            
            paramString += "&" + ajx.paramNames[i] + "=" + parVal;
        }
    }
    
    if (paramString)
    {
        url += paramString;
    }
    
    var req = ajx.reqObj;
    
    req.open(ajx.reqType, url);
    
    if (doc)
    {
        req.setRequestHeader("Content-Type", "text/xml");
        req.send(doc);
    }
    else
    {
        req.send(null);
    }
    
    return req;
}

AjaxAction.getResponseInfo = function(doc)
{
    var resElem = doc.getElementsByTagName("Result")[0];
    var statusVal = resElem.getAttribute("Status");
    
    var ex = null;
    
    var exEl = XmlTool.getSingleChildElem(resElem, "Exception");
    if (exEl) ex = new AjaxException(exEl);
    
    var res = 
    {
        dataElem: doc.getElementsByTagName("Data")[0],
        status: statusVal,
        ok: statusVal == "OK",
        message: resElem.getAttribute("Message"),
        exception: ex
    };
    
    return res;
}

AjaxAction.beforeExec = function()
{
}

AjaxAction.preprocessResponse = function(doc)
{
}

AjaxAction.makeListener = function(id)
{
    var code = 
    "var f = function() \n" +
    "{ \n" +
    "    var ajx = AjaxAction.actions['" + id + "']; \n" +
    "    var req = ajx.reqObj; \n" +
    "    if (req.readyState == 4) \n" +
    "    { \n" +
    "        ajx.inProgress = false; \n" +
    "        AjaxAction.actionsInProgress--; \n" +
    "        AjaxAction.onActionsInProgressChange(); \n" +
    "        if (ajx.traceResponse) _trace(req.responseText); \n" +
    "        var doc = req.responseXML; \n" +
    "        if (doc) \n" +
    "        { \n" +
    "            var ok = AjaxAction.preprocessResponse(doc); \n" +
    "            var dataElem = null; try{ dataElem = AjaxAction.getResponseInfo(doc).dataElem; }catch(ex){} \n" +
    "            ajx.handler(doc, ok, dataElem); \n" +
    "            req.abort(); \n" + 
    "        } \n" +
    "    } \n" +
    "} \n";

    eval(code);
    
    return f;
}

AjaxAction.makeListenerEx = function(id)
{
    var code = 
    "var f = function() \n" +
    "{ \n" +
    "    var ajx = AjaxAction.actions['" + id + "']; \n" +
    "    var req = ajx.reqObj; \n" +
    "    if (req.readyState == 4) \n" +
    "    { \n" +
    "        ajx.inProgress = false; \n" +
    "        AjaxAction.actionsInProgress--; \n" +
    "        AjaxAction.onActionsInProgressChange(); \n" +
    "        if (ajx.traceResponse) _trace(req.responseText); \n" +
    "        var doc = req.responseXML; \n" +
    "        if (doc) \n" +
    "        { \n" +
    "            var ok = AjaxAction.preprocessResponse(doc); \n" +
    "            var dataElem = null; \n" +
    "            try \n" +
    "            { \n" +
    "               var info = AjaxAction.getResponseInfo(doc); \n" +
    "               dataElem = info.dataElem; \n" +
    "               ex = info.exception; \n" +
    "            } \n" +
    "            catch(dummy_ex) \n" +
    "            { \n" +
    "            } \n" +
    "            ajx.handler(doc, ok, dataElem, ex); \n" +
    "            req.abort(); \n" + 
    "        } \n" +
    "    } \n" +
    "} \n";

    eval(code);
    
    return f;
}

AjaxAction.createXmlHttp = function()
{
    var xReq = null;
    
    if (window.XMLHttpRequest)
    {
        xReq = new XMLHttpRequest();
    }
    else if (window.ActiveXObject)
    {
        xReq = new ActiveXObject("Microsoft.XMLHTTP");        
    }
    
    return xReq;
}

AjaxAction.register = function(id, reqType, action, paramName, handler)
{
    var ajx = new AjaxAction(id, reqType, action, paramName, handler, false);
    AjaxAction.actions[id] = ajx;
}

AjaxAction.registerEx = function(action, reqType, paramNames, handler)
{
    var ajx = new AjaxAction(action, reqType, action, paramNames, handler, true);
    AjaxAction.actions[action] = ajx;
}

AjaxAction.createRequestXmlObj = function()
{
    var doc = XmlTool.createDocument();
    var docElem = doc.createElement("Request");
    doc.appendChild(docElem);
    
    var dataElem = doc.createElement("Data");
    docElem.appendChild(dataElem);
    
    return {doc: doc, dataElem: dataElem};
}

AjaxAction.onActionsInProgressChange = function()
{
    // todo[ank]
    //_trace(AjaxAction.actionsInProgress);
}

var CommonPage =
{

msgTimer: null,
msgTimerDir: null,

killMsgTimer: function()
{
    if ($cp.msgTimer)
    {
        try
        {
            clearInterval($cp.msgTimer);
            $cp.msgTimer = null;
            $cp.msgTimerDir = null;
        }
        catch(e)
        {
        }
    }
},

initMsgTimer: function(dy)
{
    $cp.killMsgTimer();
    if (!dy) return;
    dy = dy > 0 ? 1 : -1;
    
    var ms = 1;
    
    $cp.msgTimerDir = dy;
    $cp.msgTimer = setInterval($cp.progressMsg, ms);
},

progressMsg: function()
{
    var dir = $cp.msgTimerDir;
    if (!dir) return;    
    var el = DomTool.getElem("TBC_wndMsg");
    
    var dx = 1;
    var h = 24;
    
    var top = el.style.top;
    if (!top) top = "0px";
    top = parseInt(top);
    
    if (dir > 0)
    {
        if (top >= 0)
        {
            el.style.top = "0px";
            $cp.killMsgTimer();
            return;
        }
        
        top+=dx;
        el.style.top = top + "px";
    }
    else
    {
        if (top <= -h)
        {
            el.style.top = (-h) + "px";
            $cp.killMsgTimer();
            return;
        }
        
        top-=dx;
        el.style.top = top + "px";
    }
},

// 'msg' - message to display
// 'sev' [severity] - "ERR", "INF" (error, warning or info, respectively)
showMsg: function(msg, sev)
{
    var d = DomTool.getElem("TBC_wndMsg");
    d.className = "TBC_wndMsg_" + sev;
    
    var d2 = DomTool.getElem("TBC_wndMsgText");
    d2.innerHTML = msg;

    $cp.initMsgTimer(-1);
},

showCap: function()
{
    $cp.initMsgTimer(+1);
},

initAjax: function()
{
    AjaxAction.beforeExec = $cp.showCap;
    AjaxAction.preprocessResponse = $cp.preprocessAjaxResponse;
},
   
preprocessAjaxResponse: function(doc)
{
    try
    {
        var info = AjaxAction.getResponseInfo(doc);
        if (!info.ok)
        {
            $cp.showMsg(info.message, "ERR");
            return false;
        }
        
        $cp.showCap();
        return true;
    }
    catch(e)
    {
        $cp.showMsg("Неизвестная ошибка", "ERR");
        return false;
    }
},

initTrace: function(){},

getLoginAjaxAction: function()
{  
    if (!AjaxAction.actions["login"])
    {
        $cp.initAjax();
        AjaxAction.registerEx("login", "POST", null, $cp.onAjaxLogin);
    }
    
    return AjaxAction.actions["login"];
},

onHdrLoginFocus: function()
{
    var l = g_TBC_login;
    if (l.value == $cp.emptyLogin) l.value = "";
    l.style.color = "#000";
},

onHdrLoginBlur: function()
{
    var l = g_TBC_login;
    if (l.value == "")
    {
        l.style.color = "#aaa";
        l.value = $cp.emptyLogin;
    }
},

onHdrLoginKeyDown: function(e)
{   
    var k = EvTool.getKey(e);
    if (k == 13) EvTool.focusLater(g_TBC_password, true);
},

onHdrPasswordFocus: function()
{
    var p = g_TBC_password;
    p.style.color = "#000";
    
    if (p.value == $cp.emptyPassword) p.value = "";
},

onHdrPasswordKeyDown: function(e)
{
    var k = EvTool.getKey(e);
    if (k == 13) $cp.doLogin();
},

emptyLogin: "Логин или e-mail",

emptyPassword: "эмпти",

placeToRedirectOnLogin: null,

doLogin: function()
{
    var l = g_TBC_login;
    var p = g_TBC_password;
    var b = g_TBC_doLogin;
    var r = $cp.placeToRedirectOnLogin;
    
    JsonTool.each_expr([l, p, b], "instance.disabled = true");

    var ajx = $cp.getLoginAjaxAction();
    var xmlObj = AjaxAction.createRequestXmlObj();
    xmlObj.dataElem.setAttribute("Login", l.value);
    xmlObj.dataElem.setAttribute("Password", p.value);
    
    if (r)
    {
        xmlObj.dataElem.setAttribute("PlaceToRedirectOnLogin", r);
    }
    
    ajx.exec(null, xmlObj.doc);
},

onAjaxLogin: function(doc, ok, dataElem, ex)
{
    var l = g_TBC_login;
    var p = g_TBC_password;
    var b = g_TBC_doLogin;
    
    if (ex)
    {
        switch(ex.id)
        {
        case "REGISTRATION_NOT_CONFIRMED":
            UrlTool.goCommonPage("registrationconfirmation");
            return;
            
        case "USER_AUTHENTICATION_FAILURE":
            UrlTool.goCommonPage("login", "retry");
            return;
            
        default:
            alert("Ошибка: " +  ex.message);
            
            p.value = "";        
            break;
        }
    
        JsonTool.each_expr([l, p, b], "instance.disabled = false");
        p.focus();
    }
    else
    {
        var urlToRedirect = dataElem.getAttribute("UrlToRedirect");
        
        if (urlToRedirect)
        {
            location.href = urlToRedirect;
        }
        else
        {
            location.href = Global.getUserUrl();
        }
    }
},

onLoaded: function()
{
    DomTool.assignGlobalProps();
    $cp.initTrace();
    $cp.initAjax();
    
    var l = window.g_TBC_login;
    var p = window.g_TBC_password;
    var b = window.g_TBC_doLogin;
    
    if (l && p && b)
    {
        l.value = $cp.emptyLogin;
        p.value = $cp.emptyPassword;
        
        JsonTool.each_expr([l, p, b], "instance.disabled = false");
    }
},


_dummy: 0
   
};

var $cp = CommonPage;

var $_dF = function(){};

window._trace = $_dF;
window._tracef = $_dF;
window._tracen = $_dF;
window._traceo = $_dF;
window._assert = $_dF;

/* Ajax actions */

function getAjaxAction(id)
{
    if (!(AjaxAction.actions[id]))
    {   
        AjaxAction.registerEx("checkregfield", "GET", ["fieldname", "value"], onAjaxFieldChecked);
    }
    
    return AjaxAction.actions[id];
}

function onAjaxFieldChecked(doc, ok, dataElem)
{
    if (!ok) return;

    var fieldName = dataElem.getAttribute("FieldName");
    var value = dataElem.getAttribute("Value");
    var exists = dataElem.getAttribute("Exists") == "1";
    var res = ok;
    
    switch (fieldName)
    {
    case "login":
        if (value == g_textBoxLogin.value)
        {
            if (exists)
            {
                showStatus("Login", false, "Этот логин уже занят");
            }
            else
            {
                showStatus("Login", true);
            }
        }
        
        break;
        
    case "email":
        if (value == g_textBoxEmail.value)
        {
            if (exists)
            {
                showStatus("Email", false, "Этот e-mail уже используется");
            }
            else
            {
                if (value.isEmail)
                {
                    showStatus("Email", true);
                }
                else
                {
                    showStatus("Email", null);
                }
            }
        }
    
        break;
    }
}

/*** Routines ***/
// Entry JS point
function onPageLoaded()
{
    CommonPage.onLoaded();
    g_textBoxLogin.focus();
}

function checkLogin()
{
    var str = g_textBoxLogin.value;
    var regexp = "^[A-Za-z0-9_]+$";
    var res = (str.match(regexp) != null);
    
    if (res)
    {
        var ajx = getAjaxAction("checkregfield");
        ajx.exec(["login", str]);    
    }
    else
    {   
        if (str == "")
        {
            showStatus("Login", null);
        }
        else
        {
            showStatus("Login", false, "Используйте символы «a»&ndash;«z», «0»&ndash;«9», «_».");
        }
    }
    
    return res;
}

function checkPassword()
{
    var str = g_textBoxPassword.value;    
    var res = ((str.length >= 6));
    
    if (str == "")
    {
        showStatus("Pwd1", null);
    }
    else if (res)
    {
        showStatus("Pwd1", true);
    }
    else
    {
        showStatus("Pwd1", false, "Слишком короткий пароль");
    }
}

function checkEmail()
{
    var str = g_textBoxEmail.value;
    var regexp = "^(?:[A-Za-z0-9_.]+)@(?:(?:[A-Za-z0-9_]+).)+[a-zA-Z]+$";
    var res = (str.match(regexp) != null);
    
    if (res)
    {
        var ajx = getAjaxAction("checkregfield");
        ajx.exec(["email", str]);
    }
    else
    {
        showStatus("Email", null);
    }
    
    return res;
}

function showStatus(name, state, msg)
{
    var img = window["g_imgStatus" + name];
    var span = window["g_spanStatus" + name];
    
    img.src = Global.getImgUrl("pixel.gif");
    span.innerHTML = "";
    
    if (state === null)
    {
        return;
    }
    else if (state === true)
    {
        img.src = Global.getImgUrl("check.gif");
    }
    else if (state === false)
    {
        img.src = Global.getImgUrl("cross.gif");
        
        span.style.color = "red";
        span.innerHTML = msg;
    }
}

function refreshCaptcha()
{
    g_captchaImage.src = Global.getAspDir() + "GetCaptcha.ashx?p=" + Math.random() + Math.random();
}