Create = {
    element:    function(name) { return document.createElement(name) },
    text:       function(text) { return document.createTextNode(text) }
}

function $id(id) {
    return document.getElementById(id)
}

Function.prototype.bind = function(object, args) {
    var method = this
    return function() {
        var a = (args == null) ? arguments : args
        return method.apply(object, a) 
    }
}

if(typeof Array.prototype.forEach == "undefined") {
    Array.prototype.forEach = function(callback, object) {
        for(var i=0; i<this.length; i++) callback.call(object, this[i], i, this)
    }
}

DOM = {}

DOM.create = Create

DOM.getBounds = function(element) {
  var left = element.offsetLeft;
  var top = element.offsetTop;
  for (var parent = element.offsetParent; parent; parent = parent.offsetParent) {
    left += parent.offsetLeft;
    top += parent.offsetTop;
  }
  return {left: left, top: top, width: element.offsetWidth, height: element.offsetHeight};
}



if (typeof document.defaultView == 'undefined')
  document.defaultView = {};

if (typeof document.defaultView.getComputedStyle == 'undefined')
{
  document.defaultView.getComputedStyle = function(element, pseudoElement)
  {
    return element.currentStyle;
  }
}


var Animation = function(time, steps) {
    this.time  = time || 500;
    this.steps = steps || 10;
    this.position   = 0;

    this.onStart     = null;
    this.onEnd       = null;
    this.onProcess   = null;
};

Animation.prototype.start = function() {
    if(this.onStart) this.onStart();
    this.position = 0;
    this.process();
};

Animation.prototype.process = function() {
    this.position++
    if(this.onProcess) this.onProcess(this.position/this.steps);
    if(this.position >= this.steps) {
        if(this.onEnd) this.onEnd();
    } else {
        window.setTimeout(this.process.bind(this), this.time/this.steps);
    }
};


function addHandler(object, event, handler)
{
  if (typeof object.addEventListener != 'undefined')
    object.addEventListener(event, handler, false);
  else if (typeof object.attachEvent != 'undefined')
    object.attachEvent('on' + event, handler);
  else
  {
    var handlersProp = '_handlerStack_' + event;
    var eventProp = 'on' + event;
    if (typeof object[handlersProp] == 'undefined')
    {
      object[handlersProp] = [];
      if (typeof object[eventProp] != 'undefined')
        object[handlersProp].push(object[eventProp]);
      object[eventProp] = function(e)
      {
        var ret = true;
        for (var i = 0; ret != false && i < object[handlersProp].length; i++)
          ret = object[handlersProp][i](e);
        return ret;
      }
    }
    object[handlersProp].push(handler);
  }
}

function removeHandler(object, event, handler)
{
  if (typeof object.removeEventListener != 'undefined')
    object.removeEventListener(event, handler, false);
  else if (typeof object.detachEvent != 'undefined')
    object.detachEvent('on' + event, handler);
  else
  {
    var handlersProp = '_handlerStack_' + event;
    if (typeof object[handlersProp] != 'undefined')
    {
      for (var i = 0; i < object[handlersProp].length; i++)
      {
        if (object[handlersProp][i] == handler)
        {
          object[handlersProp].splice(i, 1);
          return;
        }
      }
    }
  }
}

function setGlobalOnLoad(f) {
   var root = window.addEventListener || window.attachEvent ? window : document.addEventListener ? document : null
   if (root){
      if(root.addEventListener) root.addEventListener("load", f, false)
      else if(root.attachEvent) root.attachEvent("onload", f)
   } else {
      if(typeof window.onload == 'function') {
         var existing = window.onload
         window.onload = function() {
            existing()
            f()
         }
      } else {
         window.onload = f
      }
   }
}
/*
    json.js
    2006-04-28

    This file adds these methods to JavaScript:

        object.toJSONString()

            This method produces a JSON text from an object. The
            object must not contain any cyclical references.

        array.toJSONString()

            This method produces a JSON text from an array. The
            array must not contain any cyclical references.

        string.parseJSON()

            This method parses a JSON text to produce an object or
            array. It will return false if there is an error.

    2006-08-28
        интерфейс изменён на:
        JSON.encode(mix)
        JSON.parse(string) = JSON.decode(string)

        потому что прототипы стандартных объёктов (тем более, Object-а) трогать нельзя

*/

var JSON = {};

(function () {
    var m = {
            '\b': '\\b',
            '\t': '\\t',
            '\n': '\\n',
            '\f': '\\f',
            '\r': '\\r',
            '"' : '\\"',
            '\\': '\\\\'
        },
        s = {
            array: function (x) {
                var a = ['['], b, f, i, l = x.length, v;
                for (i = 0; i < l; i += 1) {
                    v = x[i];
                    f = s[typeof v];
                    if (f) {
                        v = f(v);
                        if (typeof v == 'string') {
                            if (b) {
                                a[a.length] = ',';
                            }
                            a[a.length] = v;
                            b = true;
                        }
                    }
                }
                a[a.length] = ']';
                return a.join('');
            },
            'boolean': function (x) {
                return String(x);
            },
            'null': function (x) {
                return "null";
            },
            number: function (x) {
                return isFinite(x) ? String(x) : 'null';
            },
            object: function (x) {
                if (x) {
                    if (x instanceof Array) {
                        return s.array(x);
                    }
                    var a = ['{'], b, f, i, v;
                    for (i in x) {
                        v = x[i];
                        f = s[typeof v];
                        if (f) {
                            v = f(v);
                            if (typeof v == 'string') {
                                if (b) {
                                    a[a.length] = ',';
                                }
                                a.push(s.string(i), ':', v);
                                b = true;
                            }
                        }
                    }
                    a[a.length] = '}';
                    return a.join('');
                }
                return 'null';
            },
            string: function (x) {
                if (/["\\\x00-\x1f]/.test(x)) {
                    x = x.replace(/([\x00-\x1f\\"])/g, function(a, b) {
                        var c = m[b];
                        if (c) {
                            return c;
                        }
                        c = b.charCodeAt();
                        return '\\u00' +
                            Math.floor(c / 16).toString(16) +
                            (c % 16).toString(16);
                    });
                }
                return '"' + x + '"';
            }
        };

    /*
    Object.prototype.toJSONString = function () {
        return s.object(this);
    };

    Array.prototype.toJSONString = function () {
        return s.array(this);
    };
    */

    JSON.encode = function (mix) {
        return (mix instanceof Array) ? s.array(mix) : s.object(mix);
    }
})();

JSON.parse = JSON.decode = function (str) {
    try {
        return !(/[^,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]/.test(
                str.replace(/"(\\.|[^"\\])*"/g, ''))) &&
            eval('(' + str + ')');
    } catch (e) {
        return false;
    }
};

/*
    if(!AjaxRpc.enabled) alert("error")

    var conn = AjaxRpc.connection("./service.php", ["sum", "sub", "mul"])

    conn.sum(1, 2).callback = function(result, error) { alert(result) } 

*/


var AjaxRpc = new function() {
    this.createRequestObject = function() {
        var request = null
        if(typeof XMLHttpRequest != "undefined") request = new XMLHttpRequest();
        else if (typeof ActiveXObject != "undefined") request = new ActiveXObject("Microsoft.XMLHTTP");
/*
        if(!request) try { request=new ActiveXObject('Msxml2.XMLHTTP') } catch (exc){}
        if(!request) try { request=new ActiveXObject('Microsoft.XMLHTTP') } catch (exc){}
        if(!request) try { request=new XMLHttpRequest() } catch (exc){}
*/
        return request
    }

    this.onRequestStart = null
    this.onRequestEnd = null
    
    var self = this

    var callMethod = function(url, method, args) {
        var params = { method: method, args: [] }
        for(var i=0; i<args.length; i++) params.args.push(args[i])

        var request = self.createRequestObject()
        if(!request) return null

        var result = { callback: null }
        request.onreadystatechange  = function() {
                if(request.readyState == 4 && result.callback) {
                    if(AjaxRpc.onRequestEnd) AjaxRpc.onRequestEnd()

                    var resp = JSON.parse(request.responseText)
                    if(resp == false) {
                        //alert(request.responseText)
                        alert("AjaxRpc: JSON parsing error (" + request.responseText.substr(0, 30) + "...)")
                    } else if(typeof resp.result == "undefined" || typeof resp.error == "undefined")  {
                        alert("AjaxRpc: Invalid script output(" + request.responseText.substr(0, 30) + "...)")
                    } else if(result.callback) {
                        result.callback(resp.result, resp.error)
                    }
                }
            }

        request.open('POST', url, true)
        request.send(JSON.encode(params))
        if(AjaxRpc.onRequestStart) AjaxRpc.onRequestStart()
        return result
    }

    this.enabled = this.createRequestObject() ? true : false

    this.connection = function(url, methods) {
        var conn = {}
        for(var i=0; i<methods.length; i++) {
            conn[methods[i]] = function(u, m) {
                    return function() { return callMethod(u, m, arguments) } 
                }(url, methods[i])
        }
        return conn
    }

}()



function MouseTail(id, offsetX, offsetY) {
    this.id = id;
    this.offsetX = offsetX;
    this.offsetY = offsetY;
    this.visible = false;
    this.object = null;
    this.onMouseMove = function() {
        if(!this.visible) return;
        if(!this.object) this.object = document.getElementById(this.id);
        if(!this.object) return;
        this.object.style.left = (MouseTail.Mouse.x + this.offsetX) + "px";
        this.object.style.top  = (MouseTail.Mouse.y + this.offsetY) + "px";
    };

    this.show = function() {
        if(this.visible) return;
        this.visible = true;
        this.onMouseMove();
        if(this.object) this.object.style.visibility = "visible";
    };

    this.hide = function() {
        if(!this.visible) return;
        this.visible = false;
        if(this.object) this.object.style.visibility = "hidden";
    };


    if(!MouseTail.initialized) {
        MouseTail.Mouse = {x: 0, y: 0};
        if(typeof document.addEventListener != 'undefined') document.addEventListener("mousemove", function(e) {
                MouseTail.Mouse.x = e.pageX;
                MouseTail.Mouse.y = e.pageY;
                this.onMouseMove();
            }.bind(this), false);
        else if (typeof document.attachEvent != 'undefined') document.attachEvent("onmousemove", function() {
                MouseTail.Mouse.x = window.event.clientX+document.body.scrollLeft;
                MouseTail.Mouse.y = window.event.clientY+document.body.scrollTop;
                this.onMouseMove();
            }.bind(this));
        MouseTail.initialized = true;
    }
}

function win2unicode(str) {
	var charmap	= unescape(
		"%u0402%u0403%u201A%u0453%u201E%u2026%u2020%u2021%u20AC%u2030%u0409%u2039%u040A%u040C%u040B%u040F"+
		"%u0452%u2018%u2019%u201C%u201D%u2022%u2013%u2014%u0000%u2122%u0459%u203A%u045A%u045C%u045B%u045F"+
		"%u00A0%u040E%u045E%u0408%u00A4%u0490%u00A6%u00A7%u0401%u00A9%u0404%u00AB%u00AC%u00AD%u00AE%u0407"+
		"%u00B0%u00B1%u0406%u0456%u0491%u00B5%u00B6%u00B7%u0451%u2116%u0454%u00BB%u0458%u0405%u0455%u0457")
	var code2char = function(code) {
					if(code >= 0xC0 && code <= 0xFF) return String.fromCharCode(code - 0xC0 + 0x0410)
					if(code >= 0x80 && code <= 0xBF) return charmap.charAt(code - 0x80)
					return String.fromCharCode(code)
				}
	var res = ""
	for(var i = 0; i < str.length; i++) res = res + code2char(str.charCodeAt(i))
	return res
}

function koi2unicode(str) {
	var charmap	= unescape(
		"%u2500%u2502%u250C%u2510%u2514%u2518%u251C%u2524%u252C%u2534%u253C%u2580%u2584%u2588%u258C%u2590"+
		"%u2591%u2592%u2593%u2320%u25A0%u2219%u221A%u2248%u2264%u2265%u00A0%u2321%u00B0%u00B2%u00B7%u00F7"+
		"%u2550%u2551%u2552%u0451%u2553%u2554%u2555%u2556%u2557%u2558%u2559%u255A%u255B%u255C%u255D%u255E"+
		"%u255F%u2560%u2561%u0401%u2562%u2563%u2564%u2565%u2566%u2567%u2568%u2569%u256A%u256B%u256C%u00A9"+
		"%u044E%u0430%u0431%u0446%u0434%u0435%u0444%u0433%u0445%u0438%u0439%u043A%u043B%u043C%u043D%u043E"+
		"%u043F%u044F%u0440%u0441%u0442%u0443%u0436%u0432%u044C%u044B%u0437%u0448%u044D%u0449%u0447%u044A"+
		"%u042E%u0410%u0411%u0426%u0414%u0415%u0424%u0413%u0425%u0418%u0419%u041A%u041B%u041C%u041D%u041E"+
		"%u041F%u042F%u0420%u0421%u0422%u0423%u0416%u0412%u042C%u042B%u0417%u0428%u042D%u0429%u0427%u042A")
	var code2char = function(code) {
					if(code >= 0x80 && code <= 0xFF) return charmap.charAt(code - 0x80)
					return String.fromCharCode(code)
				}
	var res = ""
	for(var i = 0; i < str.length; i++) res = res + code2char(str.charCodeAt(i))
	return res
}

function parseQueryString(query) {
    if(!query) return {}
	params = {}
	pairs = query.split("&")
	for(var i in pairs) {
		if(!pairs[i] || !pairs[i].split) continue
		var p = pairs[i].split("=")
        if(p.length == 2) {
    		try {
    			params[p[0]] = decodeURIComponent(p[1].replace(/\+/g, "%20"))
    		} catch(e) {
    			params[p[0]] = unescape(p[1].replace(/\+/g, "%20"))
    		}
        }
	}
	return params
}

function parseUrl(url) {
	if(!url) return null
	var r = url.match(/^([a-z]+):\/\/([a-z0-9._-]+)(:([0-9]+))?([^?#]*)(\?([^#]*))?(#(.*))?/i)
	if(!r) return null
	var parsed = {
		protocol:	r[1],
		host:		r[2],
		port:		r[4],
		path:		r[5],
		query:		r[7],
		hash:		r[9],
		params:		parseQueryString(r[7])
	}
	return parsed
}

var searchHighlighter = {
	highlightWord:	function(node, word, classname) {
						if(!classname) classname = "searchword"
						if (node.hasChildNodes)
							for (var i=0; i<node.childNodes.length; i++)
								this.highlightWord(node.childNodes[i], word, classname)
						
						if (node.nodeType == 3) { // text node
							var tempNodeVal = node.nodeValue.toLowerCase()
							var tempWordVal = word.toLowerCase()
							if (tempNodeVal.indexOf(tempWordVal) != -1) {
								var parent = node.parentNode
								if (parent.className != classname) {
									var value = node.nodeValue
									var ni = tempNodeVal.indexOf(tempWordVal)

									var hiword = document.createElement("span")
									hiword.className = classname
									hiword.appendChild(document.createTextNode(value.substr(ni, word.length)))
									parent.insertBefore(document.createTextNode(value.substr(0,ni)), node)
									parent.insertBefore(hiword,node)
									parent.insertBefore(document.createTextNode(value.substr(ni+word.length)), node)
									parent.removeChild(node)
								}
							}
						}
					},

	process:		function(referer) {
						var url = parseUrl(referer)
						if(!url) return
						var serachString = ""
						if(url.host.indexOf("google.") != -1) {
							serachString = url.params.q
                            if(url.params.as_q) serachString += " "+url.params.as_q
						} else if(url.host.indexOf("yahoo.") != -1) {
							serachString = url.params.p
						} else if(url.host.indexOf(".mail.ru") != -1 && url.path == "/search") {
							serachString = win2unicode(url.params.q)
						} else if(url.host.indexOf(".rambler.ru") != -1) {
							serachString = win2unicode(url.params.words)
						} else if(url.host.indexOf("yandex.ru") != -1) {
							var params = url.params
							var decoder = win2unicode
							if(url.params.qs) {
								params = parseQueryString(url.params.qs)
								decoder = koi2unicode
							}
							serachString = params.Hint ? params.Hint : params.text ? params.text : ""
							serachString = decoder(serachString)
						}
						var words = serachString.split(/\s+/)
						for(var k=0; k<words.length; k++) {
                            if(!words[k] || !words[k].replace) continue
							var word = words[k].replace(/^\s+/i,'').replace(/\s+$/i,'');
							var classname = this.classes[k % this.classes.length]
							if(word.length <= 2) continue
							this.highlightWord(document.body, word, classname)
						}
					},
					
					
	classes:		["searchword"]
}


setGlobalOnLoad(function() { searchHighlighter.process(document.referrer) })


