/**
 * class wrapper for JS
 * founded at 
 * http://www.ajaxpath.com/javascript-inheritance
 */
function Class() { }
/**
 * constructor definition
 */
Class.prototype.construct = function() {};
/**
 * @param def - new class defifnition
 *
 * @return handled class definition
 */
Class.extend = function(def) {
    var classDef = function() {
        if (arguments[0] !== Class) { this.construct.apply(this, arguments); }
    };
    
    var proto = new this(Class);
    var superClass = this.prototype;
    
    for (var n in def) {
        var item = def[n];                        
        if (item instanceof Function) item.$ = superClass;
        proto[n] = item;
    }

    classDef.prototype = proto;
    
    //Give this new class the same static extend method    
    classDef.extend = this.extend;        
    return classDef;
};


/**
 * class - browser information
 * founded at
 * http://www.quirksmode.org/js/detect.html
 */
var Browser = Class.extend({

	/**
	 * main function - process all information about browser
	 *
	 * @return void
	 */
	initBrowserDetection: function () {
		this.browser = this.searchString(this.dataBrowser) || "An unknown browser";
		this.version = this.searchVersion(navigator.userAgent)
			|| this.searchVersion(navigator.appVersion)
			|| "an unknown version";
		this.OS = this.searchString(this.dataOS) || "an unknown OS";
	},
	
	/**
	 * private function - search srting in the array
	 *
	 * @param data  - array
	 *
	 * @return search result
	 */
	searchString: function (data) {
		for (var i=0;i<data.length;i++){
			var dataString = data[i].string;
			var dataProp = data[i].prop;
			this.versionSearchString = data[i].versionSearch || data[i].identity;
			if (dataString) {
				if (dataString.indexOf(data[i].subString) != -1) {
					return data[i].identity;
				}
			}
			else if (dataProp) {
				return data[i].identity;
			}
		}
	},
	
	/**
	 * search version in the string
	 *
	 * @param dataString - string
	 *
	 * @return version
	 */
	searchVersion: function (dataString) {
		var index = dataString.indexOf(this.versionSearchString);
		if (index == -1) return;
		return parseFloat(dataString.substring(index+this.versionSearchString.length+1));
	},

	/**
	 * array of browser detection information
	 */
	dataBrowser: [
		{ 
			string: navigator.userAgent,
			subString: "OmniWeb",
			versionSearch: "OmniWeb/",
			identity: "OmniWeb"
		},
		{
			string: navigator.vendor,
			subString: "Apple",
			identity: "Safari"
		},
		{
			prop: window.opera,
			identity: "Opera"
		},
		{
			string: navigator.vendor,
			subString: "iCab",
			identity: "iCab"
		},
		{
			string: navigator.vendor,
			subString: "KDE",
			identity: "Konqueror"
		},
		{
			string: navigator.userAgent,
			subString: "Firefox",
			identity: "Firefox"
		},
		{
			string: navigator.vendor,
			subString: "Camino",
			identity: "Camino"
		},
		{// for newer Netscapes (6+)
			string: navigator.userAgent,
			subString: "Netscape",
			identity: "Netscape"
		},
		{
			string: navigator.userAgent,
			subString: "MSIE",
			identity: "Explorer",
			versionSearch: "MSIE"
		},
		{
			string: navigator.userAgent,
			subString: "Gecko",
			identity: "Mozilla",
			versionSearch: "rv"
		},
		{ // for older Netscapes (4-)
			string: navigator.userAgent,
			subString: "Mozilla",
			identity: "Netscape",
			versionSearch: "Mozilla"
		}
	],
	
	/**
	 * array of operation system information
	 */
	dataOS : [
		{
			string: navigator.platform,
			subString: "Win",
			identity: "Windows"
		},
		{
			string: navigator.platform,
			subString: "Mac",
			identity: "Mac"
		},
		{
			string: navigator.platform,
			subString: "Linux",
			identity: "Linux"
		}
	],

	/**
	 * get browser type info
	 *
	 * @return browser name
	 */
	getBrowser: function() {
		return this.browser;
	},

	/**
	 * check is used browser IE
	 *
	 * @return boolean
	 */
	isIE: function() {
		if (this.browser == 'Explorer') {
			return true;
		}
		return false;		
	},

	/**
	 * check is used browser Opera
	 *
	 * @return boolean
	 */
	isOpera: function() {
		if (this.browser == 'Opera') {
			return true;
		}
		return false;		
	}
});



/**
 * class - window information
 * get some window object information
 */
var Window = Browser.extend({

	/**
	 * constructor
	 * initialize parent class (Browser) 
	 */
	construct: function() {
		this.initBrowserDetection();
	},

	/**
	 * return height of body
	 *
	 * @return height (px)
	 */
	getWinHeight: function() {
		return document.body.scrollHeight;
	},
	
	/**
	 * return width of body
	 *
	 * @return width (px)
	 */
	getWinWidth: function() {
		return document.body.scrollWidth;
	}
});



/**
 * class - element manager
 * manipulate with elements (create, delete, edit settings)
 */
var ElementManager = Browser.extend({

	/**
	 * constructor
	 * initialize parent class (Browser) 
	 */
	construct: function() {
		this.initBrowserDetection();
	},

	/**
	 * create <input > element with selected parameters
	 *
	 * @param id  - element id
	 * @param type - input type
	 * @param name - element name
	 * @param isChecked - is checked
	 *
	 * @return input element
	 */
	createInput: function(id, type, name, isChecked) {
    	if (this.isIE()) {
        	if (isChecked) {
        		this.inp = document.createElement('<INPUT NAME="' + name +'" checked="checked">');
        	} else{
        		this.inp = document.createElement('<INPUT NAME="' + name +'">');
        	}
			this.inp.type = type;
    	} else {
        	this.inp = document.createElement('INPUT');
			this.inp.type = type;
        	this.inp.name = name;
        	this.inp.checked = isChecked;
    	}
		this.inp.id = id;
		
		return this.inp;
	},

	/**
	 * create <DIV> element
	 * 
	 * @param id - div id
	 * @param display - display style ('', 'none', etc)
	 * @param border - border settings
	 *
	 * @return div element
	 */	
	createDiv: function(id, display, border) {
		decorateDiv = document.createElement('DIV');
		decorateDiv.id = id;
		decorateDiv.style.position = 'absolute';
		decorateDiv.style.display = display;
		if (border) {
			decorateDiv.style.border = border;
		}
		
		return decorateDiv;
	},
	
	/**
	 * set border to the element
	 *
	 * @param element
	 * @param border
	 *
	 * @return void
	 */
	setBorder: function(element, border) {
		element.style.border = border;
	},

	/**
	 * set element parameters (position and width-height)
	 *
	 * @param element
	 * @param left - left position
	 * @param top - top position
	 * @param width - width of element
	 * @param height - height of element
	 *
	 * @return void
	 */
	setElementParams: function(element, left, top, width, height) {
		element.style.width = width + 'px';
		element.style.height = height + 'px';
		element.style.left = left + 'px';
		element.style.top = top + 'px';
	},
	
	/**
	 * create <IMG> element
	 *
	 * @param src - image source file
	 * @param altText - alternate text
	 *
	 * @return img element
	 */
	createImg: function(src, altText) {
		var img = document.createElement('IMG');
		img.src = src;
		img.alt = altText;
		
		return img;
	},
	
	/**
	 * remove given element from document
	 *
	 * @param element
	 *
	 * @return void
	 */
	removeElement: function(element) {
		if (typeof(element)!='object') { return; }
		element.parentNode.removeChild(element);
	}

});

/**
 * class - eventManager
 *
 * manipulating with events
 */
var EventManager = Browser.extend({

	/**
	 * constructor
	 * initialize parent class (Browser) 
	 * set up event parameters
	 *
	 * @param event - event name (e.g. 'onclick', 'onload', etc)
	 * @param handler - string name of function-handler 
	 * @param objName - name of object which contain `handler` function
	 *
	 * @return void
	 */
	construct: function(event, handler, objName) {
		this.initBrowserDetection();
		this.event = event;
    	if (this.isIE()) {
			this.handler = eval(handler);
		} else {
	    	this.handler = objName + '.' + handler + '();';
		}
	},

	/**
	 * return classic (not class) function name from function pointer
	 *
	 * @param Fn - pointer to the function 
	 *
	 * @return function name
	 */
	getClassicFuncName: function(Fn) {
		return Fn.toString().match(/( \w+)/)[0];
	},

	/**
	 * add event handler
	 *
	 * @param element - element on which event handler should be placed
	 *
	 * @return void
	 */
	addEvent: function(element) {
		if (this.isIE()) {
			if (this.event == 'onscroll') {
				eval('element' + '.' + this.event + '=' + this.handler);
			} else {
				element.attachEvent(this.event, this.handler);
     		}
       	} else { // others
       		element.setAttribute(this.event, this.handler.toString());
       	}
	},
	
	/**
	 * remove event handler
	 *
	 * @param element
	 *
	 * @return void
	 */
	removeEvent: function(element) {
		if (this.isIE()) {
       		if (this.event == 'onscroll') {
       			element.onscroll = '';
       		} else {
	       		element.attachEvent(this.event, '');
       		}
       	} else { // others
       		element.setAttribute(this.event, '');
       	}
	},
	
	/**
	 * get scroll X position
	 *
	 * @return scroll X pos (px)
	 */
	getScrollXPos: function() {
		if( document.documentElement && document.documentElement.scrollLeft ) {
			return document.documentElement.scrollLeft;
		}
		if( document.body && document.body.scrollLeft ) {
			return document.body.scrollLeft;
		}
		if( window.pageXOffset ) {
			return window.pageXOffset;
		}
		if( window.scrollX ) {
			return window.scrollX;
		}
		return 0;
	},

	/**
	 * get scroll Y position
	 *
	 * @return scroll Y pos (px)
	 */	
	 getScrollYPos: function() {
		if( document.documentElement && document.documentElement.scrollTop ) {
			return document.documentElement.scrollTop;
		}
		if( document.body && document.body.scrollTop ) {
			return document.body.scrollTop;
		}
		if( window.pageYOffset ) {
			return window.pageYOffset;
		}
		if( window.scrollY ) {
			return window.scrollY;
		}
		return 0;
	},
	
	/**
	 * scroll scroller to selected position
	 *
	 * @param position - target scroll position
	 *
	 * @return void
	 */
	scrollTo: function(position) {
		if( document.documentElement && document.documentElement.scrollTop ) {
			document.documentElement.scrollTop = position;
		}
		if( document.body && document.body.scrollTop ) {
			document.body.scrollTop = position;
		}
		if( window.pageYOffset ) {
			window.pageYOffset = position;
		}
		if( window.scrollY ) {
			window.scrollY = position;
		}
	},
	
	/**
	 * get scroll bottom position
	 *
	 * @return bottom scroll position (px)
	 */
	getScrollBottom: function() {
		if( document.documentElement && document.documentElement.scrollTop ) {
			return document.documentElement.scrollHeight;
		}
		if( document.body && document.body.scrollTop ) {
			return document.body.scrollHeight;
		}
		if( window.pageYOffset ) {
			return window.scrollHeight;
		}
		if( window.scrollY ) {
			return window.scrollHeight;
		}
	}
});

/**
 * class - layer manager
 * mainpulate with layers (detect crossing)
 */
var LayerManager = Browser.extend({

	/**
	 * constructor
	 * initialize parent class (Browser) 
	 */
	construct: function(elementUnder, elementOver) {
		this.initBrowserDetection();
		this.elementUnder = elementUnder;
		this.elementOver = elementOver;
	},
	
	/**
	 * find left element position
	 *
	 * @param obj - element which position is required
	 *
	 * @return left element position in px (relative to window)
	 */
	findLeftPos: function(obj) {
		var curleft = 0;
		if (obj.offsetParent) {
			curleft = obj.offsetLeft
			while (obj = obj.offsetParent) {
				curleft += obj.offsetLeft
			}
		}
		return curleft;
	},
	
	/**
	 * find top element position
	 *
	 * @param obj - element which position is required
	 *
	 * @return top element position in px (relative to window)
	 */	
	 findTopPos: function(obj) {
		var curtop = 0;
		if (obj.offsetParent) {
			curtop = obj.offsetTop
			while (obj = obj.offsetParent) {
				curtop += obj.offsetTop
			}
		}
		return curtop;
	},
	
	/**
	 * detect is layers with two elements crossing or not
	 *
	 * @return boolean
	 */
	isElementsOverriding: function() {
		minUTop  = this.findTopPos(this.elementUnder);
		minULeft = this.findLeftPos(this.elementUnder);
		maxUTop  = this.elementUnder.clientHeight + minUTop;
		maxULeft = this.elementUnder.clientWidth + minULeft;

		minOTop  = this.findTopPos(this.elementOver);
		minOLeft = this.findLeftPos(this.elementOver);
		maxOTop  = this.elementOver.clientHeight + minOTop;
		maxOLeft = this.elementOver.clientWidth + minOLeft;		

		if (maxULeft < minOLeft) { return false; }
		if (minULeft > maxOLeft) { return false; }

		if (maxUTop < minOTop) { return false; }
		if (minUTop > maxOTop) { return false; }
		
		if ((minULeft < maxOLeft && maxULeft >= minOLeft) &&
			(minUTop < maxOTop && maxUTop >= minOTop)) 
				{ return true; }
		return false;
	}
});
