var last_shown_error = false;
var errors = new Object();
var first_error = new Object();
var fields = new Object();
function show_form_error(prefix, field, sticky)
{
	if (isset(errors[prefix]) && isset(errors[prefix][field])) {
		span = document.getElementById('error_msg_'+prefix);
		span.innerHTML = fields[prefix][field] + ' - ' + errors[prefix][field];
		if (sticky) last_shown_error = field;
	}
}
function hide_form_error(prefix)
{
	span = document.getElementById('error_msg_'+prefix);
	if (!span) return;
	span.innerHTML = '<br/>';
	if (typeof(last_shown_error) != 'undefined' && last_shown_error) {
		show_form_error(prefix, last_shown_error);
	}
}
function add_form_error(prefix, field, element, error_msg) {
	if (error_msg != '') {
		if (typeof(errors[prefix]) == 'undefined') {
			errors[prefix] = new Object();
		}
		errors[prefix][field] = error_msg;

		if (document.getElementById(element)) {
			// some controls don't have element to focus on (e.g. swf uploader)
			addEvent(
				document.getElementById(element),
				'focus',
				function() {
					show_form_error(prefix, field, true)
				}
			);
			addEvent(
				document.getElementById(element),
				'blur',
				function() {
					last_shown_error = false
				}
			);
		}
		/*else {
			console.log('error: focusing failed for [', prefix, '.', field, '] = ', element);
		}*/

		if (typeof(first_error[prefix]) == 'undefined' || first_error[prefix] == false) {
			first_error[prefix] = [field, element];
		}
	}
}

function FCKeditor_OnComplete( editor )
{
	Form.Resize();
}

function InitEditors() {
	if ( !$.isEmptyObject($CKEditors) ) {
		// process all CKEditor instances
		CKEDITOR.on(
			'instanceReady',
			function( ev ) {
				FCKeditor_OnComplete( CKEDITOR.instances[ ev.editor.name ] );
			}
		)

		for (var $editor_id in $CKEditors) {
			CKEDITOR.replace($editor_id, $CKEditors[$editor_id]);
		}
	}

	// process all CodePress instances
	if ($.isFunction(window.CodePress)) {
		CodePress.run(/*FCKeditor_OnComplete*/);
	}
}

function Form() {}

Form = new Form();

Form.Controls = new Array();
Form.Div = false;
Form.MinControlsHeight = 0;
Form.Options = new Object();
Form.FlexibleCount = 0;

Form.ScrollerW = 17;
Form.ScrollerH = 17;
Form.HasChanged = false;

Form.Init = function(id) {
	this.Div = document.getElementById(id);
	if (!this.Div) {
		return ;
	}

	for (var i = 0; i < this.Controls.length; i++) {
		dim = getDimensions( document.getElementById(this.Controls[i]) );
		options = this.Options[this.Controls[i]];

		if (options.height) { // fixed height
			options.min_height = options.height;
			options.max_height = options.height;
		}

		if (!options.min_height) {
			options.min_height = $( jq('#' + this.Controls[i]) ).outerHeight(); // dim.innerHeight
		}

//		if ( $( jq('#' + this.Controls[i]) ).parents('tr:first').is(':visible') ) {
			this.MinControlsHeight += options.min_height;
//		}

		if (dim.innerHeight < options.min_height) {
			document.getElementById(this.Controls[i]).style.height = options.min_height+'px';
		}
//		alert('adding element '+this.Controls[i]+' height: '+options.min_height+' total: '+this.MinControlsHeight)
	}

	// all <script> tags will be executed again after wrap method is called, so remove them to prevent that
	$('script', this.Div).remove();
	$(this.Div).wrap('<div id="' + this.Div.id + '_container" style="position: relative; overflow: auto; width: 100%;"></div>');

	Application.removeDebuggerStatistics();

	this.Table = $('table:first', this.Div).get(0);
	this.Table.style.height = 'auto';
//	this.Table.style.width = 'auto';
	this.MinHeight = this.Table.offsetHeight;
	this.MinWidth = this.Table.offsetWidth;

//	alert('Measuring min width now')

	addEvent(window, 'resize', function() {Form.Resize()})

	this.Resize(false);

	if (isset(first_error)) {
		for (var i in first_error) {
			if (first_error[i] != false) {
				if (document.getElementById(first_error[i][1])) {
					// some controls don't have element to focus on (e.g. swf uploader)
					document.getElementById(first_error[i][1]).focus();
				}
				show_form_error(i, first_error[i][0], true);
//				alert('focused on '+first_error[i][1])
			}
		}
	}

	if (_Simultanious_Edit_Message != '') {
		alert(_Simultanious_Edit_Message);
	}

	this.InitOnChange();

	Application.processHooks('m:OnAfterFormInit');
	InitEditors();
}

Form.InitOnChange = function()
{
	var inputs = window.document.getElementsByTagName('INPUT');
	var selects = window.document.getElementsByTagName('SELECT');
	var textareas = window.document.getElementsByTagName('TEXTAREA');

	var groups = [inputs, selects, textareas];

	for (var g=0; g<groups.length; g++) {
		for (var i=0; i<groups[g].length; i++) {
			var elem = groups[g][i];
			if (elem.tagName == 'INPUT' && elem.type == 'hidden') continue;
			addEvent(elem, elem.type=='button' ? 'click' : 'change', function() {Form.Changed()});
		}
	}
}

Form.Changed = function()
{
	this.HasChanged = true;
}

Form.addControl = function(id, options) {
	this.Controls.push(id);
	if (!options) {
		options = {coeff: 1, max_height: 0, min_height: 0};
	}
	else {
		if (typeof(options['coeff']) == 'undefined') options['coeff'] = 1;
		if (typeof(options['max_height']) == 'undefined') options['max_height'] = 0;
		if (typeof(options['min_height']) == 'undefined') options['min_height'] = 0;
	}
	options['real_height'] = 0;
	this.Options[id] = options; // for future use
//	print_pre(this.Options[id]);
}

Form._parseSize = function ($size) {
	if ($size.toString().match(/^([\d]+)px$/)) {
		return parseInt(RegExp.$1);
	}

	return parseInt($size);
}

Form.Resize = function($init_done) {
	if (!this.Div) {
		return ;
	}

	if ( ($init_done === true || $init_done === undefined) && !$.isEmptyObject($CKEditors) ) {
		// process all CKEditor instances
		for (var $editor_id in $CKEditors) {
			var $ckeditor_textarea = $( '#' + jq($editor_id) );
			CKEDITOR.instances[ $editor_id ].resize( $ckeditor_textarea.width(), $ckeditor_textarea.height() );
		}
	}

	var h = (document.all ? window.document.body.offsetHeight : window.innerHeight);

	var $div = $(this.Div);
	var pos = $div.offset();

	h -= pos.top;

	if (this.Div.style.height.length) {
		// height set for scroll_container overrides automatic container height detection
		h = this._parseSize(this.Div.style.height);
	}

	if ($div.attr('mode') == 'minimal') {
		// height will become minimal required (when data height is smaller, then window)
		h = this.MinHeight;
	}

	h -= ($div.outerHeight() - $div.height());

	//	alert('h after correction is '+h);

	/*
	// use this 2 lines, instead of next 3 lines, when scrolling without popups needed
	var w = $(window.document.body).outerWidth(false);
	w -= ($div.outerWidth() - $div.width());*/

	window.document.body.style.width = '100%';
	var w = (document.all ? window.document.body.offsetWidth : window.innerWidth);

	w -= pos.left + ($div.outerWidth() - $div.width());

	scroller_height = this.MinWidth > w ? this.ScrollerH : 0; // width of 1st table in scroll_container is larger, then window width?
	scroller_width =  this.MinHeight > h - scroller_height ? this.ScrollerW : 0; // table height > total height - scroller_height -> vertical scroller is found
	scroller_height = this.MinWidth > w - scroller_width ? this.ScrollerH : 0; // table width > total width - scroller_width -> horizontal scroller is found

	var st = document.getElementById('width_status');
	if (st) st.innerHTML = 'minWdith: '+this.MinWidth+' minHeight: '+this.MinHeight+' w: '+w+' h: '+h+' scroll_w: '+scroller_width+' scroll_h: '+scroller_height;

//	alert('scroller W x H = '+scroller_width+' x '+scroller_height);

//	alert('resize: '+w+'x'+h)

	this.Table.style.width = (w-scroller_width) + 'px';

	this.Div.parentNode.style.width = w + 'px';
	this.Div.style.width = (w-scroller_width) + 'px';
	this.Div.parentNode.style.height = h + 'px';

	var count = this.Controls.length;

	// -count here is adjustment - 1px for each control
	var split = h /*- (count * 2)*/ - this.MinHeight + this.MinControlsHeight;

	if (split < this.MinControlsHeight) {
		split = this.MinControlsHeight;
	}

	this.ResetHeights();
	var used = this.SetMinHeights();

	split -= used;

	var cur_diff = 0;
	var iterations = 0;
	do {
		var prev_diff = cur_diff;
		var cur_diff = this.SplitExtra(split);
		split = cur_diff;
		iterations++;
	} while (cur_diff != 0 && cur_diff != prev_diff && iterations < 10);

	for (var i = 0; i < this.Controls.length; i++) {
		document.getElementById(this.Controls[i]).style.height = this.Options[ this.Controls[i] ]['real_height'] + 'px';
//		document.getElementById(this.Controls[i]).value = this.Options[this.Controls[i]]['real_height'];
	}

//	alert('h is: '+h+' min height is '+this.MinHeight+' MinControlsHeight is '+this.MinControlsHeight+' -> '+split+' to split between '+count);
//	print_pre(this.Controls)
}

Form.ResetHeights = function()
{
	for (var i = 0; i < this.Controls.length; i++) {
		var options = this.Options[this.Controls[i]]
		options['real_height'] = 0;
		options.fixed = false;
	}
	this.FlexibleCount = this.Controls.length;
}


// Enlarge heights when possible
// Return any not split pixels number
Form.SplitExtra = function(split) {
	var number = 0;

	for (var i = 0; i < this.Controls.length; i++) {
		var options = this.Options[ this.Controls[i] ];
		if (options['max_height'] == 0 || options['real_height'] < options.max_height) {
			number++;
		}
	}

	if (number == 0) {
		return 0;
	}

	var delta = Math.floor(split / number);
//	alert('splitting '+split+' between '+number+' delta is '+delta)
	var added = 0;
	for (var i = 0; i < this.Controls.length; i++) {
		var options = this.Options[this.Controls[i]];
		var to_add;
		if (options['max_height'] != 0 && options['real_height'] + delta > options['max_height']) {
			to_add = options['max_height'] - options['real_height'];
		}
		else {
			to_add = delta;
		}
//		alert('delta: '+delta+' current real: '+options['real_height']+' min: '+options['min_height']+' max:'+options['max_height']+' to_add: '+to_add)
		options['real_height'] = options['real_height'] + to_add;
		added += to_add;
	}
//	alert('added total '+added)

	// removing extra added from the last (any) control
	if (added > split) {
		extra = added - split;
		options['real_height'] -= extra;
		added -= extra;
	}
	return split - added;
}

Form.SetMinHeights = function()
{
	var used = 0;
	for (var i = 0; i < this.Controls.length; i++) {
		var options = this.Options[this.Controls[i]]
		if (options['real_height'] < options['min_height']) {
			options['real_height'] = options.min_height;
			used += options.min_height;
		}
	}
	return used;
}