/*******************************************************\
*	JavaScript кроссброузерный интерфейс для работы
*	с окнами, с привычными Drag&Drop функциями, а также
*	минимизацией и закрытием окон.
*   Обеспечена поддержка Firefox (1.5), Opera (9.x), IE (6,7)
*	Windows JS API v.1.5
*	2006 (C) Trushko Kirill (SunZ)
*   Распространяется свободно, с условием соблюдения личных
*	авторских прав (указание реквизитов автора)
*	email: ceaz@yandex.ru
\*******************************************************/

// Настройки пользователя
var DEFAULT_LEFT = 123; // Размещение нового окна по умолчанию
var DEFAULT_TOP = 123;

var count = 0; // счетчик окон
var current_drag; // текущее перемещаемое окно
var backup = new Array(); // массив для бэкапа параметров окон
var container = new WindowContainer( 'container' ); // объект - контейнер, хранилище всех окон
var Windows = new Object(); // хранилище всех созданных объектов Window
var WindowsNames = new Array (); // хранилище имен всех созданных Window

Windowk.prototype.ToString = WindowToString;
WindowContainer.prototype.ToString = WindowContainerToString;
document.onmouseup = WindowMotionDragStop;

// Конструктор объекта - окно
// ( a, b, c, d, e ): a - название,b - имя окна, c - содержание, d - ширина окна ,
// e - высота
function Windowk ( title, name, content, width, height )
{
	this.title = title;
	this.name = name;
	this.content = content;
	this.width = width;
	this.height = height;

	this.id = count;
	this.init = true;
	this.minimized = false;

	this.MouseMove = WindowMotionMouseMove;
	this.MouseDown = WindowMotionMouseDown;
	this.MouseUp = WindowMotionMouseUp;

	count += 1;
}
// Создает окно с входящим заголовком
function WindowNew ( title, name, cont, width, height )
{
	var W;
	var content = "";
	var postfix = "";

	if ( name in WindowsNames )
	{
		alert ( 'Oкно "' + title + '" уже открыто!' );
		return;
	}

	// создаем объект Window с заданными параметрами и сохр в массив окон
	W = new Windowk( title, name, cont, width, height );
	eval ( 'Windows[' + W.id + '] = W;' );
	WindowsNames[name] = W.id;
	container.Backup ( 'backup' );

	container.Add ( W.ToString(), W.id );
	content = container.ToString();
	document.getElementById ( container.id ).innerHTML = content;

	postfix = ( typeof(W.height) !== "number" ) ? "" : "px";
	document.getElementById ( W.id ).style.height = W.height + postfix;
	postfix = ( typeof(W.width) !== "number" ) ? "" : "px";
	document.getElementById ( W.id ).style.width = W.width + postfix;

	container.Backup ( 'restore' );
	container.MouseWatch();

	return W.id;
}
// Проверяет существование окна с таким названием
function WindowExists ( winname )
{
	if ( ! ( winname in WindowsNames ) )
	{
		return false;
	}

	return true;
}

// Обновляет содержимое существующего окна
function WindowRefresh ( winname, content )
{
	if ( ! ( winname in WindowsNames ) )
	{
		return;
	}
    var windw;
	if ( windw = document.getElementById ( 'cont_' + winname ) )
	{
		windw.innerHTML = content;
	}
	else
	{
		alert ( 'Невозможно обновить содержимое окна "' + winname + '"!' );
	}
}

// Конструктор объекта - контейнер
function WindowContainer ( container_id )
{
	this.id = container_id;
	this.divids = new Array (); // Талица с номерам существующих ID блоков
	this.layers = new Array (); // Таблица соответствия ID блока с его Z позицией

	this.Add = WindowContainerAdd;
	this.Remove = WindowContainerRemove;
	this.MouseWatch = WindowDivWatchMouse;
	this.Backup = WindowContainerBackup;
	this.DividsSort = WindowContainerDividsSort;

	return;
}
// Форматирует окно как объект в строку
function WindowToString ()
{
	var div;
	if ( !this.init || this.init != true )
	{
		return "";
	}
	div = "<div id='" + this.id + "' class='window' style='z-index:" + (this.id+1) + ";'>";
	div += "<table class='window_table' id='window_table_" + this.id + "' cellspacing='0'>\n";
	div += "<tr class='window_head' id='window_head_" + this.id + "' onDblClick='WindowMinimize(" + this.id + ")'>";
	div += " <td unselectable='on' align='left' width='90%'>" + this.title + "</td>\n";
	div += " <td unselectable='on' align='right' width='10%'><span class='link' onClick='WindowMinimize(" + this.id + ")'>_</span> <span class='link' onClick='WindowClose(" + this.id + ")'>X</span> </td></tr>\n";
	div += "<tr class='window_content' id='m_" + this.id + "'><td id='cont_" + this.name + "' colspan='2'>" + this.content + "</td></tr>\n";
	div += "</table>\n";
	div += "</div>\n";

	return div;
}
// Закрывает окно с входящим ID
function WindowClose ( id )
{
	if ( typeof ( id ) == 'number' && id >= 0 )
	{
		var abort = false; // Если функция вызываемая ниже вернет true - отменяем закрытие

		// Перед закрытием окна вызовем функцию, которую мог создать разработчик
		// Для обработки события закрытия окна имя которой = windownameClose()
		if ( Windows[id] && Windows[id].name )
		{
			eval ( "var exist = ( window." + Windows[id].name + "Close ) ? true : false;" );
			if ( exist == true )
			{
				eval ( "abort = " + Windows[id].name + "Close()" );
			}
		}
		if ( abort != true )
		{
			document.getElementById ( id ).style.display = 'none';
			container.Remove ( id );
			if ( typeof ( WindowsNames[Windows[id].name] ) == 'number' )
			{
				delete WindowsNames[Windows[id].name];
			}
		}
	}
	if ( typeof ( id ) == 'string' && typeof ( WindowsNames[id] ) == 'number' )
	{
		WindowClose ( WindowsNames[id] );
	}
}
// Минимизирует окно в полосу меню, и наоборот
function WindowMinimize ( id )
{
	var tr;
	if ( typeof ( id ) == 'number' && id >= 0 )
	{
		if ( Windows[id] && ( minimized = Windows[id].minimized ) != null )
		{
			if ( minimized == false )
			{
				Windows[id].minimized = true;
				document.getElementById ( 'm_' + id ).style.display = 'none';
				document.getElementById ( id ).style.height = '21px';
			}
			else if ( minimized == true )
			{
				Windows[id].minimized = false;
				document.getElementById ( 'm_' + id ).style.display = 'block';
				document.getElementById ( id ).style.height = Windows[id].height;
			}
		}
	}
}
// Конвертирует контейнер как объект в строку
function WindowContainerToString ()
{
	var result = "";
	for ( i = 0; i < this.divids.length; i++ )
	{
		if ( typeof ( this.divids[i] ) == 'number' )
		{
			eval ( "result += this.b" + this.divids[i] + ";" );
		}
	}
	return result;
}
// Добавляет в контейнер новый блок - окно
function WindowContainerAdd ( div, id )
{
	this.layers[id+1] = id;
	this.divids.push ( id );
	eval ( "this.b" + id +" = div;" );
}
// Восстановление и бэкап некоторых параметров окошек (позиция)
function WindowContainerBackup ( mode )
{
	var style;
	if ( mode == 'backup' && container )
	{
		for ( i = 0; i < container.divids.length; i ++ )
		{
			style = document.getElementById ( container.divids[i] ).style;
			backup[i] = new Object();
			backup[i].left = style.left;
			backup[i].top = style.top;
			backup[i].width = style.width;
			backup[i].height = style.height;

			var menu = document.getElementById ( 'm_' + container.divids[i] );
			if ( menu.style && menu.style.display )
			{
				backup[i].menudisplay = menu.style.display;
			}
			else
			{
				backup[i].menudisplay = 'block';
			}

			var winname = Windows[container.divids[i]].name;
			backup[i].content = document.getElementById ( 'cont_' + winname ).innerHTML;
		}
		return;
	}
	if ( mode == 'restore' && container && typeof ( container.divids[0] ) == 'number' )
	{
		for ( i = 0; i < container.divids.length - 1; i ++ )
		{
			style = document.getElementById ( container.divids[i] ).style;
			style.left = backup[i].left;
			style.top = backup[i].top;
			style.width = backup[i].width;
			style.height = backup[i].height;

			menu = document.getElementById ( 'm_' + container.divids[i] );
			menu.style.display = backup[i].menudisplay;

			var winname = Windows[container.divids[i]].name;
			document.getElementById ( 'cont_' + winname ).innerHTML = backup[i].content;
		}
		return;
	}
}
// Удаление окна из контейнера
function WindowContainerRemove ( id )
{
	// Удаляем блок из контейнера
	eval ( "delete this.b" + id + ";" );
	// Удаляем запись о блоке
	var divids = this.divids;
	for ( i = 0; i < divids.length; i++ )
	{
		if ( divids[i] == id )
		{
			this.divids[i] = null;
			break;
		}
	}
	this.DividsSort();
}
// Метод для сортировки массива идентификаторов окон, и исключение записи об
// удаленном окне
function WindowContainerDividsSort ()
{
	if ( this.divids && this.divids.length  == 0 )
	{
		return false;
	}
	var divids = this.divids;
	var newdivids = new Array();
	var x = 0;
	var length = divids.length;
	while ( x < length )
	{
		var id = divids.shift();
		if ( id != null )
		{
			newdivids.push ( id );
		}
		x++;
	}
	this.divids = newdivids;
}
// Установление обработчиков мыши для каждого окна
function WindowDivWatchMouse ()
{
	var head;
	for ( i = 0; i < this.divids.length; i++ )
	{
		if ( head = document.getElementById ( 'window_head_' + this.divids[i] ) )
		{
			WindowDivEvent ( head, 'onmousedown', WindowMotionMouseDown );
			WindowDivEvent ( head, 'onmouseup', WindowMotionMouseUp );
		}
	}
}
// При получении события, необходимо добраться до DIV, т.к.
// нажатие могло быть произведено не на сам блок, а на его содержимое
function WindowDivSearch ( e )
{
	var path = "";
	var element = null;
	var stop = false;
	var ignore = false;

  	src = ( 'target' in e ) ? 'target' : 'srcElement'; // Mozilla : IE

	for ( i = 0;; i++ )
	{
		eval ( "if (! (element = e." + src + path + ") ) { stop = true; }" );
		if ( stop == true )
		{
			alert ( 'Произошла ошибка! Скорее всего Ваш броузер не поддерживается!' );
			return false;
		}
		if ( element.tagName == 'DIV' && element.id >= 0 )
		{
			return element;
		}
		path += ".parentNode";
	}
}
// Захват событий для некоторого объекта (предполагается div)
// Совместим с Firefox, Opera, IE
function WindowDivEvent ( div, evt, func )
{
	if ( evt == 'onmousemove' ) // захватываем передвижения по всему документу
	{
		div = document;
	}
	if ( 'attachEvent' in div )
	{
		div.attachEvent ( evt, func );
	}
	else if ( 'addEventListener' in div )
	{
		var rp, found;
		re = /^on/;
		found = evt.match ( re );
		if ( found[0] == 'on' )
		{
			evt = evt.substr ( 2 );
		}
		div.addEventListener ( evt, func, false);
	}
}
// Обработчик нажатия кнопки мыши
function WindowMotionMouseDown ( e )
{
	var div = WindowDivSearch ( e ); // получаем окно, которому принадлежит событие
	if ( div == false ) // если окно не найдено
	{
		return false;
	}

	current_drag = div;
	current_drag.LastX = e.clientX;
	current_drag.LastY = e.clientY;
	if ( current_drag.style.left == "" && current_drag.style.top == "" )
	{
		current_drag.style.left = 0;
		current_drag.style.top = 0;
	}

	WindowDivOnTop ( current_drag );

	WindowDivEvent ( div, 'onmousemove', WindowMotionMouseMove );
}
// Обработчик отпускания кнопки мыши
function WindowMotionMouseUp ( e )
{
	WindowMotionDragStop ();
}
// Остановка перехвата движений
function WindowMotionDragStop ()
{
	if ( current_drag == null )
	{
		return;
	}
	// IE, Opera
	if ( 'detachEvent' in current_drag )
	{
		document.detachEvent ( 'onmousemove', WindowMotionMouseMove );
	}
	// Mozilla, Firefox
	else if ( 'removeEventListener' in current_drag )
	{
		document.removeEventListener ( 'mousemove', WindowMotionMouseMove, false );
	}
}
// Обработчик перемещения курсора
function WindowMotionMouseMove ( e )
{
	var dX, dY, top, left;

	dX = e.clientX - current_drag.LastX;
	dY = e.clientY - current_drag.LastY;

	top = dY + parseInt ( current_drag.style.top );
	left = dX + parseInt ( current_drag.style.left );

	current_drag.style.top = top + 'px';
	current_drag.style.left = left + 'px';

	current_drag.LastX = e.clientX;
	current_drag.LastY = e.clientY;
}
// Меняем позицию окна относительно других (под/над)
function WindowDivOnTop ( ontopdiv )
{
	var divids = container.divids;
	var layers = container.layers;
	var debug = '';
	var start = false;
	// Вычисляем положения номер данного блока в таблице порядковых номеров блоков
	for ( i = 1; i < layers.length; i++ )
	{
		if ( start && ( div = document.getElementById ( layers[i] ) ) )
		{
			div.style.zIndex = i - 1;
		}
		if ( !start && layers[i] == ontopdiv.id )
		{
			start = true;
		}
	}
	ontopdiv.style.zIndex = layers.length - 1;

	// Формируем по новой массив позиционирования оконо [zindex] => [wid]
	layers = new Array();
	var z;
	for ( i = 0; i < divids.length; i++ )
	{
		z = document.getElementById ( divids[i] ).style.zIndex;
		layers[z] = divids[i];
	}
	container.layers = layers;
}
	function Dump(d,l)
	{
	    if (l == null) l = 1;
	    var s = '';
	    if (typeof(d) == "object") {
	        s += typeof(d) + " {\n";
	        for (var k in d) {
	            for (var i=0; i<l; i++) s += "  ";
	            s += k+": " + Dump(d[k],l+1);
	        }
	        for (var i=0; i<l-1; i++) s += "  ";
	        s += "}\n"
	    } else {
	        s += "" + d + "\n";
	    }
	    return s;
	}