/*
	Copyright (C) 2008 - Juan Ferrer Toribio

	This program is free software; you can redistribute it and/or
	modify it under the terms of the GNU Lesser General Public
	License as published by the Free Software Foundation; either
	version 2.1 of the License, or (at your option) any later version.

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
	Lesser General Public License for more details.

		You should have received a copy of the GNU Lesser General Public
	License along with this program; if not, write to the Free
	Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
	02111-1307 USA.
*/

//+++++++++++++++++++++++++++++++++++++++++++++++++++ HtkWidget

var HtkWidget = new Class
({
	Extends: SqlObject

	/** Border of widget **/
	,b: 0
	/** Margin of widget **/
	,m: 0
	/** Total border of widget **/
	,bdr: 0
	/** Height of widget **/
	,h: 0
	/** Width of widget **/
	,w: 0
	/** Main DOMNode that represents the widget **/
	,node: null
	/** The style property of node **/
	,style: null		

	,initialize: function (tname)
	{
		this.parent ();
		this.node = document.createElement (tname);
		this.style = this.node.style;
		this.bdr = this.getBdr ();
	}
	
	,getNode: function ()
	{
		return this.node;
	}

	,getBdr: function ()
	{
		return this.b * 2 + this.m * 2;
	}

	,setBorder: function (m)
	{
		this.style.margin = m + 'px';
		this.m = m;
		this.bdr = this.getBdr ();
	}

	,setSize: function (h, w)
	{
		if (h >= 0)
		{
			this.h = h;
			this.style.height = (h - this.bdr) + 'px';
		}
		if (w >= 0)
		{
			this.w = w;
			this.style.width = (w - this.bdr) + 'px';
		}
	}
});

//+++++++++++++++++++++++++++++++++++++++++++++++++++ Node
			
var HtkNode = new Class
({
	Extends: HtkWidget

	,initialize: function (node)
	{
		this.node = node;
		this.style = node.style;
	}

	,setSize: function (h, w) {}
});

function removeChilds (node)
{
	var cNode = node.childNodes;

	while (cNode.length > 0)
		node.removeChild (cNode[0]);
}

function removeNode (node)
{
	node.parentNode.removeChild (node);
}

function setText (node, text)
{
	removeChilds (node);

	if (text)
		node.appendChild (document.createTextNode (text));
}

function addEvent (node, evt, func, obj)
{
	node.addEventListener (evt, function () {obj.func ()}, false);
}

//+++++++++++++++++++++++++++++++++++++++++++++++++++ HtkContainer

var HtkContainer = new Class
({
	Extends: HtkWidget

	,child: new Array ()
	/** Total width available for the children **/
	,childWidth: 0
	/** Total height available for the children **/
	,childHeight: 0

	,initialize: function (el)
	{
		this.parent (el);
		this.childWidth = this.w - this.bdr;
		this.childHeight = this.h - this.bdr;
	}

	/**
	 * Sets the size of container and recalculates the size of its children.
	 **/
	,setSize: function (height, width)
	{
		this.childWidth += width - this.w;
		this.childHeight += height - this.h;
		this.parent (height, width);
		this.setChildSize ();
	}

	/**
	 * Sets the border of container and recalculates the size of its children.
	 **/
	,setBorder: function (m)
	{
		var bdr = (m * 2 + this.b * 2) - this.bdr;
		this.childWidth -= bdr
		this.childHeight -= bdr;
		this.parent (m);
		this.setChildSize ();
	}

	/**
	 * This abstract method shoud be declared by any class that inherits from
	 * container and should recalculate the size of all its childrens.
	 **/
	,setChildSize: function () {}
});

//+++++++++++++++++++++++++++++++++++++++++++++++++++ HtkBin

var HtkBin = new Class
({
	Extends: HtkContainer
	
	/** Node that will contain the only child **/
	,bin: null

	,initialize: function ()
	{
		this.parent ('div');
		this.bin = this.node;
	}

	,setChild: function (child)
	{
		// TODO: Should inherit from HtkWidget
		if (child.nodeName)
			child = new HtkNode (child);

		if (this.child.length > 0)
			this.bin.replaceChild (child.getNode (), this.bin.firstChild);
		else
			this.bin.appendChild (child.getNode ());

		this.child[0] = child;
		this.setChildSize ();
	}
	
	,removeChild: function ()
	{
		if (this.child.length > 0)
		{
			removeNode (child[0].getNode ());
			this.child.shift ();
			this.setChildSize ();
		}
	}

	,setChildSize: function ()
	{
		if (this.child.length > 0)
			this.child[0].setSize (this.childHeight, this.childWidth);
	}
});

// Scroll

var HtkScroll = new Class
({
	Extends: HtkBin

	,initialize: function ()
	{
		this.parent ();
		this.bin.style.verticalAlign = 'top';
		this.bin.style.overflow = 'auto';
	}
});

// Frame

n = -1;
var HTK_FRAME_YELLOW	= ++n;
var HTK_FRAME_BLUE		= ++n;
var HTK_FRAME_RED		= ++n;

var HtkFrame = new Class
({
	Extends: HtkBin
	
	,b: 1
	,header: false

	,initialize: function (title)
	{
		var div;
		
		this.parent ('div');
		
		if (title)
			this.setTitle (title);
		
		div = document.createElement ('div');
		this.node.className = 'box';
		this.node.appendChild (div);
		this.bin = div;
	}

	,setTitle: function (text)
	{
		var node;

		if (!this.header)
		{
			node = document.createElement ('div');
			node.className = 'title';
			this.node.insertBefore (node, this.node.firstChild);
			this.childHeight -= 25;
		}
		
		setText (this.node.firstChild, text);
		this.header = true;
	}

	,setColor: function (cid)
	{
		var bg;
		var border;
		
		switch (cid)
		{
			case HTK_FRAME_YELLOW:
				bg = '#FFC';
				border = '#CC9';
				break;
			case HTK_FRAME_BLUE:
				bg = '#EEF';
				border = '#AAC';
				break;
			case HTK_FRAME_RED:
				bg = '#FDD';
				border = '#CAA';
				break;
		}

		this.style.backgroundColor = bg;
		this.style.borderColor = border;
	}	
});

//+++++++++++++++++++++++++++++++++++++++++++++++++++ HtkBox

var HtkBox = new Class
({
	Extends: HtkContainer

	,spacing: 8

	,initialize: function ()
	{
		var table, tbody;
	
		this.parent ('div');

		table = document.createElement ('table');
		table.cellSpacing = '0px';
		table.cellPadding = '0px';
		table.style.width = '100%';
		this.node.appendChild (table);

		tbody = document.createElement ('tbody');
		table.appendChild (tbody);

		this.tbody = tbody;
	}

	,addChild: function (widget, expand)
	{
		var child = new Object ();
		child.widget = widget;
		child.expand = expand;	
		this.child.push (child);
	}

	,setSpacing: function (size)
	{
		this.spacing = size;
	}
});

// Vbox

var HtkVBox = new Class
({
	Extends: HtkBox

	,initialize: function ()
	{
		this.parent ();
		this.node.className = 'HtkVBox';
	}

	,add: function (child, expand)
	{
		var tr, cell;
		
		// TODO: Should inherit from HtkWidget
		if (child.nodeName)
			child = new HtkNode (child);
	
		if (this.tbody.firstChild)
		{
			tr = document.createElement ('tr');
			this.tbody.appendChild (tr);

			cell = document.createElement ('td');
			cell.style.height = this.spacing + 'px';
			tr.appendChild (cell);
		}

		tr = document.createElement ('tr');
		this.tbody.appendChild (tr);

		this.addChild (child, expand);
		this.setChildSize ();
	
		cell = document.createElement ('td');
		cell.style.verticalAlign = 'top';
		cell.appendChild (child.getNode ());
		tr.appendChild (cell);
	}

	,setChildSize: function ()
	{
		var n, m = 0;
		var child = this.child;
		var len = child.length;
		var height = this.childHeight;

		for (n = 0; n < len; n++)
		{
			if (child[n].expand)
				m++;
			else
				height -= child[n].widget.h;
		}

		if (m > 0)
		{
			height = (height - this.spacing * (len - 1)) / m;

			for (n = 0; n < len; n++)
				if (child[n].expand)
					child[n].widget.setSize (height, this.childWidth);
		}	
	}
});

// HBox

var HtkHBox = new Class
({
	Extends: HtkBox

	,initialize: function (align)
	{
		var tr;
		
		this.parent ();
		this.node.className = 'HtkHBox';
		
		tr = document.createElement ('tr');
		this.tbody.appendChild (tr);
		this.tr = tr;
	}

	,add: function (child, expand)
	{
		var cell;

		// TODO: Should inherit from HtkWidget
		if (child.nodeName)
			child = new HtkNode (child);

		if (this.tr.firstChild)
		{
			cell = document.createElement ('td');
			cell.style.width = this.spacing + 'px';
			this.tr.appendChild (cell);
		}

		cell = document.createElement ('td');
		cell.style.verticalAlign = 'middle';
		
		if (!expand)
			cell.style.width = '1%';

		this.addChild (child, expand);
		child.setSize (this.childHeight, -1);

		cell.appendChild (child.getNode ());
		this.tr.appendChild (cell);
	}

	,setChildSize: function ()
	{
		var n;
		var child = this.child;
		
		for (n = 0; n < child.length; n++)
			child[n].widget.setSize (this.childHeight, -1);
	}
});

// Grid

var HtkGrid = new Class
({
	Extends: HtkContainer
	
	,tbody: null
	,lastRow: null
	,cols: new Array ()
	,currentCol: 0
	,numCols: 2
	,rowHeight: 10
	
	,initialize: function (numCols)
	{
		var tbody;
	
		this.parent ('table');

		tbody = document.createElement ('tbody');
		this.node.appendChild (tbody);
		this.node.className = 'pepe';
		
		this.tbody = tbody;
		this.numCols = numCols;
		
		for (var n = 0; n < numCols; n++)
			this.cols[n] = -1;
	}
	
	,setColWidth: function (col, width)
	{
		if (col < this.numCols)
			this.cols[col] = width;
	}
	
	,removeChilds: function ()
	{
		removeChilds (this.tbody);
		this.currentCol = 0;
	}
	
	,attach: function (child)
	{
		var td;
		
		if (this.currentCol == 0)
		{		
			var tr = document.createElement ('tr');
			tr.style.height = this.rowHeight + 'px';
			this.tbody.appendChild (tr);
			this.lastRow = tr;
		}
		
		td = document.createElement ('td');
		
		if (this.cols[this.currentCol] > -1)
			td.style.width = this.cols[this.currentCol] + 'px';
		
		this.lastRow.appendChild (td);
		
		if (child != null)
		{
			if (child.nodeName)
				child = new HtkNode (child);
			td.appendChild (child.getNode ());
		}
	
		this.currentCol++;

		if (this.currentCol == this.numCols)
			this.currentCol = 0;
	}
});


//+++++++++++++++++++++++++++++++++++++++++++++++++++ HtkLink

var HtkLink = new Class
({
	Extends: HtkWidget

	,initialize: function ()
	{
		this.parent ('a');
		this.node.href = '#';
	}
});

//+++++++++++++++++++++++++++++++++++++++++++++++++++ HtkRadio

var htkRadioUid = -1;

var HtkRadio = new Class
({
	Extends: SqlObject,
	Implements: SqlParam

	,initialize: function ()
	{
		this.parent ();
		this.rButton = new Array ();
		this.uid = ++htkRadioUid;
	}

	,newRadio: function (value)
	{
		var radio;
		var obj = this;

		radio = createRadio (this.uid);
		radio.value = value;
		radio.checked = value == this.realValue;
		radio.addEventListener ('change',
			function () { obj.radioChanged (this.value); }, false);
		this.rButton.push (radio);
		
		return radio;
	}

	,radioChanged: function (value)
	{
		this.realValue = value;
		this.signalEmit ('changed');
	}

	,setRealValue: function (value)
	{
		var rButton = this.rButton;

		for (var n = 0; n < rButton.length; n++)
		{
			if (rButton[n].value == value)
			{
				rButton[n].checked = true;
				break;
			}
		}
	}

	,setEditable: function (editable)
	{
		var rButton = this.rButton;

		for (var n = 0; n < rButton.length; n++)
				rButton[n].disabled = !editable;
	}
});

//+++++++++++++++++++++++++++++++++++++++++++++++++++ HtkEntry

var HtkEntry = new Class
({
	Extends: HtkWidget,
	Implements: SqlParam

	,initialize: function (tname)
	{
		this.parent (tname);
	}
});

// Label

var HtkLabel = new Class
({
	Extends: HtkEntry

	,initialize: function ()
	{
		this.parent ('label');
		this.style.fontWeight = 'normal';
		this.node.editable = false;
	}

	,setRealValue: function (value)
	{
		setText (this.node, value);
	}

	,setEditable: function (editable) {}
});

// String

var HtkString = new Class
({
	Extends: HtkEntry

	,initialize: function (iname)
	{
		var obj = this;
		this.parent (iname);
		this.node.addEventListener ('change',
			function () { obj.changed () }, false);
	}

	,changed: function (event)
	{
		if (this.node.value == '')
			this.realValue = null;
		else
			this.realValue = this.node.value;

		this.signalEmit ('changed');
	}

	,setEditable: function (editable)
	{
		this.node.readOnly = !editable;
	}

	,setRealValue: function (value)
	{
		if (!value)
			this.node.value = '';
		else
			this.node.value = value;
	}
});

// Text

var HtkText = new Class
({
	Extends: HtkString

	,initialize: function ()
	{
		this.parent ('input');
		this.node.type = 'text';
	}
});

// TextArea

var HtkTextArea = new Class
({
	Extends: HtkString

	,initialize: function ()
	{
		this.parent ('textarea');
	}
});

// Spin

var HtkSpin = new Class
({
	Extends: HtkEntry

	,initialize: function ()
	{
		this.parent ('span');
		this.unit = null;
		this.digits = 0;
	}

	,changed: function ()
	{
		var value = (this.entry.value == '') ? null : parseFloat (this.entry.value);
		this.entry.value = value;
		this.realValue = value;
		this.signalEmit ('changed');
	}

	,setEditable: function (editable)
	{
		if (this.editable == editable)
			return;
	
		if (editable)
		{
			var input;
			var obj = this;
			
			input = document.createElement ('input');
			input.style.textAlign = 'right';
			input.style.width = '100%';
			setInputTypeNumber (input);
			input.addEventListener ('change',
				function () { obj.changed (); }, false);	
			this.node.appendChild (input);
			this.entry = input;
		}
		else
		{
			removeChilds (this.node);
			this.entry = null;
		}
		
		this.editable = editable;
	}

	,setRealValue: function (value)
	{
		var text;
		
		if (value != null)
		{
			text = (new Number (value)).toFixed (this.digits);
		
			if (this.unit != null)
				text += ' ' + this.unit;
		}
		else
			text = '';
	
		if (!this.editable)
			setText (this.node, text);
		else
			this.entry.value = text;
	}
});

// Check

var HtkCheck = new Class
({
	Extends: HtkEntry

	,initialize: function ()
	{
		var obj = this;
		this.parent ('input');
		this.node.type = 'checkbox';
		this.node.addEventListener ('change',
			function () { obj.changed (); }, false);	
	}

	,changed: function ()
	{
		this.realValue = this.node.checked;
		this.signalEmit ('changed');
	}

	,setEditable: function (editable)
	{
		this.node.disabled = !editable;
	}

	,setRealValue: function (value)
	{
		if (value)
			this.node.checked = true;
		else
			this.node.checked = false;
	}
});

// Image

var HtkImage = new Class
({
	Extends: HtkEntry
	
	,empty: false

	,initialize: function ()
	{
		var obj = this;
		this.parent ('img');
		this.node.alt = '';
		this.node.addEventListener ('error',
			function () { obj.error (); }, false);
	}

	,error: function ()
	{
		if (!this.empty)
		{
			this.empty = true;
			this.node.src = 'image/empty.png';
		}
	}

	,render: function (force)
	{
		this.cName = this.realValue;
	
		if (!this.cName && !force)
			this.error ();
		else
		{
			if (force)
				this.cName += '?' + (new Date()).getTime ();

			this.empty = false;
			this.node.src = 'image/' + this.url + '/' + this.cName + '.png';
		}
	}

	,setRealValue: function (value)
	{
		this.render (false);
	}

	,setShowFull: function (show)
	{
		if (show)
		{
			var obj = this;
			this.node.addEventListener ('mouseover',
				function () { obj.mouseOver () }, false);
			this.node.addEventListener ('mouseout',
				function () { obj.mouseOut () }, false);
		}
	}

	,setEditable: function (editable) 
	{
		if (editable)
		{
			var obj = this;
			this.style.cursor = 'pointer';
			this.node.addEventListener ('dblclick',
				function (e) { obj.dblClicked (e) }, false);
		}
	}

	,dblClicked: function (event)
	{
		var form = htkImageForm.node;
		form.style.top = getPageYOffset () + (event.clientY - 80) + 'px';
		form.style.left = (event.clientX + 30) + 'px';
		document.body.appendChild (form);
		htkImageForm.load (this);
	}

	,mouseOver: function ()
	{
		if (!this.empty)
			htkImageFull.show ('image/' + this.url, this.cName);
	}

	,mouseOut: function ()
	{
		if (!this.empty)
			htkImageFull.hide ();
	}
});

var HtkImageFull = new Class
({
	Extends: HtkWidget
	
	,img: null
	,timeout: 0
	,loading: false
	,visible: false
	,hideCalled: false

	,initialize: function ()
	{
		var div;
		var loadingBox;
		var loadingImg
	
		div = document.createElement ('div');
		div.className = 'box';
		div.style.position = 'absolute';
		div.style.backgroundColor = '#DDF';
		div.style.textAlign = 'center';
		
		loadingBox = document.createElement ('div');
		loadingBox.className = 'box';
		loadingBox.style.position = 'absolute';

		loadingImg = document.createElement ('img');
		loadingImg.style.padding = '10px';
		loadingImg.src = 'image/loading.gif';
		loadingImg.alt = TEXT_Loading;
		loadingBox.appendChild (loadingImg);

		this.loadingBox = loadingBox;
		this.loadingImg = loadingImg;
		this.div = div;
	}
	
	,getLeft: function (size)
	{
		return parseInt (getPageXOffset () + (getInnerWidth () - size) / 2) + 'px';
	}
	
	,getTop: function (size)
	{
		return parseInt (getPageYOffset () + (getInnerHeight () - size) / 2) + 'px';
	}
	
	,show: function (url, cName)
	{
		var img;
		var obj = this;
		
		if (this.timeout)
		{
			clearTimeout (this.timeout);
			this.timeout = 0;
		}

		this.hideCalled = false;
		this.loadingBox.style.left = this.getLeft (40);
		this.loadingBox.style.top = this.getTop (40);

		img = document.createElement ('img');
		img.addEventListener ('load',
			function () { obj.imageLoaded (img); }, false);

		this.img = img;
		img.src = url + '/full/' + cName + '.png';

		if (!img.complete && !this.loading)
		{
			document.body.appendChild (this.loadingBox);
			this.loading = true;
		}
	}
	
	,imageLoaded: function (img)
	{	
		if (img != this.img || this.hideCalled)
			return;
		
		var aux = 0;
		var w = img.width;
		var h = img.height;
		var ih = getInnerHeight () - 60;
		var iw = getInnerWidth () - 350;
	
		if (w > iw)
		{
			aux = w / iw;
			h = parseInt (h / aux);
			w = iw;
		}
	
		if (h > ih)
		{
			aux = h / ih;
			w = parseInt (w / aux);
			h = ih;
		}

		this.hideLoading ();
		this.div.style.left = this.getLeft (w + 2);
		this.div.style.top = this.getTop (h + 2);
		this.div.style.width = w + 'px';
		this.div.style.height = h + 'px';

		if (aux > 0)
		{
			img.style.width = w + 'px';
			img.style.height = h + 'px';
		}

		if (this.div.firstChild != null)
			this.div.replaceChild (img, this.div.firstChild);
		else
			this.div.appendChild (img);

		if (!this.visible)
		{
			document.body.appendChild (this.div);
			this.visible = true;
		}
	}

	,hide: function ()
	{
		var obj = this;
		this.hideCalled = true;
		this.hideLoading ();
		
		if (this.visible)
			this.timeout = setTimeout (function () { obj.hideTimeout () }, 450);
	}
	
	,hideTimeout: function ()
	{
		document.body.removeChild (this.div);
		this.visible = false;
		this.timeout = 0;
	}
	
	,hideLoading: function ()
	{
		if (this.loading)
		{
			document.body.removeChild (this.loadingBox);
			this.loading = false;
		}
	}
});

var HtkImageForm = new Class
({	
	Extends: HtkWidget

	,initialize: function ()
	{
		var h;
		var val;
		var fname;
		var dst;
		var obj;
		var file;
		var form;
		var input;
		var iframe;
		var table;
		var tbody;
		var tr;
		var td;
		var obj = this;
	
		this.parent ('div');
		this.style.position = 'absolute';
		this.style.width = '400px';
		this.node.className = 'box';

		h = document.createElement ('div');
		h.className = 'title';
		h.appendChild (document.createTextNode (TEXT_UpdateImage));
		this.node.appendChild (h);

		table = document.createElement ('table');
		table.cellSpacing = 5;
		this.node.appendChild (table);

		tbody = document.createElement ('tbody');
		table.appendChild (tbody);

		tr = document.createElement ('tr');
		tbody.appendChild (tr);

		td = document.createElement ('td');
		td.style.textAlign = 'right';
		td.appendChild (document.createTextNode (TEXT_FileName + ':'));
		tr.appendChild (td);

		td = document.createElement ('td');
		tr.appendChild (td);
	
		val = new HtkText ();
		val.addSignal ('changed', this.valueChanged, obj);
		td.appendChild (val.getNode ());

		tr = document.createElement ('tr');
		tbody.appendChild (tr);

		td = document.createElement ('td');
		td.style.textAlign = 'right';
		td.appendChild (document.createTextNode (TEXT_File + ':'));
		tr.appendChild (td);

		td = document.createElement ('td');
		tr.appendChild (td);
		
		form = document.createElement ('form');
		form.method = 'post';
		form.action = 'module.php';
		form.target = 'htkImageForm';
		form.enctype = 'multipart/form-data';
		td.appendChild (form);
	
		input = document.createElement ('input');
		input.type = 'hidden';
		input.name = 'MAX_FILE_SIZE';
		input.value = '3145728';	// 3 MegaBytes
		form.appendChild (input);
	
		file = document.createElement ('input');
		file.type = 'file';
		file.name = 'image';
		form.appendChild (file);
	
		input = document.createElement ('input');
		input.type = 'hidden';
		input.name = 'mod';
		input.value = 'image';
		form.appendChild (input);
	
		fname = document.createElement ('input');
		fname.type = 'hidden';
		fname.name = 'fname';
		form.appendChild (fname);
	
		dst = document.createElement ('input');
		dst.type = 'hidden';
		dst.name = 'dst';
		form.appendChild (dst);

		tr = document.createElement ('tr');
		tbody.appendChild (tr);

		td = document.createElement ('td');
		td.style.textAlign = 'center';
		td.colSpan = 2;
		tr.appendChild (td);
	
		input = document.createElement ('button');
		input.addEventListener ('click',
			function () { obj.upload (); }, false);
		input.appendChild (document.createTextNode (TEXT_UploadFile));
		td.appendChild (input);
	
		input = document.createElement ('button');
		input.style.marginLeft = '10px';
		input.addEventListener ('click',
			function () { obj.clicked (); }, false);
		input.appendChild (document.createTextNode (TEXT_Close));
		td.appendChild (input);
		
		iframe = document.createElement ('iframe');
		iframe.name = 'htkImageForm';
		iframe.style.display = 'none';
		iframe.addEventListener ('load', 
			function () { obj.loaded (this); }, false);
		td.appendChild (iframe);
		
		this.form = form;
		this.val = val;
		this.fname = fname;
		this.dst = dst;
		this.file = file;
	}

	,load: function (img)
	{	
		this.img = img;
		this.src = img.src;
		this.fname.value = this.img.getValue ();
		this.val.setValue (this.img.getValue ());
		this.dst.value = this.img.url;
		this.style.display = 'block';
	}

	,loaded: function (iframe)
	{
		var text = iframe.contentDocument.body.textContent;

		if (text)
		{
			this.changeImage ();
			
			if (text != 1)
				alert (text);
		}
	}

	,changeImage: function ()
	{
		this.img.render (true);
		this.style.display = 'none';
	}

	,upload: function ()
	{
		this.img.node.src = 'image/loading.gif';
		this.form.submit ();
	}

	,valueChanged: function (entry)
	{
		var val = entry.getValue ();
		this.fname.value = val;
		this.img.setValue (val);
		this.img.signalEmit ('changed');
	}

	,clicked: function ()
	{
		document.body.removeChild (this.node);
	}
});

var htkImageFull = new HtkImageFull ();
var htkImageForm = new HtkImageForm ();

// Select

var HtkSelect = new Class
({
	Extends: HtkEntry

	,initialize: function (model)
	{
		var obj = this;
		this.parent ('select');
		this.node.addEventListener ('change',
			function () { obj.changed (); }, true);
		this.col = 0;
		this.model = model;
		model.addSignal ('status-changed', this.modelRefresh, this);
		this.modelRefresh (model, null);
	}
	
	,changed: function (event)
	{
		var index = this.node.selectedIndex - 1;

		if (index >= 0)
			this.realValue = this.model.getValue (index, 0);
		else
			this.realValue = null;

		this.signalEmit ('changed');
	}
	
	,modelRefresh: function (model, status)
	{
		var option;
		var text = null;
		
		removeChilds (this.node);

		switch (model.status)
		{
			case DB_MODEL_STATUS_READY:
			{
				var col = this.col;
				var data = model.data;

				this.node.appendChild (document.createElement ('option'));
				
				for (var n = 0; n < data.length; n++)
				{
					option = document.createElement ('option');
					option.value = data[n][col];
					option.appendChild (document.createTextNode (data[n][1]));
					this.node.appendChild (option);
				}
				
				this.setRealValue ();

				break;
			}
			case DB_MODEL_STATUS_LOADING:
				text = TEXT_Loading + '...';
				break;
			case DB_MODEL_STATUS_ERROR:
				text = TEXT_Error;
				break;
		}

		if (text != null)
		{
			option = document.createElement ('option');
			option.value = null;
			this.node.appendChild (option);
			this.nullOption = option;
			this.nullOption.appendChild (document.createTextNode (text));
		}
	}
	
	,setEditable: function (editable)
	{
		this.node.disabled = !editable;
	}

	,setRealValue: function (value)
	{
		var row = this.model.searchValue (this.col, this.realValue) + 1;
		this.node.childNodes[row].setAttribute ('selected', true);
	}
});

// Date

n = -1;
var DATE_FORMAT_FULL_DATE_TIME	= ++n;
var DATE_FORMAT_FULL_DATE		= ++n;
var DATE_FORMAT_FULL_TIME		= ++n;
var DATE_FORMAT_ABR_DATE		= ++n;
var DATE_FORMAT_ABR_DATE_TIME	= ++n;
var DATE_FORMAT_ABR_TIME		= ++n;

var HtkDate = new Class
({
	Extends: HtkEntry

	,editable: false
	,format: undefined
	,handler: null
	
	,initialize: function ()
	{
		var tbody;
		var tr;
		var text;
		
		this.parent ('table');
		this.node.cellSpacing = 0;
		this.node.cellPadding = 0;
		
		tbody = document.createElement ('tbody');
		this.node.appendChild (tbody);
		
		tr = document.createElement ('tr');
		tbody.appendChild (tr);
		
		text = document.createElement ('td');
		tr.appendChild (text);

		this.text = text;
		this.tr = tr;
	}

	,toStr: function (value)
	{
		if (value < 10)
			return '0' + value.toString ();
		return value.toString ();
	}

	,formatFullDate: function ()
	{
		var date = this.realValue;
	
		return TEXT_WeekDay[date.getDay ()] + ', ' + this.toStr (date.getDate ()) + ' ' + TEXT_Of + ' '
		+ TEXT_Month[date.getMonth ()] + ' ' + TEXT_OfThe + ' ' + date.getFullYear ();
	}

	,formatAbrDate: function ()
	{
		var date = this.realValue;
	
		return TEXT_WDay[date.getDay ()] + ', ' + this.toStr (date.getDate ()) + ' '
		+ TEXT_AbrMonth[date.getMonth ()] + ' ' + date.getFullYear ();
	}

	,formatAbrTime: function ()
	{
		var date = this.realValue;

		return this.toStr (date.getHours ()) +':' + this.toStr (date.getMinutes ());
	}

	,setRealValue: function (value)
	{
		removeChilds (this.text);

		if (value instanceof Date)
		{
			var string;
	
			switch (this.format)
			{
				case DATE_FORMAT_FULL_DATE:
					string = this.formatFullDate ();
					break;
				case DATE_FORMAT_ABR_DATE:
					string = this.formatAbrDate ();
					break;
				case DATE_FORMAT_FULL_TIME:
					string = value.toLocaleTimeString ();
					break;
				case DATE_FORMAT_ABR_TIME:
					string = this.formatAbrTime ();
					break;
				case DATE_FORMAT_ABR_DATE_TIME:
					string = this.formatAbrDate () + ' - ' + this.formatAbrTime ();
					break;
				default:
					string = this.formatFullDate () + ' ' + TEXT_At + ' ' + value.toLocaleTimeString ();
			}

			this.text.appendChild (document.createTextNode (string));
		}
	}

	,setEditable: function (editable)
	{
		if (this.editable == editable)
			return;

		if (editable)
		{
			var td;
			var button;
			var img;
			var cal;
			var obj = this;

			td = document.createElement ('td');
			td.style.width = '1px';
			this.tr.insertBefore (td, this.text);
		
			button = document.createElement ('button');
			button.title = TEXT_ChangeDate;
			button.style.padding = '1px';
			button.style.margin = '0px';
			button.style.marginRight = '8px';
			button.addEventListener ('click',
				function (e) { obj.showCalendar (e); }, false);
			td.appendChild (button);
		
			img = document.createElement ('img');
			img.alt = TEXT_ChangeDate;
			img.src = 'image/calendar.png';
			button.appendChild (img);
		
			cal = new HtkCalendar ();
			cal.addSignal ('changed', this.calendarChanged, this);
			this.calendar = cal;

			cal = cal.getNode ();
			cal.style.width = '180px';
			cal.style.position = 'absolute';
			cal.style.top = '0px';
			cal.style.left = '0px';
			cal.addEventListener ('mousedown',
				function (e) { e.stopPropagation (); }, false);
		}
		else
		{
			this.calendar = null;
			this.tr.removeChild (this.tr.firstChild);
		}
		
		this.editable = editable;
	}

	,calendarChanged: function (cal)
	{
		this.hideCalendar ();
		this.setValue (cal.getValue ());
		this.signalEmit ('changed');
	}

	,hideCalendar: function ()
	{
		document.removeEventListener ('mousedown', this.handler, false);
		document.body.removeChild (this.calendar.getNode ());
	}

	,showCalendar: function (event)
	{
		var obj = this;
		var cal = this.calendar;

		cal.style.top = (event.clientY - 40) + 'px';
		cal.style.left = (event.clientX + 30) + 'px';
		cal.paramChanged (this);
		document.body.appendChild (cal.getNode ());
		
		this.handler = function () { obj.hideCalendar (); };
		document.addEventListener ('mousedown', this.handler, false);
	}
});

// HtkTable

var HtkTable = new Class
({
	Extends: HtkEntry

	,initialize: function ()
	{
		var tv;
		var renderer;
		var rbGroup;
		
		this.parent ('div');
		
		tv = new HtkTreeView ();
		this.node.appendChild (tv.getNode ());
		
		renderer = new HtkCellRendererRadio ();
		tv.appendColumn (0, renderer, '');
		
		rbGroup = renderer.rbGroup;
		rbGroup.addSignal ('changed', this.changed, this);

		this.treeview = tv;
		this.rbGroup = rbGroup;
	}

	,setModel: function (model)
	{
		this.treeview.setModel (model);
		model.addSignal ('status-changed', this.modelRefresh, this);
		this.selectValue ();
	}

	,changed: function (rbGroup)
	{
		this.realValue = this.rbGroup.getValue ();
		this.signalEmit ('changed');
	}

	,selectValue: function ()
	{
		this.rbGroup.setValue (this.realValue);
	}

	,setRealValue: function ()
	{
		this.selectValue ();
	}

	,modelRefresh: function (model, status)
	{
		if (status == DB_MODEL_STATUS_READY)
			this.selectValue ();
	}

	,setEditable: function (editable)
	{
		this.rbGroup.setEditable (editable);
	}
});

//+++++++++++++++++++++++++++++++++++++++++++++++++++ HtkCellRenderer

var HtkCellRenderer = new Class
({
	Extends: HtkWidget

	,value: null
	,editable: false

	,initialize: function ()
	{
		this.parent ('td');
		this.style.paddingLeft = '10px';
		this.style.paddingRight = '10px';
	},
		
	bindParam: function (form, col)
	{
		this.form = form;
		this.col = col;
	}

	,render: function (tr)
	{
		var node = this.node.cloneNode (true);
		node.appendChild (this.subRender (tr));
		return node;		
	}

	,changed: function (entry, tr)
	{
		this.form.setRow (tr.rowIndex - 1);
		this.form.setValue (this.col, entry.getValue ());
	}
});

// Text

var HtkCellRendererText = new Class
({
	Extends: HtkCellRenderer

	,initialize: function ()
	{
		this.parent ();
		this.style.textAlign = 'left';
	}

	,subRender: function (tr)
	{
		var entry;
	
		if (this.editable)
		{
			entry = new HtkText ();
			entry.style.width = '100%';
			entry.setEditable (this.editable);
			entry.addSignal ('changed', this.changed, this, tr);
		}
		else
			entry = new HtkLabel ();
		
		entry.setValue (this.value);
		return entry.getNode ();
	}
});

// Spin

var HtkCellRendererSpin = new Class
({
	Extends: HtkCellRenderer

	,initialize: function ()
	{
		this.parent ();
		this.style.textAlign = 'right';
		this.unit = null;
		this.digits = 0;
	}

	,subRender: function (tr)
	{
		var entry = new HtkSpin ();
		entry.style.width = '45px';		
		entry.digits = this.digits;
		entry.unit = this.unit;
		entry.setEditable (this.editable);
		entry.setValue (this.value);
		
		if (this.editable)
			entry.addSignal ('changed', this.changed, this, tr);

		return entry.getNode ();
	}
});

// Date

var HtkCellRendererDate = new Class
({
	Extends: HtkCellRenderer

	,editable: false

	,initialize: function ()
	{
		this.parent ();
		this.style.textAlign = 'left';
		this.format = DATE_FORMAT_ABR_DATE;
	}

	,subRender: function (tr)
	{
		var entry = new HtkDate ();
		entry.format = this.format;
		entry.setEditable (this.editable);
		entry.setValue (this.value);
		
		if (this.editable)
			entry.addSignal ('changed', this.changed, this, tr);

		return entry.getNode ();
	}
});

// Image

var HtkCellRendererImage = new Class
({
	Extends: HtkCellRenderer

	,initialize: function ()
	{
		return this.parent ();
	}

	,subRender: function (tr)
	{
		var entry = new HtkImage ();
		entry.url = this.url;
		entry.setShowFull (this.showFull);
		entry.setEditable (this.editable);
		entry.setValue (this.value);

		if (this.editable)
			entry.addSignal ('changed', this.changed, this, tr);
		
		return entry.getNode ();
	}
});

// ImgButton

var HtkCellRendererImgButton = new Class
({
	Extends: HtkCellRenderer

	,initialize: function ()
	{
		return this.parent ();
	}

	,setData: function (func, url, txt, data)
	{
		this.func = func;
		this.data = data;
		this.txt = txt;
		this.url = url;
	}

	,subRender: function (tr)
	{
		var img;
		var button;
		var obj = this;
		var value = this.value;

		button = document.createElement ('button');
		button.style.padding = '0px';
		button.style.margin = '0px';
		button.title = this.txt;
		button.addEventListener ('click', 
			function () { obj.clicked (value, tr); }, false);
	
		img = document.createElement ('img');
		img.src = this.url;
		img.alt = this.txt;
		button.appendChild (img);

		return button;
	}

	,clicked: function (value, tr)
	{
		this.func (tr.rowIndex, value, this.data);
	}
});

// RadioButton

var HtkCellRendererRadio = new Class
({
	Extends: HtkCellRenderer

	,initialize: function ()
	{
		this.parent ();
		this.rbGroup = new HtkRadio ();
	}

	,setData: function (func, data)
	{
		this.func = func;
		this.data = data;
	}

	,subRender: function (tr)
	{
		return this.rbGroup.newRadio (this.value);
	}
});

//+++++++++++++++++++++++++++++++++++++++++++++++++++ HtkTreeView

n = 0;
var HTK_TREE_VIEW_MODE_INDEX	= n++;
var HTK_TREE_VIEW_MODE_FUNCTION	= n++;

var HtkTreeView = new Class
({
	Extends: HtkFrame
	
	,model: null
	,renderer: new Array ()

	,initialize: function ()
	{
		var table;
		var colgroup;
		var thead;
		var tfoot;
		var tbody;
		var head;

		this.parent ();
		this.style.overflow = 'auto';
		this.style.overflowX = 'hidden';
		
		table = document.createElement ('table');
		table.className = 'treeview';
//		table.style.tableLayout = 'fixed';
		this.setChild (table);

		colgroup = document.createElement ('colgroup');
		table.appendChild (colgroup);

		thead = document.createElement ('thead');
		table.appendChild (thead);

		head = document.createElement ('tr');
		thead.appendChild (head);
		
		tfoot = document.createElement ('tfoot');
		table.appendChild (tfoot);

		tbody = document.createElement ('tbody');
		table.appendChild (tbody);
	
		this.tr = document.createElement ('tr');
		this.table = table;
		this.colgroup = colgroup;
		this.head = head;
		this.tfoot = tfoot;
		this.tbody = tbody;
	}

	,setFoot: function (tr)
	{
		this.tfoot.appendChild (tr);
		this.foot = tr;
	}

	,removeClicked: function (row, value, model)
	{
		if (confirm (TEXT_ReallyDelete))
			model.delRow (row - 1);
	}

	,modelRowDeleted: function (model, row)
	{
		var tr = this.tbody.childNodes;

		this.tbody.removeChild (tr[row]);
		
		for (var n = row; n < tr.length; n++)
				tr[n].className = (n % 2) ? 'highlight' : undefined;
	
		this.showNoRecordsFound ();
	}

	,modelRowInserted: function (model, row)
	{
		this.buildRow (1);
	}

	,modelRowUpdated: function (model, row, col)
	{
		var n;
		var ok;
		var rend;
		var cell;
		var renderer = this.renderer;
		var tr = this.tbody.childNodes[row];
		var td = tr.childNodes;

		for (var m = 0; m < renderer.length; m++)
		{
			rend = renderer[m];
		
			if (rend.mode == HTK_TREE_VIEW_MODE_INDEX)
			{
				ok = false;

				for (n = 0; n < col.length; n++)
				{
					if (col[n] == rend.value)
					{
						ok = true;
						break;
					}
				}
			}
			else
				ok = true;
		
			if (ok)
			{
				cell = this.buildRenderer (rend, tr, model.data[row]);
				tr.replaceChild (cell, td[m]);
			}
		}
	}

	,buildRenderer: function (rend, tr, row)
	{
		switch (rend.mode)
		{
			case HTK_TREE_VIEW_MODE_INDEX:
				rend.object.value = row[rend.value];
				break;
			case HTK_TREE_VIEW_MODE_FUNCTION:
				rend.value (rend.object, row);
				break;
		}
		
		return rend.object.render (tr);
	}

	,buildRow: function (count)
	{
		var n;
		var tr;
		var cell;
		var rend = this.renderer;
		var data = this.model.data;
	
		for (var m = 0; m < count; m++)
		{
			tr = this.tr.cloneNode (false);
		
			if (m % 2)
				tr.className = 'highlight';

			for (n = 0; n < rend.length; n++)
			{
				cell = this.buildRenderer (rend[n], tr, data[m]);
				tr.appendChild (cell);
			}

			this.tbody.appendChild (tr);
		}
	}

	,setModel: function (model)
	{
		var rend;
		var renderer = this.renderer;
	
		this.model = model;
	
		if (model.target)
		{
			var rendel = new HtkCellRendererImgButton ();
			rendel.setData (this.removeClicked, 'image/remove.png', TEXT_Remove, this.model);
			this.appendColumnWithFunc (function () {}, rendel, TEXT_Remove);
		}
		
		this.form = new DbForm (model);
		
		for (var n = 0; n < renderer.length; n++)
		{
			rend = renderer[n];
		
			if (rend.object.editable)
				rend.object.bindParam (this.form, rend.value);
		}
		
		model.addSignal ('status-changed', this.modelRefresh, this);
		model.addSignal ('row-deleted', this.modelRowDeleted, this);
		model.addSignal ('row-updated', this.modelRowUpdated, this);
		model.addSignal ('row-inserted', this.modelRowInserted, this);
		this.modelRefresh ();
	}

	,modelRefresh: function ()
	{
		var tbody = this.tbody;
		var status = this.model.status;

		this.table.removeChild (tbody);
		removeChilds (tbody);

		switch (status)
		{
			case DB_MODEL_STATUS_READY:
				this.buildRow (this.model.data.length);
				this.showNoRecordsFound ();
				break;
			case DB_MODEL_STATUS_CLEAN:
			{
				var msg;
			
				if (this.emptyMsg)
					msg = this.emptyMsg;
				else
					msg = TEXT_NoRecordsLoaded;
			
				this.showMessage (msg, 'refresh.png');
				break;
			}
			case DB_MODEL_STATUS_ERROR:
				this.showMessage (TEXT_ErrorLoadingData, 'error.png');
				break;			
			case DB_MODEL_STATUS_LOADING:
				this.showMessage (TEXT_Loading, 'loading.gif');
				break;
		}

		this.table.appendChild (tbody);
	}

	,showNoRecordsFound: function (count)
	{
		if (this.model.data.length == 0)
			this.showMessage (TEXT_NoRecordsFound, 'clean.png');
	}

	,showMessage: function (msg, img)
	{
		var tr;
		var td;

		tr =  document.createElement ('tr');
		this.tbody.appendChild (tr);

		td = document.createElement ('td');
		td.colSpan = this.renderer.length;
		td.appendChild (new HtkMessage (msg, img).getNode ());
		tr.appendChild (td);
	}

	,orderModel: function (col)
	{
		if (this.model)
			this.model.orderBy (col);
	}
	
	,scrollTo: function (col, value)
	{
		var row = this.model.searchValue (col, value);

		if (row != -1)
		{
			var height = parseInt (this.tr.style.height);
			this.scrollTop = (row - 2) * height;
			
			this.tbody.childNodes[row].style.backgroundColor = '#FDD';
		}
	}

	,addColumn: function (pos, value, renderer, title, mode)
	{
		var col;
		var th;
		var rend;
		var cn;
		var text;

		col = document.createElement ('col');
		th = document.createElement ('th');
		text = document.createTextNode (title);
		
		if (mode == HTK_TREE_VIEW_MODE_INDEX)
		{
			var link;
			var obj = this;
			
			link = document.createElement ('a');
			link.href = '#';
			link.addEventListener ('click', 
				function () { obj.orderModel (value); }, false);
			link.appendChild (text);
			text = link;
		}
		
		th.appendChild (text);

		rend = new Object ();
		rend.object = renderer;
		rend.mode = mode;
		rend.value = value;
		
		cn = this.colgroup.childNodes;

		if (pos == -1)
		{
			this.colgroup.appendChild (col);
			this.head.appendChild (th);
			this.renderer.push (rend);
		}
		else if (pos < cn.length)
		{	
			this.colgroup.insertBefore (col, cn[pos]);
			this.head.insertBefore (th, this.head.childNodes[pos]);
			this.renderer.splice (pos, 0, rend);
		}

		this.reloadModel ();
	}

	,insertColumn: function (pos, index, renderer, title)
	{
		this.addColumn (pos, index, renderer, title, HTK_TREE_VIEW_MODE_INDEX);
	}

	,insertColumnWithFunc: function (pos, func, renderer, title)
	{
		this.addColumn (pos, func, renderer, title, HTK_TREE_VIEW_MODE_FUNCTION);
	}

	,appendColumn: function (index, renderer, title)
	{
		this.insertColumn (-1, index, renderer, title);
	}

	,appendColumnWithFunc: function (func, renderer, title)
	{
		this.insertColumnWithFunc (-1, func, renderer, title);
	}

	,removeColumn: function (pos)
	{
		var nd;

		if (pos < 0 || pos >= this.renderer.length)
			return;

		this.renderer.splice (pos, 1);
		
		nd = this.colgroup;
		nd.removeChild (nd.childNodes[pos]);

		nd = this.head;
		nd.removeChild (nd.childNodes[pos]);
		
		this.reloadModel ();
	}

	,reloadModel: function ()
	{
		if (this.model != null)
			this.modelRefresh ();
	}
});

//+++++++++++++++++++++++++++++++++++++++++++++++++++ HtkMessage

var HtkMessage = new Class
({
	Extends: HtkWidget

	,initialize: function (msg, image)
	{
		var tbody;
		var td;
		var tr;
		var img;
	
		this.parent ('table');
		this.style.height = '100%';
		this.cellSpacing = 6;

		tbody = document.createElement ('tbody');
		this.node.appendChild (tbody);
	
		tr = document.createElement ('tr');
		tbody.appendChild (tr);

		td = document.createElement ('td');
		td.style.textAlign = 'right';
		td.style.width = '40%';
		tr.appendChild (td);

		img = document.createElement ('img');
		img.alt = TEXT_Loading;
		img.src = 'image/' +  image;
		td.appendChild (img);

		td = document.createElement ('td');
		td.style.textAlign = 'left';
		td.appendChild (document.createTextNode (msg));
		tr.appendChild (td);
	}
});

//+++++++++++++++++++++++++++++++++++++++++++++++++++ HtkCalendar

var HtkCalendar = new Class
({
	Extends: HtkEntry

	,b: 1

	,initialize: function ()
	{
		var n, m;
		var table;
		var colgroup;
		var col;
		var thead;
		var tfoot;
		var tr;
		var th;
		var td;
		var year;
		var month;
		var day;
		var date;
		var txt;
		var len = TEXT_WDay.length;
		var obj = this;
		
		this.parent ('div');
		this.node.className = 'box';
		this.setSize (197, -1);
		
		table = document.createElement ('table');
		table.className = 'calendar';
		this.node.appendChild (table);

		colgroup = document.createElement ('colgroup');
		table.appendChild (colgroup);
		
		for (n = 0; n < len; n++)
		{
			col = document.createElement ('col');
			col.style.width = '14.2%'
			colgroup.appendChild (col);
		}
		
		thead = document.createElement ('thead');
		table.appendChild (thead);

		tr = document.createElement ('tr');
		thead.appendChild (tr);

		th = document.createElement ('th');
		th.appendChild (document.createTextNode ('<'));
		th.className = 'button';
		th.addEventListener ('click',
			function() { obj.prevMonth (); }, false);		
		tr.appendChild (th);

		month = document.createElement ('th');
		month.colSpan = 5;
		tr.appendChild (month);

		th = document.createElement ('th');
		th.appendChild (document.createTextNode ('>'));
		th.className = 'button';
		th.addEventListener ('click',
			function() { obj.nextMonth (); }, false);
		tr.appendChild (th);
		
		tr = document.createElement ('tr');
		thead.appendChild (tr);
		
		for (n = 1; n <= len; n++)
		{
			txt = (n != len) ? TEXT_WDay[n] : TEXT_WDay[0];
			th = document.createElement ('th');
			th.appendChild (document.createTextNode (txt));
			tr.appendChild (th);
		}

		tfoot = document.createElement ('tfoot');
		table.appendChild (tfoot);

		tr = document.createElement ('tr');
		tfoot.appendChild (tr);

		th = document.createElement ('th');
		th.appendChild (document.createTextNode ('<'));
		th.className = 'button';
		th.addEventListener ('click',
			function() { obj.prevYear (); }, false);
		tr.appendChild (th);

		year = document.createElement ('th');
		year.colSpan = 5;
		tr.appendChild (year);

		th = document.createElement ('th');
		th.appendChild (document.createTextNode ('>'));
		th.className = 'button';
		th.addEventListener ('click',
			function() { obj.nextYear (); }, false);
		tr.appendChild (th);
		
		day = document.createElement ('tbody');
		table.appendChild (day);
		
		for (m = 0; m < 6; m++)
		{
			tr = document.createElement ('tr');
			day.appendChild (tr);

			for (n = 0; n < 7; n++)
			{
				td = document.createElement ('td');
				td.style.cursor = 'pointer';
				td.addEventListener ('click',
					function () { obj.setDay (this); }, false);
				tr.appendChild (td);
			}
		}
		
		date = new Date ();
		this.emonth = month;
		this.eyear = year;
		this.day = day;
		this.date = date;
		this.month = date.getMonth ();
		this.year = date.getFullYear ();
		this.refresh ();
	}

	,refresh: function ()
	{
		var n;
		var day;
		var td;
		var start;
		var count;
		var date = this.realValue;

		setText (this.eyear, this.year);
		setText (this.emonth, TEXT_Month[this.month]);

		this.date.setDate (1);
		this.date.setMonth (this.month);
		this.date.setFullYear (this.year);

		start = this.date.getDay ();
		start = (start != 0) ? start - 1 : 6;
		count = this.monthDays (this.year, this.month);
		td = this.day.getElementsByTagName ('td');
		day = 1;

		for (n = 0; n < td.length; n++)
		{
			if (start <= n && day <= count)
			{
				td[n].day = day;
				setText (td[n], day++);
			}
			else
			{
				td[n].day = 0;
				removeChilds (td[n]);
			}
		}

		if (date instanceof Date)
		{
			this.unmarkTd ();

			if (this.year == date.getFullYear () && this.month == date.getMonth ())
			{
				var day = date.getDate ();
	
				for (n = 0; n < td.length && td[n].day != day; n++);
		
				this.markTd (td[n]);
			}
		}
	}

	,unmarkTd: function ()
	{	
		if (this.td != null)
		{
			this.td.className = undefined;
			this.td = null;
		}
	}

	,markTd: function (td)
	{
		td.className = 'highlight';
		this.td = td;
	}

	,setRealValue: function (value)
	{
		if (value instanceof Date)
		{
			this.year = value.getFullYear ();
			this.month = value.getMonth ();
			this.refresh ();
		}
	}

	,setDay: function (td)
	{
		if (td.day > 0)
		{
			var date = this.realValue;

			if (date != null)
			{
				date.setDate (td.day);
				date.setMonth (this.month);
				date.setYear (this.year);
				this.unmarkTd ();
			}
			else
				this.realValue = new Date (this.year, this.month, td.day);

			this.markTd (td);
			this.signalEmit ('changed');
		}
	}

	,prevMonth: function ()
	{
		if (this.month > 0)
			this.month--;
		else
		{
			this.month = 11;
			this.year--;
		}
		
		this.refresh ();
	}

	,nextMonth: function ()
	{
		if (this.month < 11)
			this.month++;
		else
		{
			this.month = 0;
			this.year++;
		}
		
		this.refresh ();
	}

	,prevYear: function ()
	{
		this.year--;
		this.refresh ();
	}

	,nextYear: function ()
	{
		this.year++;
		this.refresh ();
	}

	,monthDays: function (year, month)
	{
		var days;

		if (month > 6)
			days = (month % 2 != 0) ? 31 : 30;
		else if (month != 1)
			days = (month % 2 != 1) ? 31 : 30;
		else
			days = (year % 4 != 0) ? 28 : 29;

		return days;
	}

	,setEditable: function (editable) {}
});


