idCache = {};

function GetById (itemId) {
    var cached = idCache[itemId];
    if (!cached) {
        cached = document.getElementById (itemId);
        idCache[itemId] = cached;
    }
    return cached;
}

function CheckAll(event, name){
    if (!event) event = window.event;
    var control = event.target || event.srcElement;
    var frm = control.form; 
    if(!frm) return;
    var i;
    var e;
    var state = control.checked;
    var title = state ? 'Отменить выделенные' : 'Выделить все';

    for (i = 0; i < frm.elements.length; i++) {
        e = frm.elements[i];
        if (e.type == 'checkbox' && e.name == name) {
            e.checked = state;
        }
    }
}

function CheckGroup(event, name, group_id){
    if (!event) event = window.event;
    var control = event.target || event.srcElement;
    var frm = control.form;
    if(!frm) return;
    var i;
    var e;
    var state = control.checked;
    var title = state ? 'Отменить выделенные' : 'Выделить все';

    for (i = 0; i < frm.elements.length; i++) {
        e = frm.elements[i];
        if (e.type == 'checkbox' && e.name == name && e.id == group_id ) {
            if (e.checked != state) {
                e.checked = state;
            }
        }
    }
}


function CheckAmountOfCheckboxes(event, max) {

    if (!event) event = window.event;
    var control = event.target || event.srcElement;
	
	var frm = control.form;
	var checked_ammount = 0;
    for (i = 0; i < frm.elements.length; i++) {
		e = frm.elements[i];
        if (e.type == 'checkbox' && e.checked == 1) {
			checked_ammount++;
		}
	}
	if (checked_ammount > max) {
		alert ('Нельзя выбирать более '+max+' позиций');
		return false;
	}
	return true;
}

function CheckSeorostRules() {
	var chkbx = GetById('promote_rules');
	if (chkbx.checked != 1) {
		return confirm('Если Вы не согласны с условиями продвижения, то Ваш выбор запросов будет отменён. Продолжить?');
	}
	return 1;
}

function CheckLinesAmount(max) {
	if (max == '') {
		return true;
	}
    var frm = event.srcElement.form;
	var count = 0;
    for (i = 0; i < frm.elements.length; i++) {
		e = frm.elements[i];
		if (e.type == 'textarea') {
			var text = e.value;
			var entries = text.split(/[\r\n,\s+]/g);
			for (j = 0; j < entries.length; j ++) { 
				if (entries[j].length) {
					count ++;
				}
			}
			if (count > max) {
				alert('Вы ввели слишком много зеркал');
				return false;
			}
			return true;
		}
	}
	return false;
}

function AddWithAlias (url) {
	var withalias = confirm('Хотите ли вы также добавить алиас вместе с этим сайтом?');
	if (withalias) {
		window.location = url + '&add_aliases=1';
		return;
	}
	window.location = url;
}
function ChangeVis(element, target, url){
    var block = GetById(target);
    if(!block) return;

    if(!window.loader) window.loader = new net.ContentLoader();
    var str = '';
    for (i in element) {
        str += i + '\n';
    }
    if (element.innerText == '+') {
        window.loader.loadXMLDoc(url, target);
        element.innerHTML = '&#150;'
    } else {
        element.innerText = '+';
        block.innerHTML = '';
    } 
}


function Show (element) {
    if (!element.style) {
        element = GetById (element);
    }
	if (element) {
	    element.style.display = 'block';
	}
}

function Hide (element) {
    if (!element.style) {
        element = GetById (element);
    }
    if (element) {
	    element.style.display = 'none';
	}
}

function ShowHide (element) {
    if (!element.style) {
        element = GetById (element);
    }

    if (element.style.display == 'block') {
		element.style.display = 'none'
	} else {
		element.style.display = 'block'
	}
}

function ShowModalForm (formId) {
    Show (formId);
    var shadow = GetById ('shadow');
	var login_form = GetById ('login');
	var window_height = document.compatMode=='CSS1Compat' && !window.opera?document.documentElement.clientHeight:document.body.clientHeight;
	var page_height = GetYScroll() + 10;
	var result_height = window_height > page_height ? window_height : page_height;
    shadow.style.height = result_height + 'px'; 
    Show (shadow);
//	Hide ('flash_graph');
    Show ('modal');
	login_form.elements[0].focus();
}

function HideModalForm (formId) {
    Hide (formId);
    Hide ('shadow');
    Hide ('modal');
//	Show ('flash_graph');
}

if (document.getElementById) {
		document.onkeydown = escapekey;
}

function escapekey(e) {
    var code;
    if (!e) e = window.event;
    if (e.keyCode) code = e.keyCode;
    else if (e.which) code = e.which;
    if ((code == 27) && (e.ctrlKey == false) && (e.altKey == false)) {
		HideModalForm('modal');
		HideFaq();
	}
}


function SetInput () {
    for(var i = 0; i < arguments.length; i++) {
        GetById (arguments[i]).value = arguments[++i];
    }
}

function SetScalar () {
    for(var i = 0; i < arguments.length; i++) {
        GetById (arguments[i]).innerHTML = arguments[++i];
    }
}

function GetYScroll() {
    yScroll = 0;

    if (window.innerHeight && window.scrollMaxY || window.innerWidth && window.scrollMaxX) {
	    yScroll = window.innerHeight + window.scrollMaxY;
	    xScroll = window.innerWidth + window.scrollMaxX;
	
	    var deff = document.documentElement;
	    var wff = (deff&&deff.clientWidth) || document.body.clientWidth || window.innerWidth || self.innerWidth;
	    var hff = (deff&&deff.clientHeight) || document.body.clientHeight || window.innerHeight || self.innerHeight;
	
	    xScroll -= (window.innerWidth - wff);
	    yScroll -= (window.innerHeight - hff);
    } else if (document.body.scrollHeight > document.body.offsetHeight || document.body.scrollWidth > document.body.offsetWidth) { // all but Explorer Mac
	    yScroll = document.body.scrollHeight;
	    xScroll = document.body.scrollWidth;
    } else { // Explorer Mac...would also work in Explorer 6 Strict, Mozilla and Safari
	    yScroll = document.body.offsetHeight;
	    xScroll = document.body.offsetWidth;
    }

    return yScroll;
}

function getOffsetY()
{
  return self.pageYOffset || (document.documentElement && document.documentElement.scrollTop) || (document.body && document.body.scrollTop);
}

function PrepareChecked (form, targetFormId, controlName) {
    var values = {};
    var valuesCount = 0;
    for (i = 0; i < form.length; i ++) {
        var currField = form[i];
        if (currField.type != 'checkbox') continue;
        if (currField.checked) {
            values[currField.value] = 1;
            valuesCount ++;
        }
    }
    
    if (!valuesCount) {
        alert ("Вами не указан ни один элемент. Выберите как минимум один и намите на кнопку еще раз.");
        return 0;
    }
    
    var targetForm = GetById (targetFormId);
    //targetForm

    var baseInput = targetForm[controlName];
    
    var first = 1;
    
    for (var key in values) {
        if (first) {
            baseInput.setAttribute ('value', key);
            first = 0;
            continue;
        }
        var clone = baseInput.cloneNode (1);
        clone.setAttribute ('value', key);
        targetForm.appendChild (clone);
    }
    
    return 1;
}

function GetCookie (name) {
	
	var start = document.cookie.indexOf (name + "=");
	var len = start + name.length + 1;
	if ((!start) && (name != document.cookie.substring (0, name.length))) {
		return null;
	}
	if (start == -1) return null;
	var end = document.cookie.indexOf(";", len);
	if (end == -1)
		end = document.cookie.length;
	return unescape( document.cookie.substring (len, end));
}

// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

function ToggleDetails (id, src) {
	
	obj = src.parentNode.parentNode;
	if (!obj) return;

	var str = src.innerHTML;

	var nextObj = obj.nextSibling;
	if (nextObj && nextObj.tagName == 'TR' && nextObj.className == 'details_' + id) {
		//src.innerHTML = str.replace('-', '+');
		obj.parentNode.removeChild(nextObj);
		return;
	}

	//src.innerHTML = str.replace('+', '-');
	
	var detailsObj = GetById('details_' + id);
	if (!detailsObj) return; 

	var tr = document.createElement('TR');
	tr.className = 'details_' + id;
	var td = document.createElement('TD');
	
	td.innerHTML = detailsObj.innerHTML;
	td.setAttribute('colspan', detailsColspan);
	td.colSpan = detailsColspan; // for IE
	td.className = 'site_info';

	tr.appendChild(td);
	obj.parentNode.insertBefore(tr, obj.nextSibling);
	
}


var dom = (document.getElementById) ? true : false;
var ns5 = (!document.all && dom || window.opera) ? true: false;
var ie5 = ((navigator.userAgent.indexOf("MSIE")>-1) && dom) ? true : false;
var ie4 = (document.all && !dom) ? true : false;

var offX = 25;
var offY = 10; 

var t1,t2;	// for setTimeouts

function PopupDetails (event, siteId, object) {
	var infoBlock   = GetById ('info-popup');
	var infoContent = GetById ('info-popup-content');
	if (!(infoBlock && infoContent)) return;
	
	var infoStyle = infoBlock.style;
	
	if (object.className != 'site') {
		var sibling = object.previousSibling;
		while (sibling.className != 'site') {
			sibling = sibling.previousSibling;
		}
		object = sibling;
	}
	
	// we show info block before get it width;
	infoContent.innerHTML = GetById ('details_'+siteId).innerHTML;
	infoStyle.display = 'block';
	
	/*var infoW = (ie4||ie5)? infoBlock.clientWidth: infoBlock.offsetWidth;
	var infoH = (ie4||ie5)? infoBlock.clientHeight: infoBlock.offsetHeight;
	var infoL = (ie4||ie5)? object.clientLeft: object.offsetLeft;*/
	var infoW = infoBlock.offsetWidth;
	var infoH = infoBlock.offsetHeight;
	var infoL = object.offsetLeft + object.offsetParent.offsetLeft;

	infoStyle.left = infoL+offX;
	
	if (t1) clearTimeout(t1);
	if (t2) clearTimeout(t2);

	//create reference to common "body" across doctypes
	var standardBody = (document.compatMode=="CSS1Compat")
		? document.documentElement
		: document.body;
	
	var mouseX, mouseY, winW, winH;
	
	if (ns5) {
		mouseX = event.pageX;
		mouseY = event.pageY;
		winW = window.innerWidth-20 + window.pageXOffset;
		winH = window.innerHeight-20 + window.pageYOffset;
	} else {
		mouseX = window.event.clientX + standardBody.scrollLeft;
		mouseY = window.event.clientY + standardBody.scrollTop;
		winW = standardBody.clientWidth + standardBody.scrollLeft;
		winH = standardBody.clientHeight + standardBody.scrollTop;
	}
	
	/*if ((mouseX+offX+infoW)>winW) {
		infoStyle.left = mouseX-(infoW+offX)+"px";
	} else {
		infoStyle.left = mouseX+offX+"px";
	}*/
	
	if ((mouseY+offY+infoH)>winH) { 
		infoStyle.top = mouseY-(infoH+offY)+"px";
		infoBlock.className = 'upper';
	} else {
		infoStyle.top = mouseY+offY+"px";
		infoBlock.className = '';
	}
	
	infoContent.innerHTML += '';
}

function PopdownDetails () {
	var infoBlock = GetById ('info-popup');
	var infoStyle = infoBlock.style;

	infoStyle.display = 'none';
}


function ShowFaq (href, height) {
    var y = getOffsetY();

    HideFaq();
	
    var ifr = document.createElement('IFRAME');
    ifr.setAttribute('id', 'faq_div');
    ifr.setAttribute('frameBorder', 'no');
    ifr.setAttribute('scrolling', 'no');
    ifr.src = href;
    ifr.style.top = y + 135 + 'px';
	if (height) {
	    ifr.style.height = height;
	};
    document.body.appendChild(ifr);
    ifr.style.display = 'block';
    return false;
}

function HideFaq() {
    var iframe = document.getElementById('faq_div');
    if (iframe) {
        document.body.removeChild(iframe);
    }
}

function set_fullday (wday) {
    var input_field = GetById(wday);
    input_field.value = '00:00-23:59';
    return 0;
}

function isEnterKey (event) {
	return (event.keyCode == 13);
}

function load_url (href, id) {
	var Loader = new Ajax.Updater(id, href, {method: 'get'});
}

function load_ajax_page(id, url, param) {
	if (!param) {
		param = $H(url.toQueryParams());
		var arrChunks = url.split('?');
		url = arrChunks[0];
	}
	param.set('rnd', Math.floor(Math.random()*1000));
	
	var Loader = new Ajax.Updater(
		id,
		url,
		{
			parameters: param
		}
	);

	$(id).scrollTo();
}

var strModalWindow;

function escapeKeyDown (e) {
	var element = Event.element(e);
	if (strModalWindow && e.keyCode == 27) {
		hideModalWindow(strModalWindow);
	}
}

function showModalWindow (id) {
	var element = $(id);
	if (element) {
		var shadow = $('shadow');
		if (shadow) {
			var window_height = document.compatMode=='CSS1Compat' 
				&& !window.opera
				?document.documentElement.clientHeight
				:document.body.clientHeight;
			var page_height = GetYScroll() + 10;
			var result_height = window_height > page_height ? window_height : page_height;
//			shadow.style.height = result_height + 'px';
			Show('shadow');
			Show(id);
		}

		var v = document.viewport;
		var intLeft = parseInt(v.getWidth() / 2 - element.getWidth() / 2);
		var intTop = parseInt(v.getHeight() / 3 - element.getHeight() / 2);
		element.setStyle({
			'top' : intTop + 'px',
			'left' : intLeft + 'px'
		});
		return true;
	}
	return false;
}

function hideModalWindow (id) {
	var element = $(id);
	if (element) {
		if (element.onHide) {
			element.onHide();
		}
		Hide(id);
	}
	Hide('shadow');
}


var PageObjects = $H();
var flashMovie = new Object();

function amChartInited (chart_id) {
	flashMovie[chart_id] = document.getElementById(chart_id);
}
	

var Control = Class.create({
	initialize: function (args) {
		args = $H(args);
		this.dataset_id = args.get('dataset_id');
		this.id = this.getFullId(args.get('id'));
	},
	getFullId: function (id) {
		return this.dataset_id + ':' + id;
	},
	dataset: function () {
		return PageObjects.get(this.dataset_id);
	}
});

var CheckboxControl = Class.create(Control, {
	initialize: function ($super, args) {
		$super(args);
		this.name = args.get('id');
		this.update();	
	},
	update: function () {
		var table = this.dataset().table();
		if (table) {
			var checkboxes = table.select('input[type="checkbox"]');
			var id = this.id;
			
			for (var i = 0; i < checkboxes.length; i ++) {
				var element = checkboxes[i];
				if (element.id.startsWith(id)) {
					Event.observe(element, 'click', this.checkboxClick.bind(this));
				}
			}
		}
	},
	checkboxClick: function (event) {
		var element = Event.element(event);
		if (element) {
			var option = new Option(element.id);
			var paramValue = option.value;
			var paramName = this.name;
			
			this.dataset().usePage = 1;
			if (element.checked) {
				this.dataset().updateParam(paramName, paramValue);
			} else {
				this.dataset().updateParam(paramName, '-' + paramValue);
			}
			this.dataset().usePage = 0;
		}
	}
});

var CheckboxSubmitControl = Class.create(Control, {
	initialize: function ($super, args) {
		$super(args);
		this.checkbox_id = args.get('checkbox_id');
		this.action = args.get('action') || 'update';
		var obj = $(this.id);
		if (obj) {
			this.obj = obj;
			Event.observe(obj, 'click', this.buttonClick.bind(this));
		}
	},
	buttonClick: function (event) {
		var elements = this.getElements(true);
		var length = elements.length;
		if (length > 0) {
			var ids = [];
			var update = (this.action == 'update');
			var name = this.checkbox_id;
			for (var i = 0; i < length; i ++) {
				var element = elements[i];
				var option = new Option(element.id);
				if (update) {
					ids.push(option.value);
				} else {
					element.name = this.checkbox_id;
					element.value = option.value;
				}
			}
			if (this.action == 'update') {
				this.dataset().updateParam(this.checkbox_id, ids);
			} else {
				var Form = this.obj.form;
				var fields = [this.dataset().bypass, this.dataset().state];
				for (var i = 0; i < fields.length; i++) {
					var bypass = fields[i]; 
					if (bypass) {
						var keys = bypass.keys();
						for (var k = 0; k < keys.length; k ++) {
							var name = keys[k];
							if (Form[name]) {
								Form[name].disabled = true;
							}
							var value = bypass.get(name);
							var input = document.createElement('INPUT');
							input.setAttribute('type', 'hidden');
							input.setAttribute('name', name);
							input.setAttribute('value', value);
							Form.appendChild(input);
						}
					}
				}
				Form.submit();
			}
		} else {
			alert('Не выделено ни одной позиции в списке!');
		}
	},
	getElements: function (checked) {
		var table = this.dataset().table();
		if (table) {
			var elements = [];
			var pattern = this.getFullId(this.checkbox_id);
			var checkboxes = table.select('[type="checkbox"]');
			for (var i = 0; i < checkboxes.length; i ++) {
				var checkbox = checkboxes[i];
				if (checkbox.id && checkbox.id.startsWith(pattern)) {
					if (!checked || checkbox.checked) {
						elements.push(checkbox);
					}
				}
			}
			return elements;
		}
		return [];
	}
}); 

var Chart = Class.create(Control, {
	initialize: function ($super, args) {
		$super(args);
		args = $H(args);
		this.id = args.get('id');
		this.legend = $('graph_legend');
		this.data_url = args.get('data_url') || 'graph.html';
	},
	updateData: function (args) {
		var param = $H();
		var groups = [this.dataset().bypass, args];
		for (var g = 0; g < groups.length; g ++) {
			var group = groups[g];
			var keys = group.keys();
			for (var i = 0; i < keys.length; i ++) {
				var key = keys[i];
				param.set(key, group.get(key));
			}
		}
		param.set('rnd', Math.floor(Math.random()*1000));

		new Ajax.Request(
			this.data_url,
			{
				parameters: param,
				onSuccess: function (response) {
					if (response.responseText) {
						if (this.legend) {
							var startLegend = response.responseText.indexOf('<table');
							var legendText = response.responseText.substr(startLegend);
							if (legendText) {
								this.legend.innerHTML = legendText;
							}
						}
					}
					flashMovie[this.id].setData(response.responseText);
					var controls = this.dataset().controlObjects;
					for (var i = 0; i < controls.length; i ++) {
						var control = controls[i];
						if (control.type == 'graph_legend' || control.type == 'chartbox') {
							control.updateByChart();
						}
					}
				}.bind(this),
				onComplete: function (response) {
					flashMovie[this.id].setParam('background.file', 'white.jpg');
				}.bind(this)
			}
		);
	},
	setParam: function (name, value) {
		flashMovie[this.id].setParam(name, value);
	},
	setData: function (str) {
		flashMovie[this.id].setData(str);
	}
});

var ChartControl = Class.create(Control, {
	initialize: function ($super, args) {
		$super(args);
		this.chart_id = args.get('chart_id');
		this.id = 'graph:' + args.get('id');
		
		if (!this.chart()) {
			this.createChart();
		}
		this.param = args.get('name');	
		this.scrollToGraph = true;
	},
	createChart: function () {
		PageObjects.set(
			this.chart_id, 
			new Chart({'id':this.chart_id,'dataset_id':this.dataset_id})
		);
	},
	chart: function () {
		return PageObjects.get(this.chart_id);
	},
	updateId: function (id) {
		this.updateChart(this.param, id);
	},
	updateChart: function (name, value) {
		if (this.scrollToGraph) {
			window.scroll(0,0);
		}
		var param = $H();
		param.set(name, value);
		this.prepareChart();
		this.chart().updateData(param);
	},
	updateTitle: function (value) {
		var param = 'labels.label[0].text';
		var title = this.title;
		if (title) {
			var chunks = title.split(' ');
			chunks[chunks.length - 1] = value;
			title = chunks.join(' ');
			this.title = title;
			this.chart().setParam(param, '<b>' + title + '</b>');
		}
	},
	prepareChart: function () {
		this.chart().setParam('background.alpha', '50');
		this.chart().setParam('background.file', 'loading_chart_data.jpg');
	}
});

var ChartboxControl = Class.create(ChartControl,{ 
	initialize: function ($super, args) {
		$super(args);
		this.scrollToGraph = false;
		this.param = args.get('id');
		this.limit = parseInt(args.get('limit'));
		this.count = parseInt(args.get('count'));
		this.id = this.dataset_id + ':' + this.param;
		this.update();
	},
	controlType: function () {return 'checkbox'},
	updateBoxes: function (setEvent) {
		var table = this.dataset().table();
		if (table) {
			var checkboxes = table.select('input[type="' + this.controlType() + '"]');
			var id = this.id;
			
			var disable = (this.count >= this.limit);
			for (var i = 0; i < checkboxes.length; i ++) {
				var element = checkboxes[i];
				if (element.id.startsWith(id)) {
					if (setEvent) {
						Event.observe(element, 'click', this.checkboxClick.bind(this));
						Event.observe(element, 'chartbox:uncheck', this.checkboxUncheck.bind(this));
					}
					if (element.checked || !disable) {
						element.disabled = false;
					} else {
						element.disabled = true;
					}
				}
			}
		}
	},
	update: function () {
		this.updateBoxes(true);
	},
	updateByChart: function () {
		this.updateBoxes(false);
	},
	checkboxClick: function (event) {
		var element = Event.element(event);
		if (element) {
			var option = new Option(element.id);
			var paramValue = option.value;
			
			if (element.checked) {
				if (this.count < this.limit) {
					this.count ++;
					this.updateId(paramValue);
				} else {
					element.checked = false;
					element.disabled = true;
				}
			} else {
				this.updateId('-' + paramValue);
				this.count --;
			}
		}
	},
	checkboxUncheck: function (event) {
		this.count --;
	}
});

var ChartboxRadioControl = Class.create(ChartboxControl, {
	initialize: function ($super, args) {
		$super(args);
		this.title = args.get('title');
	},	
	controlType: function () {return 'radio'},
	updateChart: function ($super, name, value) {
		$super(name, value);
		this.updateTitle(value);
	},
	checkboxClick: function (event) {
		var element = Event.element(event);
		if (element) {
			var option = new Option(element.id);
			var paramValue = option.value;
			
			if (element.checked) {
				this.updateId(paramValue);
			} 
		}
	}
});

var Controls = $H({
	checkbox: CheckboxControl,
	checkbox_submit: CheckboxSubmitControl,
	serp_top: Class.create(Control, {
		initialize: function ($super, args) {
			$super(args);
			var id = this.id;
			var obj = $(id);
			if (obj) {
				var positions = $(id + '0');
				var engines = $(id + '1');
				if (positions && engines) {
					this.positions = positions;
					this.engines = engines;
					this.updateVisibility();
					Event.observe(positions.id, 'change', this.valueChange.bind(this));
					Event.observe(engines.id, 'change', this.valueChange.bind(this));
				}
			}
			this.updateType = 'none';
		},
		updateVisibility: function () {
			this.engines.style.visibility = this.positions.selectedIndex > 1 
				? 'visible' : 'hidden';
		},
		valueChange: function (event) {
			var param = $H();
			var positions = this.positions;
			var position = this.positions.value;
			param.set(positions.name, positions.value);
			var engines = this.engines;
			var engineName = engines.name;
			if (positions.selectedIndex > 1) {
				param.set(engineName, engines.value);
			} else {
				this.dataset().deleteState(engineName);
			}
			this.dataset().update(param);
			this.dataset().setState(param);
			this.updateVisibility();
		}
	}),
	accept: Class.create(Control, {
		initialize: function ($super, args) {
			$super(args);
			var id = this.id;
			var obj = $(id);
			var checkbox = $(id + '_checkbox');
			if (obj && checkbox) {
				Event.observe(obj, 'click', this.buttonClick.bind(this));
				this.checkbox = checkbox;
				this.name = obj.name;
			}
		},
		buttonClick: function (event) {
			var param = $H();
			param.set(this.name, 1);
			var checkbox = this.checkbox;
			param.set(checkbox.name, checkbox.checked ? 1 : 0);
			var elements = checkbox.form.elements;
			var promoteParam = 'q';
			var affectedParam = 'qq';
			var promoteValues = [];
			var affectedValues = [];
			for (var i = 0; i < elements.length; i ++) {
				var element = elements[i];
				if (element.type == 'checkbox' && element.name == promoteParam) {
					var value = element.value;
					if (element.checked) {
						promoteValues.push(value);
					} 
					affectedValues.push(value);
				}
			}
			param.set(promoteParam, promoteValues);
			param.set(affectedParam, affectedValues);
			this.dataset().update(param);
		}
	}),
	chartbox: ChartboxControl,
	chartbox_radio: ChartboxRadioControl,
	graph_legend: Class.create(ChartControl, {
		initialize: function ($super, args) {
			$super(args);
			this.scrollToGraph = false;
			this.exportFile = args.get('export');
			this.exportParam = args.get('exportParam');
			this.update();
		},
		update: function () {
			var box = $('graph_legend');
			if (box) {
				var elements = box.select('img');
				for (var i = 0; i < elements.length; i ++) {
					var element = elements[i];
					Event.observe(element, 'click', this.imageClick.bind(this));
					Event.observe(element, 'mouseover', this.mouseOver.bind(this));
					Event.observe(element, 'mouseout', this.mouseOut.bind(this));
				}
			}
		},
		updateByChart: function () {
			this.update();
			var box = $('graph_legend');
			if (box) {
				var colors = box.select('img');
				var elements = box.select('td[class="legend"]');
				if (elements.length > 0) {
					var args = [];
					var paramName = 'l';
					for (var i = 0; i < elements.length; i ++) {
						var element = elements[i];
						var color = colors[i].style.backgroundColor;
						var title = element.innerHTML;
						args.push(paramName + '=' + encodeURIComponent(color + ':' + title));
					}
					var url = this.exportFile + '?' + args.join('&');
					this.chart().setParam(this.exportParam, url);
				}
			}
		},
		mouseOver: function (event) {
			this.mouseEvent(event, 'close');
		},
		mouseOut: function (event) {
			this.mouseEvent(event, 'empty');
		},
		mouseEvent: function (event, src) {
			var element = Event.element(event);
			if (element && element.src) {
				element.src = '/image/' + src + '.gif';
			}
		},
		imageClick: function (event) {
			var element = Event.element(event);
			if (element) {
				var option = new Option(element.id);
				var value = option.value;
				var chartbox = $(this.dataset_id + ':' + this.param + '_' + value);
				if (chartbox) {
					chartbox.checked = false;
					chartbox.fire('chartbox:uncheck');
				}
				this.updateId('-' + value);
			}
		}
	}),
	graph_engine: Class.create(ChartControl,{
		initialize: function ($super, args) {
			$super(args);
			this.titles = $H(args.get('titles'));
			this.title = args.get('title');
			var element = $(this.id);
			if (element) {
				Event.observe(element, 'change', this.valueChange.bind(this));
			}
		},
		valueChange: function (event) {
			var element = Event.element(event);
			if (element) {
				this.updateId(element.value);
			}
		},
		updateChart: function ($super, name, value) {
			$super(name, value);
			this.updateTitle(this.titles.get(value));
		}
	}),
	delta_interval: Class.create(Control, {
		initialize: function ($super, args) {
			$super(args);
			this.update();
		},
		valueChange: function (event) {
			var element = Event.element(event);
			if (element) {
				var param = $H();
				param.set(element.name, element.value);
				this.dataset().update(param);
			}
		},
		update: function () {
			var element = $(this.id);
			if (element) {
				Event.observe(element, 'change', this.valueChange.bind(this));
			}
		}
	}),
	graph_links: Class.create(ChartControl,{
		initialize: function ($super, args) {
			$super(args);	
			var box = $(this.id);
			if (box) {
				this.box = box;
				this.update();
			}
		},
		valueChange: function (event) {
			var element = Event.element(event);
			var linkClass = 'link';
			var currentClass = 'current';
			if (element) {
				element.removeClassName(linkClass);
				element.addClassName('current');
				Event.stopObserving(element, 'click');
				var links = this.getElements();

				var oldIndex;
				var newIndex;
				for (var i = 0; i < links.length; i ++) {
					var link = links[i];
					if (link.id != element.id) {
						if (link.hasClassName(currentClass)) {
							oldIndex = i;
							link.removeClassName('current');
							link.addClassName('link');
						}
					} else {
						newIndex = i;
					}
				}

				var option = new Option(element.id);
				if (newIndex == 0 || oldIndex == 0) {
					var param = this.dataset().bypass;
					param.set(this.param, option.value);
					var chunks = location.href.split('?');
					var urlPath = chunks[0];
					this.prepareChart();
					document.location.href = urlPath + '?' + param.toQueryString();
				} else {
					this.dataset().bypass.set(this.param, option.value);
					this.updateId(option.value);
					this.update();
				}
			}
		},
		getElements: function () {
			return this.box.select('SPAN');
		},
		update: function () {
			var elements = this.box.select('SPAN');
			for (var i = 0; i < elements.length; i++) {
				var element = elements[i];
				if (element.hasClassName('link')) {
					Event.observe(element, 'click', this.valueChange.bind(this));
				} else {
					var option = new Option(element.id);
					this.current = option.value;
				}
			}
		}
	})
});


var Option = Class.create({
	initialize: function (elementId) {
		var arrChunks = elementId.split(':');
		arrChunks = arrChunks[1].split('_');
		var optionName = arrChunks.shift();
		var paramName;
		if (optionName == 'exp') {
			paramName = '_' + arrChunks.shift();
		} else {
			paramName = optionName;
		}
		this.paramName = paramName;
		this.value = arrChunks.join('_');
	}
});


function createRecordset (args) {
	var recordset = new Recordset(args);
	if (recordset) {
		PageObjects.set(recordset.id, recordset);
		recordset.initControls();
	}
}

function getRecordset (id) {
	return Recordsets.get(id);
}

var Recordset = Class.create({
	initialize: function (args) {
		args = $H(args);
		this.id = args.get('id');
		var url = args.get('url');
		this.url = url ? url : this.id + '.html';
		var bypass = args.get('bypass');
		if (!bypass) {
			bypass = $H();
		} 
		this.bypass = $H(bypass);
		var options = args.get('options') || [];
		options.push('exp');
		this.options = options;
		this.optionSelector = '.option'
		this.expandSelector = '.icon';

		this.controls = $H(args.get('controls') || {});

		this.sortId = 0;
		this.page = 1;
		this.pageParam = 'p';
		this.sortParam = args.get('sort_param') || 'o';
		var bypassKeys = this.bypass.keys();
		for (var i = 0; i < bypassKeys.length; i ++) {
			var key = bypassKeys[i];
			if (key == this.pageParam || key == this.sortParam) {
				this.bypass.unset(key);
			}
		}
		this.searchParam = 'search';
		this.initProgressCapture();
//		this.initControls();
		this.state = $H();
	},
	initControls: function () {
		this.initDisplayArea();
		this.initPager();
		this.initHeaders();
		this.initOptions();
		this.initSearchControl();
		this.initCopyText(); 
		var controls = this.controls;
		var keys = controls.keys();
		if (this.loaded) {
			var objects = this.controlObjects;
			for (var i = 0; i < objects.length; i ++) {
				var object = objects[i];
				if(object.update) {
					object.update();
				}
			}
		} else {
			this.controlObjects = [];
			for (var i = 0; i < keys.length; i ++) {
				var key = keys[i];
				var definition = Controls.get(key);
				if (definition) {
					var classObj = Class.create(definition);
					var args = $H(controls.get(key));
					args.set('dataset_id', this.id);
					var control = new classObj(args);
					control.type = key;
					this.controlObjects.push(control);
				}
			}
			this.loaded = 1;
		}
	},
	initPager: function () {
		var box = $(this.createId('pager'));
		if (box) {
			var elements = box.select('[class="link"]');
			for (var i = 0; i < elements.length; i ++) {
				var element = elements[i];
				if (element.id) {	
					Event.observe(element, 'click', this.pageLinkClick.bind(this));
				}
			}
		} else {
			var inputPage = $(this.createId('input_page'));
			if (inputPage) {
				this.page = inputPage.value;
				this.usePager = true;
				Event.observe(inputPage.id, 'keydown', this.inputPageKeyDown.bind(this));
			}
			var controls = new Array('first', 'last', 'back', 'forward');
			for (var i = 0; i < controls.length; i ++) {
				var controlName = controls[i];
				var controlId = this.createId(controlName);
				var element = $(controlId);
				if (element && element.name) {
					Event.observe(controlId, 'click', this.pageButtonClick.bind(this));
				}
			}
		}
	},
	inputPageKeyDown: function (event) {
		var element = Event.element(event);
		if (element && isEnterKey(event)) {
			var page = element.value;
			if (isNaN(page) || page < 1) {
				alert('Недопустимое значение!');
			} else {
				this.goPage(page);
			}
		}
	},
	pageButtonClick: function (event) {
		var element = Event.element(event);	
		if (element && element.name) {
			Event.stopObserving(element.id, 'click');
			this.goPage(element.name);
		}	
	},
	pageLinkClick: function (event) {
		var element = Event.element(event);
		if (element) {
			Event.stopObserving(element.id, 'click');
			var option = new Option(element.id);
			this.goPage(option.value);
		}
	},
	initProgressCapture: function () {
		var capture = this.getProgressCapture();
		if (capture) {
			capture.hide();
			capture.innerHTML = '<p>идёт загрузка...</p>';
			capture.absolutize();
		}
	},
	initHeaders: function () {
		var headers = $(this.id).getElementsByClassName('sort_link');
		var headersCount = headers.length;
		if (headersCount > 0) {
			this.useHeaders = true;
			for (var i = 0; i < headers.length; i ++) {
				var header = headers[i];
				Event.observe(header.id, 'click', this.sortLinkClick.bind(this));
			}
		}
	},
	initDisplayArea: function () {
		var scrollObj = $(this.createId('scrollarea'));
		if (scrollObj) {
			var height = document.viewport.getHeight();
			height = height - height/3;
			var objHeight = scrollObj.getHeight();
			if (objHeight > height) {
				scrollObj.setStyle({
					'height' : height + 'px',
					'overflow' : 'auto'
				});
			}
		}
	},
	initSearchControl: function () {
		var searchFieldId = this.createId('search_text');
		var searchField = $(searchFieldId);
		if (searchField) {
			if (!this.searchFieldReady) {
				var objForm = searchField.form;
				if (objForm) {
					this.replaceFormSubmit(objForm);
				}
				this.useSearch = true;
				this.searchParam = 'search';
				this.searchFieldId = searchFieldId;
				this.searchText = searchField.value;
				Event.observe(searchField.id, 'keydown', this.searchTextKeyDown.bind(this));
				var searchButton = $(this.createId('search'));
				if (searchButton) {
					Event.observe(searchButton.id, 'click', this.searchButtonClick.bind(this));
				}
				var cancelButton = $(this.createId('cancel_search'));
				if (cancelButton) {
					Event.observe(cancelButton.id, 'click', this.cancelButtonClick.bind(this));
				}
				this.searchFieldReady = true;
			}
			var searchLinkId = this.createId('search_link');
			var searchLink = $(searchLinkId);
			if (searchLink) {
				this.searchLinkId = searchLinkId;
				Event.observe(searchLinkId, 'click', this.searchLinkClick.bind(this));
			}
		}
	},
	replaceFormSubmit: function (objForm) {
		objForm.setAttribute('onsubmit', 'return false');
	},
	searchLinkClick: function (event) {
		var element = Event.element(event);
		if (element && element.id == this.searchLinkId) {
			this.showSearchBox();
		}
	},
	showSearchBox: function () {
		var windowId = this.createId('search_box');
		var textBoxId = this.createId('search_text');
		var textBox = $(textBoxId);	
		if (textBox && showModalWindow(windowId)) {
			textBox.focus();
			var searchBox = $(windowId);
			searchBox.onHide = function () {
				textBox.value = '';
			};
			Event.observe(document, 'keydown', escapeKeyDown);
			strModalWindow = windowId;
		}
	},
	searchTextKeyDown: function (event) {
		var element = Event.element(event);
		if (element && isEnterKey(event)) {
			this.goSearch(element.value);
		}
	},
	searchButtonClick: function (event) {
		var element = $(this.searchFieldId);
		if (element) {
			this.goSearch(element.value);
		}
	},
	cancelButtonClick: function (event) {
		var element = $(this.searchFieldId);
		if (element) {
			element.value = '';
			this.goSearch('');
		}
	},
	goSearch: function (text) {
		var modalWindow = $(strModalWindow);
		if (modalWindow) {
			if (modalWindow.onHide) {
				modalWindow.onHide = null;
			}
			hideModalWindow(strModalWindow);
		}
		this.searchText = text;
		var param = $H();
		param.set(this.searchParam, text);
		this.update(param);
		this.setState(param);
	},
	table: function () {
		return $(this.createId('table'));
	},
	initOptions: function () {
		var table = this.table();
		if (table) {
			var options = this.options;
			var optionIds = [];
			for (var i = 0; i < options.length; i ++) {
				optionIds.push(this.createId(options[i]));
			}
			
			var arrOptions = table.select(this.optionSelector).concat(table.select(this.expandSelector));

			for (var s = 0; s < arrOptions.length; s ++) {
				var option = arrOptions[s];
				var optionId = option.id;
				if (optionId) {
					for (var i = 0; i < optionIds.length; i ++) {
						if (optionId.startsWith(optionIds[i])) {
							Event.observe(optionId, 'click', this.optionClick.bind(this));	
						}
					}
				}
			}
		}
	},
	optionClick: function (event) {
		var element = Event.findElement(event, this.optionSelector)
			|| Event.findElement(event, this.expandSelector);
		if (element) {
			var elementId = element.id;
			var option = new Option(elementId);
			var param = $H();
			param.set(option.paramName, option.value);
			this.update(param);
		}
	},
	deleteElement: function (id) {
		var param = $H();
		param.set('delete', id);
		this.update(param);
	},
	createId: function (name) {
		return this.id + ':' + name;
	},
	extractId: function (str) {
		var chunks = str.split(':');
		return chunks[1];
	},
	extractValue: function (str) {
		var chunks = this.extractId(str).split('_');
		return chunks[1];
		
	},
	setState: function (param) {
		var keys = param.keys();
		for (var i = 0; i < keys.length; i ++) {
			var key = keys[i];
			this.state.set(key, param.get(key));
		}
	},
	deleteState: function (key) {
		this.state.unset(key);
	},
	update: function (args) {
		if (!args) {
			args = $H();
		}
		var param = $H();
		param.set('_AJAX', Math.floor(Math.random()*1000));
		
		var bypass = this.bypass;
		var keys = bypass.keys();
		for (var i = 0; i < keys.length; i ++) {
			var key = keys[i];
			param.set(key, bypass.get(key));
		}

		var state = this.state;
		keys = state.keys();
		for (var i = 0; i < keys.length; i ++) {
			var key = keys[i];
			if (key == this.pageParam && !this.usePage) {
				continue;
			}
			param.set(key, state.get(key));
		}

		keys = args.keys();
		for (var i = 0; i < keys.length; i ++) {
			var key = keys[i];
			param.set(key, args.get(key));	
		}
	
		var Loader = new Ajax.Updater(
			this.id,
			this.url,
			{
				parameters: param,
				onCreate: function () {
					this.showProgressCapture();
				}.bind(this),
				onComplete: function (response) {
					this.hideProgressCapture();
					this.initControls();
				}.bind(this)
			}
		);
	},
	getProgressCapture: function () {
		var captureId = this.createId('progress');
		return $(captureId);
	},
	showProgressCapture: function () {
		var capture = this.getProgressCapture();
		if (capture) {
			capture.clonePosition($(this.id));
			capture.absolutize();
			capture.show();
		}
	},
	hideProgressCapture: function () {
		var capture = this.getProgressCapture();
		if (capture) {
			capture.hide();
		}
	},
	sortLinkClick: function (event) {
		var element = Event.element(event);
		if (element) {
			var elementId = element.id;
			Event.stopObserving(elementId, 'click');
			this.sort(this.extractValue(elementId));
		}
	},
	updateParam: function (name, value) {
		var param = $H();
		param.set(name, value);
		this.update(param);
	},
	updateIntParam: function (name, value, positive) {
		if (!isNaN(value) && (positive && value > 0 || value != 0)) {
			this.updateParam(name, value);
		}
	},
	goPage: function (page) {
		var paramName = this.pageParam;
		if (isNaN(page)) {
			this.updateParam(paramName, page);
		} else {
			this.updateIntParam(paramName, page, true);
			var state = $H();
			state.set(paramName, page);
			this.setState(state);
		}
	},
	sort: function(sortId) {
		this.updateIntParam(this.sortParam, sortId, false);
	},
	initCopyText: function () {
		var table = $(this.createId('table'));
		var strClass = 'shorten';
		if (table) {
			var elements = table.getElementsByClassName(strClass);

			for (var i = 0; i < elements.length; i ++) {
				var element = elements[i];
				Event.observe(element, 'click', this.copyTextClick.bind(this));	
			}
		}

	},
	copyTextClick: function (event) {
		var element = Event.element(event);
		if (element) {
			var strTitle = element.getAttribute('title');
			if (strTitle) {
				alert(strTitle);
			}
		}
	}
});
