/* © Ильюша Абельчаков. http://www.ilyuha.ru/ */
var _MC = new MC();
function MC() {
	var _this = this;
	/* BROWSERS */
	/* IE or not IE :) */
	this.isIe = function() {
		if( document.all && !self.opera )
			return true;
		else
			return false;
	},
	this.isFF = function() {
		if( navigator.appVersion.indexOf('Chrome')<0 && navigator.appVersion.indexOf('Safari')<0 && navigator.appName.toLowerCase() == 'netscape' )
			return true;
		else
			return false;
	},
	this.isOpera = function() {
		if( self.opera )
			return true;
		else
			return false;
	},
	this.isSafari = function() {
		if( navigator.appVersion.indexOf('Chrome')<0 && navigator.appVersion.indexOf('Safari')>0 && navigator.appName.toLowerCase() == 'netscape' )
			return true;
		else
			return false;
	},
	this.isChrome = function() {
		if( navigator.appVersion.indexOf('Chrome')>0 && navigator.appName.toLowerCase() == 'netscape' )
			return true;
		else
			return false;
	},
	
	/* Browser */
	this.BrowserHeight = function() {
		return _this.isIe() ? document.documentElement.clientHeight*1 : document.body.clientHeight*1;
	},
	this.BrowserScroll = function() {
		return _this.isIe() ? document.body.parentElement.scrollTop*1 : window.scrollY*1;
	},
	this.BrowserVersion = function() {
		var oBrowser = {
			'browser':'',
			'version':0
		}
		if( _this.isIe() ) {
			var aStr = navigator.userAgent.split('MSIE');
			oBrowser['browser'] = 'IE';
			oBrowser['version'] = parseFloat(aStr[1]);
		}
		if( _this.isFF() ) {
			var aStr = navigator.userAgent.split('Firefox/');
			oBrowser['browser'] = 'FF';
			oBrowser['version'] = parseFloat(aStr[1]);
		}
		if( _this.isOpera() ) {
			var aStr = navigator.userAgent.split('Opera/');
			oBrowser['browser'] = 'Opera';
			oBrowser['version'] = parseFloat(aStr[1]);
		}
		if( _this.isSafari() ) {
			var aStr = navigator.userAgent.split('Version/');
			oBrowser['browser'] = 'Safari';
			oBrowser['version'] = parseFloat(aStr[1]);
		}
		if( _this.isChrome() ) {
			var aStr = navigator.userAgent.split('Chrome/');
			oBrowser['browser'] = 'Chrome';
			oBrowser['version'] = parseFloat(aStr[1]);
		}
		return oBrowser;
	},
	
	/* CLASSES */
	this.MatchClass = function( oElem, sClass ) {
		/*
		oElem - ссылка на объект
		sClass - имя класса
		*/
		/* Проверяем наличие класса у объекта */
		var oRegExp = oElem.className.match( (new RegExp("(^|\\s+)("+sClass+")($|\\s+)")) );
		var bClass = ( sClass && oElem.className && oElem.className.length && oRegExp );
		return bClass;
	},
	this.SetClass = function( oElem, sClass, sInstead ) {
		/*
		oElem - ссылка на объект
		sClass - имя класса, на которое меняется текущий класс
		sInstead - имя класса, который меняем
		в случае, например, убирания класса, sClass = ' ';
		*/
		/* Проводим замену класса объекта */
		if( oElem ){
			sClass = (sClass.length) ? sClass.replace(/(^\s+|\s+$)/, '') : '';
			if( oElem.className.length ){
				var sOld = sClass;
				if( sInstead && sInstead.length ){
					sInstead = sInstead.replace( /\s+(\S)/g, "|$1" );
					if( sOld ){
						sOld += "|";
					}
					sOld += sInstead;
				}
				var oRegExp = new RegExp("(^|\\s+)(" + sOld +")($|\\s+)", "g");
				oElem.className = oElem.className.replace( oRegExp, "$1" );
			}
			oElem.className += ( oElem.className.length && sClass ? " " : "" ) + sClass;
		}
	},
	
	/* Strings */
	this.Trim = function( sStr ) {
		/* Обрезание лишних пробелов по в начале и в конце строки - sStr */
		var sValue='';
		if( sStr != '' ) {
			sValue = sStr.replace(/^(\s)*/g, '');
			sValue = sStr.replace(/(\s)*$/g, '');
		}
		return sValue;
	},
	this.RandomStr = function() {
		var sStr = 'abcdefghiklmnopqrstvxyzABCDEFGHIKLMNOPQRSTVXYZ0123456789';
		var iStrLen = sStr.length-1;
		var sRandom = '';
		for(var q=0; q<12; q++) {
			var iRand=Math.floor(Math.random()*iStrLen);
			sRandom += sStr[iRand];
		}
		return sRandom;
	},
	
	/* DOM */
	this.AddNode = function( oParent, sName, aParams, sContent ) {
		/*
		oParent - ссылка на родительский объект, возможна также передача id объекта
		sName - имя создаваемого тега
		aParams - массив с атрибутами (['id=elem_id','class=reducer'])
		sContent - текстовое содержимое елемента
		*/
		/* Добавление нового тега в DOM-дерево. Возвращает ссылку на новосозданный объект */
		var oParent = (typeof oParent == 'string') ? $(oParent) : ( (typeof oParent == 'object') ? oParent : null );
		sName = sName.toUpperCase();
		var oNode = document.createElement(sName);
		oParent.appendChild(oNode);
		
		var iLen = aParams.length;
		for(var a=0; a<iLen; a++) {
			var aAttr = aParams[a].split('=');
			var sAttrName = aAttr[0];
			var sAttrVal = (aAttr[1] == '') ? '' : aAttr[1];
			if(sAttrName=='class' && sAttrVal!='')
				oNode.className = sAttrVal;
			else
				oNode.setAttribute(sAttrName, sAttrVal);
		}
		
		if(sName.toLowerCase() != 'iframe' && sName.toLowerCase() != 'table' && sName.toLowerCase() != 'img') {
			oNode.innerHTML = sContent;
		}
		return oNode;
	},
	this.DeleteNode = function( oParent, oDelNode ) {
		/*
		oParent - ссылка на родительский объект, возможна также передача id объекта
		oDelNode - ссылка на удаляемый объект, возможна также передача id объекта
		*/
		/* Удаляет элемент из DOM-дерева */
		var oParent = (typeof oParent == 'string') ? $(oParent) : ( (typeof oParent == 'object') ? oParent : null );
		var oDelNode = (typeof oDelNode == 'string') ? $(oDelNode) : ( (typeof oDelNode == 'object') ? oDelNode : null );
		if(oParent && oDelNode)
			oParent.removeChild(oDelNode);
	},
	this.EvenOddElems = function( oParent ) {
		/*
		oParent - ссылка на родительский объект, возможна также передача id объекта
		*/
		/*
		Собирает ссылки на четные и нечетные вложенные элементы.
		Возвращает объект с 2-я массивами (odd и even).
		*/
		var oParent = (typeof oParent == 'string') ? $(oParent) : ( (typeof oParent == 'object') ? oParent : null );
		var oElems = {'even':[],'odd':[]};
		var aNodes = [];
		for( var j=0, iLen = oParent.childNodes.length; j<iLen; j++ ) {
			if ( oParent.childNodes[j].nodeType == 1 )
				aNodes.push(oParent.childNodes[j]);
		}
		for( var i=0, iLen = aNodes.length; i<iLen; i++ ) {
			if( i%2 == 0 )
				oElems['odd'].push(aNodes[i]);
			else
				oElems['even'].push(aNodes[i]);
		}
		return oElems;
	},
	this.ParentNode = function( oElem, sId, sClass, sName ) {
		/*
		oElem - ссылка на объект, у которого следует проверить наличие родителся с заданными параметрами
		sId - id элемента, который выше по дереву
		sClass - class элемента, который выше по дереву
		sName - имя тега элемента, который выше по дереву
		*/
		/* Поиск элемента выше текущего по дереву элементов по id, имени тега или классу */
		var bId = (sId) ? false : true;
		var bClass = (sClass) ? false : true;
		var bName = (sName) ? false : true;
		while(oElem) {
			oElem = oElem.parentNode;
			if(sId && sId == oElem.id)
				bId = true;
			if(sClass && this.MatchClass(oElem, sClass))
				bClass = true;
			if(sName) {
				if(sName.toUpperCase() == oElem.nodeName.toUpperCase())
					bName = true;
			}
			if(bId && bClass && bName)
				return oElem;
		}
		return oElem;
	},
	this.Coords = function( oElem ) {
		/*
		oElem - ссылка на объект, у которого следует проверить наличие родителся с заданными параметрами
		*/
		/* Координаты элемента на странице. Считаются от левого верхнего угла страницы. */
		var oCoords = {
			iTop  : 0,
			iLeft : 0
			};
		while(oElem) {
			oCoords.iTop += oElem.offsetTop;
			oCoords.iLeft += oElem.offsetLeft;
			oElem = oElem.offsetParent;
		}
		return oCoords;
	},
	/* table */
	/* row */
	this.AddRow = function( oTable, index, aAttributes, aTd, iLimit, bFollowLimit ) {
		/*
		oTable - ссылка на таблицу или id таблицы в которую добавляем строку
		index - индекс строки в таблице, возможны также индексы first и last, для установки строки первой или последней в таблице
		aAttributes - массив с атрибутами (['id=elem_id','class=reducer'])
		aTd - массив с объектом содержащим данные по атрибутам и содержимому ячеек таблицы ( {'attr':['class=td_class','id=td_id'],'content':содержимое} )
		iLimit - максимальное количество строк в таблице.
		bFollowLimit - использовать значение максимального количества строк в таблице. В случае bFollowLimit==true при добавлении новых строк в таблицу будут удаляться строки из начала или с конца таблицы (в зависимости от значения index, если строка вставляется не в конец таблицы - удаляется последняя).
		*/
		/* Добавляет строку (можно с ячейками) в таблицу */
		var oTbl = (typeof oTable == 'string') ? $(oTable) : ( (typeof oTable == 'object') ? oTable : null );
		if(!oTbl)
			return;
		var iIndex = (index == 'first') ? 0 : ( (index == 'last') ? oTbl.rows.length : index ) ;
		var oCurrRow = oTbl.insertRow(iIndex);
		var iLen = aAttributes.length;
		for(var a=0; a<iLen; a++) {
			var aAttr = aAttributes[a].split('=');
			var sAttrName = aAttr[0];
			var sAttrVal = (aAttr[1] == '') ? '' : aAttr[1];
			if(sAttrName=='class' && sAttrVal!='')
				oCurrRow.className = sAttrVal;
			else
				oCurrRow.setAttribute(sAttrName, sAttrVal);
		}
		for( var j=0, iLn=aTd.length;j<iLn; j++ ) {
			this.AddCell(oCurrRow, j, aTd[j]['attr'], aTd[j]['content']);
		}
		if(bFollowLimit) {
			if( oTbl.rows.length > iLimit ) {
				if( index == 'last' || iIndex>(oTbl.rows.length-1) )
					this.DelRow(oTbl, 0);
				else
					this.DelRow(oTbl, oTbl.rows.length-1);
			}
		}
	},
	this.DelRow = function( oTable, index ) {
		/*
		oTable - ссылка на таблицу или id таблицы в которой удаляем строку
		index - индекс строки в таблице
		*/
		/* Удаление строки из таблицы */
		var oTbl = (typeof oTable == 'string') ? $(oTable) : ( (typeof oTable == 'object') ? oTable : null );
		oTbl.deleteRow(index);
	},
	this.RowIndex = function( oRow ) {
		/*
		oRow - ссылка на строку или её id
		*/
		/* Возврат индекса строки в таблице */
		var oRow = (typeof oRow == 'string') ? $(oRow) : ( (typeof oRow == 'object') ? oRow : null );
		return oRow.rowIndex;
	},
	/* cell */
	this.AddCell = function( oTr, index, aAttributes, sContent ) {
		/*
		oTr - ссылка на строку таблицы или id строки таблицы в которую добавляем ячейку
		index - индекс ячейки в строке
		aAttributes - массив с атрибутами (['id=elem_id','class=reducer'])
		sContent - содержимое ячейки таблицы
		*/
		/* Добавляет ячейку в строку таблицы */
		var oTr = (typeof oTr == 'string') ? $(oTr) : ( (typeof oTr == 'object') ? oTr : null );
		if(!oTr || oTr==null)
			return;
		var oCurrCell = oTr.insertCell(index);
		oCurrCell.innerHTML = sContent;
		var iALen = aAttributes.length;
		for(var a=0; a<iALen; a++) {
			var aAttr = aAttributes[a].split('=');
			var sAttrName = aAttr[0];
			var sAttrVal = (aAttr[1]=='') ? '' : aAttr[1];
			if(sAttrName=='class' && sAttrVal!='')
				oCurrCell.className = sAttrVal;
			else
				oCurrCell.setAttribute(sAttrName, sAttrVal);
		}
	},
	this.DelCell = function( oTr, index ) {
		/*  */
		return false;
	},
	
	/* URL */
	this.GET = function () {
		/* Сбор гет параметров из урла страницы. Возвращает хэш с данными */
		var sPrams = unescape(location.search);
		if(sPrams.substr(0, 1) == '?')
			sPrams = sPrams.substr(1);
		var aParts = sPrams.split('&');
		var oGet = {};
		for(var j=0, iLength = aParts.length; j<iLength; j++) {
			var aElems = aParts[j].split('=');
			oGet[aElems[0]] = aElems[1];
		}
		return oGet;
	},
	this.GetHash = function() {
		/* Получить значение хеша страницы */
		return location.hash.substr(1);
	},
	this.SetHash = function( sHash ) {
		/*
		sHash - новое значение хеша страницы
		*/
		/* Устанавливает новое значение хеша страницы */
		var sCurrHash = _this.GetHash();
		if(sHash != sCurrHash)
			location.hash = sHash;
	},
	
	/* EVENTS */
	this.bDocumentReady = false,
	this.DocumentReady = function( aFns ) {
		if(_this.bDocumentReady)
			return;
		_this.bDocumentReady = true;
		if( _this.isIe() ) {
			document.write("<script id=__ie_onload defer src=javascript:void(0)>");
			document.write("<\/script>");
			var script = document.getElementById("__ie_onload");
			script.onreadystatechange = function() {
				if (this.readyState == "complete") {
					for(var i=0, iLn=aFns.length; i<iLn; i++) {
						aFns[i]();
					}
				}
			}
		}
		if( _this.isFF() || _this.isOpera() ) {
			_this.AddEvent(
				document,
				{'DOMContentLoaded': function() {
					document.removeEventListener( 'DOMContentLoaded', arguments.callee, false );
					for(var i=0, iLn=aFns.length; i<iLn; i++) {
						aFns[i]();
					}
				}},
				false
			);
		}
		if( _this.isSafari() || _this.isChrome() ) {
			var _timer = setInterval(function() {
				if (/loaded|complete/.test(document.readyState)) {
					clearInterval(_timer);
					delete _timer;
					for(var i=0, iLn=aFns.length; i<iLn; i++) {
						aFns[i]();
					}
				}
			}, 10);
		}
	}	,
	this.EventList = [] /* массив, в который записуются устанавливаемые обработчики событий */,
	this.AddEvent = function( oElem, oParams, bCapture ) {
		/*
		oElem - ссылка на элемент, на который вешается обработчик событий
		oParams - хеш, где ключем выступает событие, значением - функция
		bCapture - осанавливать или нет всплытие событий
		*/
		/* Добавление обработчика событий на элемент */
		for(var j in oParams) {
			var bIsType = _this.AddEventList(oElem, j, oParams[j]);
			if( _this.isIe()) {
				if(!bIsType) {
					oElem.attachEvent('on'+j, oParams[j]);
					window.event.cancelBubble = true;
					window.event.returnValue = false;
				}
			}
			else
				oElem.addEventListener(j, oParams[j], bCapture);
		}
	},
	this.DelEvent = function(oElem, oParams, bCapture) {
		/*
		oElem - ссылка на элемент, с которого удаляется обработчик событий
		oParams - хеш, где ключем выступает событие, значением - функция
		bCapture - осанавливать или нет всплытие событий
		*/
		/* Удаление обработчика событий с элемента */
		for(var j in oParams) {
			if( _this.isIe())
				oElem.detachEvent('on'+j, oParams[j]);
			else
				oElem.removeEventListener(j, oParams[j], bCapture);
			_this.DelEventList(oElem, j, oParams[j]);
		}
	},
	this.AddEventList = function( oElem, sType, sFunck ) {
		/*
		oElem - ссылка на элемент, на который вешается обработчик событий
		sType - событие
		sFunck - функция вызываемая в случае возникновения события
		*/
		/* Запись в массив добавляемого события */
		var aList = _this.EventList;
		var iELen = aList.length;
		var bIsEvent = false;
		for(var i=0; i<iELen; i++) {
			if(aList[i].inArray(oElem) && aList[i].inArray(sType) && aList[i].inArray(sFunck))
			/* if(aList[i][0] == oElem && aList[i][1] == sType && aList[i][2] == sFunck) */
				bIsEvent = true;
		}
		if(!bIsEvent) {
			aList.push([oElem, sType, sFunck]);
		}
		return bIsEvent;
	},
	this.DelEventList = function( oElem, sType, sFunck ) {
		/*
		oElem - ссылка на элемент, с которого удаляется обработчик события
		sType - событие
		sFunck - функция вызываемая в случае возникновения события
		*/
		/* Удаления из массива события */
		var aList = _this.EventList;
		var iELen = aList.length;
		for(var i=iELen-1; i>=0; i--) {
			if(aList[i].inArray(oElem) && aList[i].inArray(sType) && aList[i].inArray(sFunck))
			/* if(aList[i][0] == oElem && aList[i][1] == sType && aList[i][2] == sFunck) */
				aList.splice(i, 1);
		}
	},
	
	//Drag & Drop
	this.bHor = true,
	this.bVer = true,
	this.oDElem = null,
	this.oStartPoint = {'x': 0, 'y': 0},
	this.MouseCoords = {'x': 0, 'y': 0},
	
	this.onDrugFunc = null,
	this.onStopDrugFunc = null,
	
	this.MCoords = function( event ) {
		if( _this.isIe() || _this.isOpera() ) {
			_this.MouseCoords['x'] = window.event.clientX*1 + document.documentElement.scrollLeft*1 + document.body.scrollLeft*1;
			_this.MouseCoords['y'] = window.event.clientY*1 + document.documentElement.scrollTop*1 + document.body.scrollTop*1;
		}
		else {
			_this.MouseCoords['x'] = event.clientX + window.scrollX;
			_this.MouseCoords['y'] = event.clientY + window.scrollY;
		}
	},
	this.StartDrug = function( oElem, oFunk, bHorizontal, bVertical, ev ) {
		//Атрибуты:
		//1. Объект
		//2. Функции {'ondrug': func(), 'onstopdrug': funcEnd()}
		//3. bool можно ли перемещать по горизонтали
		//4. bool можно ли перемещать по вертикали
		//5. bool захват
		_this.bHor = bHorizontal;
		_this.bVer = bVertical;
		_this.oDElem = oElem;
		var iLeft = ( isNaN( parseInt(_this.oDElem.style.left) ) ) ? 0 : parseInt(_this.oDElem.style.left);
		var iTop = ( isNaN( parseInt(_this.oDElem.style.top) ) ) ? 0 : parseInt(_this.oDElem.style.top);
		if(ev) {
			_this.MCoords(ev);
			_this.oStartPoint['x'] = parseInt(_this.MouseCoords['x'] - iLeft);
			_this.oStartPoint['y'] = parseInt(_this.MouseCoords['y'] - iTop);
			if( !_this.isIe() ) {
				ev.preventDefault();
			}
		}
		_this.AddEvent(
			document,
			{
				'mousemove': _this.OnDrug,
				'mouseup': _this.StopDrug
			},
			true
		);
		
		if(oFunk['ondrug']) {
			_this.onDrugFunc = oFunk['ondrug'];
		}
		if(oFunk['onstopdrug']) {
			_this.onStopDrugFunc = oFunk['onstopdrug'];
		}
	},
	this.OnDrug = function( event ) {
		_this.MCoords(event);
		/*
		_this.oStartPoint - стартовые координаты курсора мыши
		_this.MouseCoords - текущие координаты курсора мыши
		*/
		var iCurrLeft = ( isNaN( parseInt(_this.oDElem.style.left) ) ) ? 0 : parseInt(_this.oDElem.style.left);
		var iCurrTop = ( isNaN( parseInt(_this.oDElem.style.top) ) ) ? 0 : parseInt(_this.oDElem.style.top);
		if( _this.bHor ) {
			iCurrLeft = _this.MouseCoords['x'] - _this.oStartPoint['x'];
		}
		if( _this.bVer ) {
			iCurrTop = _this.MouseCoords['y'] - _this.oStartPoint['y'];
		}
		if ( _this.isIe() ) {
			window.event.cancelBubble = true;
			window.event.returnValue = false;
		}
		else {
			event.preventDefault();
		}
		
		if( _this.onDrugFunc )
			_this.onDrugFunc(iCurrLeft, iCurrTop);
		
	},
	this.StopDrug = function( event ) {
		_this.DelEvent(
			document,
			{
				'mousemove':_this.OnDrug,
				'mouseup':_this.StopDrug
			},
			true
		);
		var iCurrLeft = ( isNaN( parseInt(_this.oDElem.style.left) ) ) ? 0 : parseInt(_this.oDElem.style.left);
		var iCurrTop = ( isNaN( parseInt(_this.oDElem.style.top) ) ) ? 0 : parseInt(_this.oDElem.style.top);
		if( _this.bHor ) {
			iCurrLeft = _this.MouseCoords['x'] - _this.oStartPoint['x'];
		}
		if( _this.bVer ) {
			iCurrTop = _this.MouseCoords['y'] - _this.oStartPoint['y'];
		}
		if( _this.onStopDrugFunc )
			_this.onStopDrugFunc(iCurrLeft, iCurrTop);
		
		_this.oDElem = null;
		_this.oStartPoint = {'x': 0, 'y': 0};
		_this.MouseCoords = {'x': 0, 'y': 0};
		_this.onDrugFunc = null;
		_this.onStopDrugFunc = null;
	}
};

Array.prototype.inArray = function( value ) {
	/* Проверяет содержится ли значение в массиве */
	for (var i=0, iLn=this.length; i<iLn; i++) {
		if (this[i] == value)
			return true;
	}
	return false;
}

function $(sId) {
	/* Шо-то делает */
	return (document.all) ? document.all(sId) : document.getElementById(sId);
}

/* AJAX */
var _AJAX = function( sUrl, sMethod, sFunction, sParams ) {
	/*
	sUrl - url на который посылается запрос
	sMethod - метод get или post
	sFunction - функция-обработчик выполняемая в слычае ответа 200 сервера
	sParams - параметры, необходимо для post запросов
	*/
	/* Посылка запроса на сервер */
	sMethod = (typeof sMethod == 'undefined') ? 'GET' : sMethod;
	sFunction = (typeof sFunction == 'undefined') ? false : sFunction;
	sParams = (typeof sParams == 'undefined') ? ( ( _MC.isIe() ) ? '' : null ) : sParams;
	
	var _this = this;
	
	 
	if( _MC.isIe() ) {
		try {
			this.oLoad = new ActiveXObject("Msxml2.XMLHTTP");
		}
		catch (e) {
			try {
				this.oLoad = new ActiveXObject("Microsoft.XMLHTTP");
			}
			catch (E) {
				this.oLoad = false;
			}
		}
	}
	else {
		this.oLoad = new XMLHttpRequest();
	}
	
	if (this.oLoad) {
		this.oLoad.open(sMethod, sUrl, true);
		if (sMethod.toLowerCase() == 'post') {
			this.oLoad.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
			this.oLoad.setRequestHeader("Content-length", sParams.length);
			this.oLoad.setRequestHeader("Connection", "close");
		}
		this.oLoad.setRequestHeader("X-Requested-With", "XMLHttpRequest");
		if (sFunction) {
			this.AnswerFunc = sFunction;
			this.ReqTimer = null;
			this.oReqState = function() {
				/* Получаем состояние готовности сервера выдать ответ */
				if(_this.ReqTimer != null) {
					clearTimeout(_this.ReqTimer);
				}
				
				if(_this.oLoad.readyState == 4) {
					if (_this.oLoad.status == 200) {
						_this.AnswerFunc(_this.oLoad);
					}
					clearTimeout(_this.ReqTimer);
					_this.ReqTimer = null;
				}
				else {
					_this.ReqTimer = setTimeout(_this.oReqState, 10);
				}
			}
			this.oReqState();
		}
		this.oLoad.send( unescape(sParams) );
	}
	else
		return false;
}