// Расширение функциональности массивов
function arrUnion(array1, array2, callback) {
    if ( 'function' != typeof callback )
        callback = function(value1, value2) {
            return value1 != value2;
        }
    for (var i = 0; i < array2.length; i++) {
        var j = 0;
        var u = true;
        while ( j < array1.length ) {
            u = callback(array1[j], array2[i]);
            if ( ! u )
                break;
            j++;
        }
        if ( ! u )
            continue;
        array1[array1.length] = array2[i];
    }
    return array1;
}

function byId(node) {
    return typeof node == 'string' || typeof node == 'number' ? document.getElementById(node) : node;
}

(function(){
    window.browser={}
    var d=browser

    var n = navigator;
    var dua = n.userAgent;
    var dav = n.appVersion;
    var tv = parseFloat(dav);

    d.isOpera = (dua.indexOf("Opera") >= 0) ? tv : 0;
    d.isKhtml = (dav.indexOf("Konqueror") >= 0)||(dav.indexOf("Safari") >= 0) ? tv : 0;
    d.isSafari = (dav.indexOf("Safari") >= 0) ? tv : 0;
    var geckoPos = dua.indexOf("Gecko");
    d.isMozilla = ((geckoPos >= 0)&&(!d.isKhtml)) ? tv : 0;
    d.isFF = 0;
    d.isIE = 0;
    try{
        if(d.isMozilla){
            d.isFF = parseFloat(dua.split("Firefox/")[1].split(" ")[0]);
        }
        if((document.all)&&(!d.isOpera)){
            d.isIE = parseFloat(dav.split("MSIE ")[1].split(";")[0]);
        }
    }catch(e){}
})()

// Поиск элемента по классу getElementsByClassName("название класса", элемент внутри которого ищем)
var getElementsByClassName = (function(){
    var d = window.document;
    if (typeof d.getElementsByClassName == 'function')
        return function(className, node){
            return (node || d).getElementsByClassName(className);
        };
    else
    if (typeof d.querySelectorAll == 'function')
        return function(className, node){
            return (node || d).querySelectorAll('.' + className);
        };
    else
        return function(className, node){
            if (!className)
                return [];
            var elements = (node || document).getElementsByTagName('*'), list = [], expr = new RegExp('(^|\\b)' + className + '(\\b|$)');
            if (elements.length == 0)
                return elements;
            for (var i = 0, length = elements.length; i < length; i++)
                if (expr.test(elements[i].className))
                    list[list.length] = elements[i];
            return list;
        };
})();

// возвращает cookie если есть или undefined
function getCookie(name){
    var matches = document.cookie.match(new RegExp("(?:^|; )" + name.replace(/([\.$?*|{}\(\)\[\]\\\/\+^])/g, '\\$1') + "=([^;]*)"))
    return matches ? decodeURIComponent(matches[1]) : undefined
}

// уcтанавливает cookie
function setCookie(name, value, props){
    props = props ||
    {}
    var exp = props.expires;
    if (typeof exp == "number" && exp) {
        var d = new Date();
        d.setTime(d.getTime() + exp * 1000);
        exp = props.expires = d;
    }
    if (exp && exp.toUTCString) {
        props.expires = exp.toUTCString();
    }
    value = encodeURIComponent(value);
    var updatedCookie = name + "=" + value;
    for (var propName in props) {
        updatedCookie += "; " + propName;
        var propValue = props[propName];
        if (propValue !== true) {
            updatedCookie += "=" + propValue;
        }
    }
    document.cookie = updatedCookie;
}

// удаляет cookie
function deleteCookie(name){
    setCookie(name, null, {
        expires: -1
    })
}

// Переключатель "показать-спрятать"
function toggle(el){
    el.style.display = (el.style.display == 'none') ? '' : 'none';
}

// Проверить наличие класса (при 'expand' совпадёт с  'expander')
function hasClass(o, c) {
    return new RegExp("(^|\\s)"+c+"(\\s|$)").test(o.className);
}

// Добавить класс элементу
function addClass(o, c){
    var re = new RegExp("(^|\\s)" + c + "(\\s|$)", "g")
    if (re.test(o.className)) return
    o.className = (o.className + " " + c).replace(/\s+/g, " ").replace(/(^ | $)/g, "")
}

// Удалить класс элемента
function removeClass(o, c){
    var re = new RegExp("(^|\\s)" + c + "(\\s|$)", "g")
    o.className = o.className.replace(re, "$1").replace(/\s+/g, " ").replace(/(^ | $)/g, "")
}

// Убирает пробельные символы слева
function ltrim(inp) {
    var ptrn = /\s*((\S+\s*)*)/;
    return inp.replace(ptrn, "$1");
}
// Убирает пробельные символы справа
function rtrim(inp) {
    var ptrn = /((\s*\S+)*)\s*/;
    return inp.replace(ptrn, "$1");
}
// Убирает пробельные символы с обоих концов
function trim(inp) {
    return ltrim(rtrim(inp));
}




// Функция добавления параметров в форму
function addParam(form, key, value){
    var input = document.createElement('textarea');
    input.name = key;
    input.value = value;
    form.appendChild(input);
}

// Функция скачивания файлов (да да не смейтесь...
function file_dload_nt(fid, fname, ftype, fctype) {
    var form=document.createElement('form');
    form.action='/portal/page/portal/server/loadfile0';
    form.method='POST';
    addParam(form, 'param1', fid);
    addParam(form, 'ftype', ftype);
    addParam(form, 'fctype', fctype);
    form.style.display='none';
    document.body.appendChild(form);
    form.submit();
    return false;
}

function file_dload_nt2(fid, fname, ftype, fctype) {
    var form=document.createElement('form');
    form.action='/portal/page/portal/server/loadfile2';
    form.method='POST';
    addParam(form, 'param1', fid);
    addParam(form, 'ftype', ftype);
    addParam(form, 'fctype', fctype);
    form.style.display='none';
    document.body.appendChild(form);
    form.submit();
    return false;
}

function locationSearchToArray() {
    var get = location.search.substr(1); // строка GET запроса
    return parseKeyValueString(get);
}

function parseKeyValueString(str) {
    var one = []; // два вспомагательных
    var two = []; // массива
    var res = [];
    if(typeof str == 'string' && str !== '' && str !== undefined) {
        one = (str.replace(new RegExp('&amp;','g'), '&')).split('&'); // разделяем переменные
        for(var i = 0; i < one.length; i++) {
            two = one[i].split('='); // массив param будет содержать
            res[two[0]] = two[1]; // пары ключ(имя переменной)->значение
        }
        return res;
    }
    else {
        return null;
    }
}

/**
* Сохраняет в куках текущий адрес страницы
* @param {number} id Ключ
* @param {Array} add Массив дополнительных get-параметров
* @return {boolean} Всегда false для использования в ссылках: onClick="return bck_set('fuck_each')"
*/
function bck_set(id, add) {
    var url;
    try {
        url = upd.location.href();
    } catch (e) {
        url = window.location.href;
    }
    if (add !== undefined) {
        var get = locationSearchToArray();
        var arrRes = [];
        var strRes = '';
        for (var key1 in get) arrRes[key1] = get[key1];
        for (var key2 in add) arrRes[key2] = add[key2];
        for (var key3 in arrRes) strRes += '&'+key3+'='+encodeURIComponent(arrRes[key3]);
        if (strRes.length > 0) strRes = '?'+strRes.substr(1);
        setCookie('bck_'+id, url.split('?')[0]+strRes, {
            path: '/'
        });
    }
    else {
        setCookie('bck_'+id, url, {
            path: '/'
        });
    }
    return false;
}

function bck_get(id, alt) {
    var link = bck_get_url(id, alt);
    if (link !== undefined)
        window.location.href = link;
    return false;
}

function bck_get_url(id, alt) {
    var link = getCookie('bck_'+id);
    if (link !== undefined) return link;
    if (alt !== undefined) return alt;
    return window.location.href;
}

function moveCaretStart(inp)
{
    if (inp.createTextRange) {// IE
        var r = inp.createTextRange();
        r.collapse(true);
        r.select();
    }
    if (inp.selectionStart) {// Moz
        inp.setSelectionRange(0,0);
    }
    inp.focus();
}

function moveCaretEnd(inp)
{
    if (inp.createTextRange) {// IE
        var r = inp.createTextRange();
        r.collapse(false);
        r.select();
    }
    if (inp.selectionStart) {// Moz
        var end = inp.value.length;
        inp.setSelectionRange(end,end);
    }
    inp.focus();
}

// функция постит объект-хэш content в виде формы с нужным action, target
// напр. postToIframe({a:5,b:6}, '/count.php', 'frame1')
function postToIframe(content, action, callback) {
    var code = Math.floor(Math.random() * 99999);
    var iframeId = 'iframe'+code;
    var formId = 'form'+code;
    var divId = 'div'+code;
    var callbackPerm = 'postToIframeCallbackPerm'+code;
    var callbackName = 'postToIframeCallbackName'+code;
    window[callbackPerm] = false;
    window[callbackName] = function(resp) {
        //alert(getIframeDocument(byId(iframeId)));
        if (window[callbackPerm]==true) {
            var div = byId(formId);
            div.parentNode.removeChild(div);
            if (callback)
                callback(resp);
        }
    };
    var tmpl = '<form name="'+formId+'" id="'+formId+'" action="'+action+'" method="post" target="'+iframeId+'">\n';
    for(var x in content) {
        //console.log(x + ' = ' + content[x]);
        tmpl += '<input type="hidden" name="'+x+'" value="'+content[x]+'">\n';
    }
    tmpl += '</form>\n\
<iframe name="'+iframeId+'" id="'+iframeId+'" height="0" width="0" onload="window.'+callbackName+'()"></iframe>';
    var div = document.createElement('div');
    div.id = divId;
    div.innerHTML = tmpl;
    //alert(div.innerHTML);
    document.body.appendChild(div);
    window[callbackPerm] = true;
    var phonyForm = document.forms[formId];
    phonyForm.submit();
}

// получить окно по тегу
function getIframeDocument(iframeNode) {
    if (iframeNode.contentDocument) return iframeNode.contentDocument
    if (iframeNode.contentWindow) return iframeNode.contentWindow.document
    return iframeNode.document
}

// браузер хранится в объекте browser
function createIFrame(fname, src, callback, debug){
    var ifrstr;
    if (callback)
        ifrstr = browser.isIE ? '<iframe name="'+fname+'" src="'+src+'" onload="this.callback()"></iframe>' : 'iframe';
    else
        ifrstr = browser.isIE ? '<iframe name="'+fname+'" src="'+src+'"></iframe>' : 'iframe';
    var cframe = document.createElement(ifrstr);
    with(cframe){
        name = fname; // это не для IE
        setAttribute('name', fname); // и это тоже, но вреда не будет
        id = fname; // а это везде ок
        }
    cframe.callback = function(){
        callback();
    }
    cframe.onload = cframe.callback();
    // можно добавлять сразу к document.body
    document.body.appendChild(cframe);
    if (!debug)
        hideIframe(cframe)
    if(!browser.isIE)
        setIframeSrc(cframe, src);
    return cframe
}

function setIframeSrc(iframeNode, src) {
    getIframeDocument(iframeNode).location.replace(src)
}

// прячем фрейм
function hideIframe(iframeNode) {
    with(iframeNode.style) {
        if(!browser.isSafari){
            position = "absolute";
        }
        left = top = "0px";
        height = width = "1px";
        visibility = "hidden";
        }
}

// Поля формы в виде JSON-массива
function formToJSON(form, encode) {
    var par = {}, el, length = form.elements.length;
    encode = encode == undefined ? true : false;
    for(var i = 0; i < length; ++i) {
        el = form.elements[i];
        if (encode === true)
            par[encodeURIComponent(el.name)] = encodeURIComponent(el.value);
        else
            par[el.name] = el.value;
    }
    return par;
}

var punycode = new function Punycode(){
    this.utf16={
        decode:function(input){
            var output=[],i=0,len=input.length,value,extra;
            while(i<len){
                value=input.charCodeAt(i++);
                if((value&63488)===55296){
                    extra=input.charCodeAt(i++);
                    if(((value&64512)!==55296)||((extra&64512)!==56320)){
                        throw new RangeError("UTF-16(decode): Illegal UTF-16 sequence");
                    }
                    value=((value&1023)<<10)+(extra&1023)+65536;
                }
                output.push(value);
            }
            return output;
        },
        encode:function(input){
            var output=[],i=0,len=input.length,value;
            while(i<len){
                value=input[i++];
                if((value&63488)===55296){
                    throw new RangeError("UTF-16(encode): Illegal UTF-16 value");
                }
                if(value>65535){
                    value-=65536;
                    output.push(String.fromCharCode(((value>>>10)&1023)|55296));
                    value=56320|(value&1023);
                }
                output.push(String.fromCharCode(value));
            }
            return output.join("");
        }
    };
    
    var initial_n=128;
    var initial_bias=72;
    var delimiter="\x2D";
    var base=36;
    var damp=700;
    var tmin=1;
    var tmax=26;
    var skew=38;
    var maxint=2147483647;
    function decode_digit(cp){
        return cp-48<10?cp-22:cp-65<26?cp-65:cp-97<26?cp-97:base;
    }
    function encode_digit(d,flag){
        return d+22+75*(d<26)-((flag!=0)<<5);
    }
    function adapt(delta,numpoints,firsttime){
        var k;
        delta=firsttime?Math.floor(delta/damp):(delta>>1);
        delta+=Math.floor(delta/numpoints);
        for(k=0;delta>(((base-tmin)*tmax)>>1);k+=base){
            delta=Math.floor(delta/(base-tmin));
        }
        return Math.floor(k+(base-tmin+1)*delta/(delta+skew));
    }
    function encode_basic(bcp,flag){
        bcp-=(bcp-97<26)<<5;
        return bcp+((!flag&&(bcp-65<26))<<5);
    }
    this.decode=function(input,preserveCase){
        var output=[];
        var case_flags=[];
        var input_length=input.length;
        var n,out,i,bias,basic,j,ic,oldi,w,k,digit,t,len;
        n=initial_n;
        i=0;
        bias=initial_bias;
        basic=input.lastIndexOf(delimiter);
        if(basic<0){
            basic=0;
        }
        for(j=0;j<basic;++j){
            if(preserveCase){
                case_flags[output.length]=(input.charCodeAt(j)-65<26);
            }
            if(input.charCodeAt(j)>=128){
                throw new RangeError("Illegal input >= 0x80");
            }
            output.push(input.charCodeAt(j));
        }
        for(ic=basic>0?basic+1:0;ic<input_length;){
            for(oldi=i,w=1,k=base;;k+=base){
                if(ic>=input_length){
                    throw RangeError("punycode_bad_input(1)");
                }
                digit=decode_digit(input.charCodeAt(ic++));
                if(digit>=base){
                    throw RangeError("punycode_bad_input(2)");
                }
                if(digit>Math.floor((maxint-i)/w)){
                    throw RangeError("punycode_overflow(1)");
                }
                i+=digit*w;
                t=k<=bias?tmin:k>=bias+tmax?tmax:k-bias;
                if(digit<t){
                    break;
                }
                if(w>Math.floor(maxint/(base-t))){
                    throw RangeError("punycode_overflow(2)");
                }
                w*=(base-t);
            }
            out=output.length+1;
            bias=adapt(i-oldi,out,oldi===0);
            if(Math.floor(i/out)>maxint-n){
                throw RangeError("punycode_overflow(3)");
            }
            n+=Math.floor(i/out);
            i%=out;
            if(preserveCase){
                case_flags.splice(i,0,input.charCodeAt(ic-1)-65<26);
            }
            output.splice(i,0,n);
            i++;
        }
        if(preserveCase){
            for(i=0,len=output.length;i<len;i++){
                if(case_flags[i]){
                    output[i]=(String.fromCharCode(output[i]).toUpperCase()).charCodeAt(0);
                }
            }
        }
        return this.utf16.encode(output);
    };

    this.encode=function(input,preserveCase){
        var n,delta,h,b,bias,j,m,q,k,t,ijv,case_flags;
        if(preserveCase){
            case_flags=this.utf16.decode(input);
        }
        input=this.utf16.decode(input.toLowerCase());
        var input_length=input.length;
        if(preserveCase){
            for(j=0;j<input_length;j++){
                case_flags[j]=input[j]!=case_flags[j];
            }
        }
        var output=[];
        n=initial_n;
        delta=0;
        bias=initial_bias;
        for(j=0;j<input_length;++j){
            if(input[j]<128){
                output.push(String.fromCharCode(case_flags?encode_basic(input[j],case_flags[j]):input[j]));
            }
        }
        h=b=output.length;
        if(b>0){
            output.push(delimiter);
        }while(h<input_length){
            for(m=maxint,j=0;j<input_length;++j){
                ijv=input[j];
                if(ijv>=n&&ijv<m){
                    m=ijv;
                }
            }
            if(m-n>Math.floor((maxint-delta)/(h+1))){
                throw RangeError("punycode_overflow (1)");
            }
            delta+=(m-n)*(h+1);
            n=m;
            for(j=0;j<input_length;++j){
                ijv=input[j];
                if(ijv<n){
                    if(++delta>maxint){
                        return Error("punycode_overflow(2)");
                    }
                }
                if(ijv==n){
                    for(q=delta,k=base;;k+=base){
                        t=k<=bias?tmin:k>=bias+tmax?tmax:k-bias;
                        if(q<t){
                            break;
                        }
                        output.push(String.fromCharCode(encode_digit(t+(q-t)%(base-t),0)));
                        q=Math.floor((q-t)/(base-t));
                    }
                    output.push(String.fromCharCode(encode_digit(q,preserveCase&&case_flags[j]?1:0)));
                    bias=adapt(delta,h+1,h==b);
                    delta=0;
                    ++h;
                }
            }
            ++delta,++n;
        }
        return output.join("");
    };

    this.ToASCII=function(domain){
        var domain_array=domain.split(".");
        var out=[];
        for(var i=0;i<domain_array.length;++i){
            var s=domain_array[i];
            out.push(s.match(/[^A-Za-z0-9-]/)?"xn--"+punycode.encode(s):s);
        }
        return out.join(".");
    };

    this.ToUnicode=function(domain){
        var domain_array=domain.split(".");
        var out=[];
        for(var i=0;i<domain_array.length;++i){
            var s=domain_array[i];
            out.push(s.match(/^xn--/)?punycode.decode(s.slice(4)):s);
        }
        return out.join(".");
    };

}();
