var BTN_LEFT = is_browser_ie() ? 1 : 0;
var BTN_MIDDLE = is_browser_ie() ? 4 : 1;
var BTN_RIGHT = 2;

function hash(data)
{
    var hash = '';
    if (typeof data == 'object') {
        for (i in data) {
            hash += '\n' + i + ':' + data[i];
        }
    } else if (typeof data == 'array') {
        for (i = 0; i < data.length; i ++) {
            hash += '\n' + i + ':' + data[i];
        }
    }
    return hash;
}

function deep_hash(data, padding, pad_with)
{
    if (!padding) {
        padding = '\n';
    }
    if (!pad_with) {
        pad_with = '\t';
    }
    var hash = '';
    switch (typeof data) {
    case 'object':
        for (i in data) {
            hash += padding + i + ':' + deep_hash(data[i], padding + pad_with, pad_with);
        }
        break;
    case 'array':
        for (i = 0; i < data.length; i ++) {
            hash += '\n' + i + ':' + deep_hash(data[i], padding + pad_with, pad_with);
        }
        break;
    default:
        hash = data;
    }
    return hash;
}

function empty(object)
{
    return !object || object == '';
}

function array_get(array, name, default_value)
{
    if (array[name]) {
        return array[name];
    } else {
        return default_value ? default_value : '';
    }
}

function in_array(value, array)
{
    for (var i in array) {
        if (value == array[i]) {
            return true;
        }
    }
    return false;
}

function is_scalar(variable)
{
    return ['number', 'string', 'boolean'].has(typeof variable);
}

Math.sign = function (x) {
    return x == 0 ? 0 : (x > 0 ? 1 : -1);
}

Math.rand = function (min, max) {
    if (!max) {
        min = 0;
        max = min
    }
    return Math.round(Math.random() * (max - min)) + min;
}

Array.prototype.has = function (value) {
    for (var i in this) {
        if (value == this[i]) {
            return true;
        }
    }
    return false;
}

Array.prototype.pull = function (value) {
    for (var i in this) {
        if (value == this[i]) {
            this.splice(i, 1);
        }
    }
}

Array.prototype.last = function () {
    return this.slice(-1)[0];
}

var $ = ID = function (id)
{
    return document.getElementById(id);
}

function preg_quote(str)
{
    var regexp = new RegExp('([\\<\\>\\/\\?\\.\\$\\^\\[\\]\\*\\+\\\\])', 'g');
    return str.replace(regexp, '\\$1');
}

function is_browser_ie()
{
    var isDOM = document.getElementById; //DOM1 browser (MSIE 5+, Netscape 6, Opera 5+)
    var isOpera = isOpera5 = window.opera && isDOM; //Opera 5+
    var isOpera6 = isOpera && window.print; //Opera 6+
    var isOpera7 = isOpera && document.readyState; //Opera 7+
    var isMSIE = document.all && document.all.item && !isOpera; //Microsoft Internet Explorer 4+
    var isMSIE5 = isDOM && isMSIE; //MSIE 5+
    var isNetscape4 = document.layers; //Netscape 4.*
    var isMozilla = isDOM && navigator.appName=="Netscape"; //Mozilla or Netscape 6.*
    return isMSIE;
}

function is_browser_opera()
{
    var isDOM = document.getElementById;
    return (window.opera && isDOM);
}

/**
 * Event handler
 *
 */
var Events = function (object) {
    this.object = object;
    this.attach = function (event, action, useCapture) {
    	if (!useCapture) {
    	    useCapture = false;
    	}
    	if (this.object.addEventListener) {
    		return this.object.addEventListener(event, action, useCapture);
    	} else if (this.object.attachEvent) {
    	    return this.object.attachEvent('on' + event, action);
    	}
    }

    this.detach = function (event, action, useCapture) {
    	if (!useCapture) {
    	    useCapture = false;
    	}
    	if (this.object.removeEventListener) {
    	    return this.object.removeEventListener(event, action, useCapture);
    	} else if (this.object.detachEvent) {
    	    return this.object.detachEvent('on' + event, action);
    	}
    }


    this.prevent_default = function (evt) {
    	// *** Cross browser function to prevent the default action from occuring.
    	if (!evt && window.event) {
    	    evt = window.event;
    	}
    	if (evt != null) {
    		if (typeof(evt.preventDefault) == 'function') {
    		    evt.preventDefault();
    		} else {
    		    evt.returnValue = false;
    		}
    	}
    	return false;
    }

    this.cancel_bubble = function (evt) {
    	// *** Cross browser function to prevent the event from bubbling.
    	if (!evt && window.event) {
    	    evt = window.event;
    	}
    	if (evt != null) {
    		if (typeof evt.stopPropagation == 'function') {
    		    evt.stopPropagation();
    		} else {
    		    evt.cancelBubble = true;
    		}
    	}
    	return false;
    }

    return this;
}


/**
 * CSS handler
 * From x-Point.ru: http://xpoint.ru/know-how/JavaScript/PoleznyieFunktsii?31
 */

//class-wrapper
function CssClassesHandler(object) {
    this.object = object;
}

CssClassesHandler.prototype = {
    object: null,

    //return all classes as an array
    all: function() {
        if (this.object) {
            return this.object.className ? this.object.className.split(new RegExp('\\s+')) : [];
        } else {
            return '';
        }
    },

    //checks class
    exists: function(className) {
        var classes = this.all();
        for (var i = 0; i < classes.length; i ++) {
            if (classes[i] == className) {
                return true;
            }
        }
        return false;
    },

    //add class
    add: function(className) {
        if (this.object) {
            if (!this.exists(className)) {
                this.object.className = this.object.className + ' ' + className;
            }
        }
    },

    //remove class
    remove: function(className) {
        if (this.object) {
            var classes = this.all();
            var cn = '';
            for (var i = 0; i < classes.length; i ++) {
                if (classes[i] != className) {
                    cn = cn + ' ' + classes[i];
                }
            }
            this.object.className = cn.substr(1);
        }
    },

    //replace class
    replace: function(find, replace) {
        if (this.object) {
            var classes = this.all();
            var cn = '';
            for (var i = 0; i < classes.length; i ++) {
                if (classes[i] != find) {
                    cn = cn + ' ' + classes[i];
                } else {
                    cn = cn + ' ' + replace;
                }
            }
            this.object.className = cn.substr(1);
        }
    },

    //set or remove class depends on state
    set: function(className, state) {
        if (state) {
            this.add(className);
        } else {
            this.remove(className);
        }
    },

    //set class if not isset, otherwise remove it
    flip: function(className) {
        if (this.exists(className)) {
            this.remove(className);
        } else {
            this.add(className);
        }
    }
}

//create object wrapper
function CssClasses(object) {
    return new CssClassesHandler(object);
}

/**
 * Positioner
 *
 */
var Positions = (function () {

    this.get_cursor = function (e)
    {
    	var x = 0, y = 0;

    	if (!e) {
    	    e = window.event;
    	}

    	if (e.pageX || e.pageY)	{
    		x = e.pageX;
    		y = e.pageY;
    	} else if (e.clientX || e.clientY) {
    		x = e.clientX + this.get_body_scroll().left;
    		y = e.clientY + this.get_body_scroll().top;
    	} else if (e.screenX || e.screenY) {
    	    x = e.screenX;
    	    y = e.screenY;
    	}

        return {'x': x, 'y': y};
    }

    this.get_element = function (e) {
        var x = 0, y = 0;
        while (e) {
            x += e.offsetLeft;
            y += e.offsetTop;
            e = e.offsetParent;
        }
        return {'x': x, 'y': y};
    }

    this.get_body_scroll = function ()
    {
        var top = self.pageYOffset
                || (document.documentElement && document.documentElement.scrollTop)
                || (document.body && document.body.scrollTop);

        var left = self.pageXOffset
                 || (document.documentElement && document.documentElement.scrollLeft)
                 || (document.body && document.body.scrollLeft);

        return {'left': left, 'top': top};
    }

    this.get_client = function (win) {
    	var w = 0;

        if (!win) {
            win = window.window;
        }

    	if (win.self.innerHeight) {
    	    w = win.self.innerWidth;
    	    h = win.self.innerHeight;
    	} else if (win.document.documentElement && win.document.documentElement.clientWidth) {
    	    w = win.document.documentElement.clientWidth;
    	    h = win.document.documentElement.clientHeight;
    	} else if (win.document.body) {
    	    w = win.document.body.clientWidth;
    	    h = win.document.body.clientHeight;
    	}

    	return {'width': w, 'height': h};
    }

    return this;
})();

Nodes = function (node) {
    var self = this;
    this.node = node;

    this.is_descendant_of = function (node) {
        var parent = self.node.parentNode;
        while (parent) {
            if (parent == node) {
                return true;
            }
            parent = parent.parentNode;
        }
        return false;
    }

    this.is_ancestor_of = function (node) {
        var parent = node.parentNode;
        while (parent) {
            if (parent == self.node) {
                return true;
            }
            parent = parent.parentNode;
        }
        return false;
    }

    this.remove_children = function () {
        while (this.node.firstChild) {
            this.node.removeChild(this.node.firstChild);
        }
    }

    this.next_tag = function (tag) {
        var current = self.node.nextSibling;
        while (current && (!current.tagName || current.tagName.toLowerCase() != tag.toLowerCase())) {
            current = current.nextSibling;
        }
        return current;
    }

    this.ancestor_tag = function (tag) {
        var current = self.node.parentNode;
        while (current && (!current.tagName || current.tagName.toLowerCase() != tag.toLowerCase())) {
            current = current.parentNode;
        }
        return current;
    }

    this.previous_tag = function (tag) {
        var current = self.node.previousSibling;
        while (current && (!current.tagName || current.tagName.toLowerCase() != tag.toLowerCase())) {
            current = current.previousSibling;
        }
        return current;
    }

    this.replace = function (node) {
        this.node.parentNode.replaceChild(node, this.node);
    }

    return this;
};

var included = [];
function include(path)
{
    include_path = URL['js'] + path.replace(new RegExp('\\.', 'g'), '/') + '.js';
    if (!included.has(path)) {
        var script = document.createElement('SCRIPT');
        script.type = 'text/javascript';
        script.src = include_path;
        document.getElementsByTagName('HEAD')[0].appendChild(script);

//        var request = new Ajax(include_path);
//        request.sync = false;
//        request.send();
//        eval(request.text_response);

        included.push(path);

    }
}

function require(path, procedure)
{
    include_path = URL['js'] + path.replace(new RegExp('\\.', 'g'), '/') + '.js';
    if (!included.has(path)) {
        var script = document.createElement('SCRIPT');
        script.type = 'text/javascript';
        script.src = include_path;
        document.getElementsByTagName('HEAD')[0].appendChild(script);

        script.onreadystatechange = function () {
            if (this.readyState == 'loaded') {
                procedure();
            }
        }

        script.onload = function () {
            procedure();
        }

        included.push(path);

    }
}
