/**
 * Component - interface for updateable component of the layout
 *
 * {HTMLObject} container - root HTML object
 * {HTMLObject} contents - HTML object of contents
 * {Layout} layout - Layout to which the component is attached
 *
 * @constructor
 * @param {String} element - Id of the HTML object to which the component is written
 * @param {Options} options - other component specific options
 */
var Component = Class.create();
Component.prototype.initialize = function(element, options)
{
	if(typeof(options) != 'object') options = {};
	for(var i in options)
		this[i] = options[i];
	this.element = element;
	this.container = $(element);
	this.innerContainer = this.container;
	if(this.collapsible || this.draggable || this.title || this.closeable || this.shadow)
	{
		this.slideOptions = {
			before: null,
			duration: 0.3,
			queue: {
				position: 'end',
				scope: 'Component'
			}
		};
		if(this.shadow)//&& pngSupport)
		{
			var shadowContainer = this.container.appendChild(new Element('div'));
			shadowContainer.className = 'shadow_container';

			this.shadowNE = shadowContainer.appendChild(new Element('div'));
			this.shadowNE.className = 'shadowNE';
			this.shadowSW = shadowContainer.appendChild(new Element('div'));
			this.shadowSW.className = 'shadowSW';
			this.shadowSE = shadowContainer.appendChild(new Element('div'));
			this.shadowSE.className = 'shadowSE';

			this.shadowS = shadowContainer.appendChild(new Element('div'));
			this.shadowS.className = 'shadowS';
			this.shadowE = shadowContainer.appendChild(new Element('div'));
			this.shadowE.className = 'shadowE';

			this.innerContainer = this.container.appendChild(new Element('div'));
			this.slideOptions.afterUpdate = this.redrawShadow.bind(this);
			this.slideOptions.afterFinish = this.redrawShadow.bind(this);
		}

		var handle = this.innerContainer.appendChild(new Element('div'));
		handle.className = 'handle';
		if(this.closeable)
		{
			var closeButton = handle.appendChild(new ImageButton(this.close.bind(this), 'generated/icons/close.png', language('image-close'), language('image-close'), 'generated/icons/hover_close.png'));
			closeButton.className = 'close';
		}

		if(this.collapsible)
		{
			this.expandButton = new ExpandButton(this.expand.bind(this));
			this.expandButton.set(true);
			handle.appendChild(this.expandButton.getButton());
			this.slide = this.innerContainer.appendChild(new Element('div'));
			var nest = this.slide.appendChild(new Element('div'));
			this.contents = nest.appendChild(new Element('div'));
		}
		else
		{
			this.contents = this.innerContainer.appendChild(new Element('div'));
		}
		this.contents.className = 'contents'
		if(this.title)
			handle.appendChild($T(' ' + this.title));
		if(this.draggable)
		{
			this.drag = new Draggable(this.container, {
				handle: handle,
				starteffect: (function() {
					var pagePos = Position.cumulativeOffset(this.container);
					var offsetPos = this.drag.currentDelta();
					this.startPos = [pagePos[0] - offsetPos[0], pagePos[1] - offsetPos[1]];
				}).bind(this),
				snap: (function(x, y) {
					return [x, Math.max(-this.startPos[1], y)];
				}).bind(this),
				change: this.onmove.bind(this),
				endeffect: (function() { this.ondrop(); this.bringToFront(); }).bind(this)
			});
			handle.style.cursor = 'move';
			if(this.floatsToFront)
			{
				Event.observe(handle, 'mousedown', this.bringToFront.bind(this), false)
				Event.observe(this.contents, 'mousedown', this.bringToFront.bind(this), false)
			}
		}
		if(this.closeable)
		{
			handle.appendChild(new Lineclear());
		}
	}
	else
	{
		this.contents = this.container;
	}
	this.layout;
	this.expanded = true;
};

Component.prototype.close = function() {};

/**
 * Component.redrawShadow - redraws the drop shadow
 * @method
 */
Component.prototype.redrawShadow = function()
{
	if(this.shadow)// && pngSupport)
	{
		var w = this.innerContainer.getWidth();
		var h = this.innerContainer.getHeight();
		this.shadowNE.style.left = w + 'px';
		this.shadowSE.style.left = w + 'px';
		this.shadowE.style.left = w + 'px';
		this.shadowSW.style.top = h + 'px';
		this.shadowSE.style.top = h + 'px';
		this.shadowS.style.top = h + 'px';

		if(w > 6)
			this.shadowS.style.width = (w-6) + 'px'
		if(h > 6)
			this.shadowE.style.height = (h-6) + 'px';
	}
}

/**
 * Component.onmove - fires when component is moved (if set to draggable)
 * @method
 */
Component.prototype.onmove = function(drag) {};
/**
 * Component.ondrop - fires when component is dropped (if set to draggable)
 * @method
 */
Component.prototype.ondrop = function(drag) {};
/**
 * Component.bringToFront - bring component to top z-index
 * @method
 */
Component.prototype.bringToFront = function()
{
	if(this.floatsToFront)
	{
		this.container.style.zIndex = this.layout.topZIndex;
		this.layout.topZIndex++;
	}
}
/**
 * Component.expand - expand/collapse a collapsible component
 * @method
 */
Component.prototype.expand = function()
{
	if(this.expanded)
	{
		new Effect.SlideUp(this.slide, this.slideOptions);
	}
	else
	{
		new Effect.SlideDown(this.slide, this.slideOptions);
	}
	this.expanded = !this.expanded;
	this.expandButton.set(this.expanded);
};
/**
 * Component.setVisibility - sets the visibility of the entire component
 * @method
 * @param {boolean} visible - visiblity
 */
Component.prototype.setVisibility = function(visible)
{
	this.container.style.display = visible ? 'block' : 'none';
}
/**
 * Component.init - intialise the component - run after layout has been set
 * @method
 */
Component.prototype.init = function() {};
/**
 * Component.update - update the component
 * @method
 * @param {XMLNode} xml - XML data to update the component
*/
Component.prototype.update = function(xml) {};

/**
 * Layout - Container class for all components
 * @constructor
 * @param {Object} options - Initialisation options
 *
 * {int} page - The current page (list)
 * {int} lastYear, lastMonth, lastDay - The current date (calendar)
 * {String} make, model - current make and model filter
 * {String} viewMode - current view mode
 * {String} sortBy - current sort mode
 * {String} sortOrder - current sort order
 * {boolean[]} catFilters - categories in current filter
 * {Component[]} components - components attached to layout
 */
var Layout = Class.create();
Layout.prototype.initialize = function(options)
{
	if(!options) options = {};
	for(var i in options)
		this[i] = options[i];

	if(!this.page) this.page = 1; /** page */
	if(!this.sortBy) this.sortBy = 'taken';
	if(!this.sortOrder) this.sortOrder = settings.newest_first ? 'desc' : 'asc';
	if(!this.make) this.make = '';
	if(!this.model) this.model = '';
	if(!this.viewMode) this.viewMode = 'list';

	this.catFilters = {};

	if(options.catFilters)
	{
		var c = options.catFilters.split(',');
		for(var i = 0, il = c.length; i < il; i++)
			this.catFilters[c[i]] = true;
	}
	this.components = [];
	if(this.viewArea)
	{
		this.viewArea = $(this.viewArea);
		this.topZIndex = 100;
	}
	this.lastYear;
	this.lastMonth;
	this.lastDay;
}

/**
 * Layout.add
 * @method
 * @param {Component} component - Component to add to the layout
 * @param {Component[]} component - Array of components to add to the layout
 */
Layout.prototype.add = function(component)
{
	if(!(component instanceof Array))
		component = [component];
	for(var i = 0, il = component.length; i < il; i++)
	{
		if(component[i].container)
		{
			component[i].layout = this;
			if(component[i].init)
				component[i].init();

			this.components.push(component[i]);
		}
		else
		{
			throw new Error('Element "' + component[i].element + '" not found');
		}
	}
}

/**
 * Layout.loadData - load new data
 * @method
 * @aram {Object} options - Loading options
 */
Layout.prototype.loadData = function(options) // options = {mode, page, year, month, day, updateFilters, updateRecents, onSuccess}
{
	if(typeof(options) != 'object') options = {};
	options.mode = options.mode || this.viewMode;
	options.page = options.page || this.page;

	var data = {};

	data.mode = options.mode
	data.set_priv = session.setPriv ? 1 : 0;
	data.lang = setLang;
	if(options.updateFilters) data.update_filters = '';
	if(options.updateRecents) data.update_recents = '';
	if(options.updateTrees) {
		var catTrees = $A(this.components).findAll(function(component) { return component instanceof CatTree; })
		catTrees.invoke('init');
	}

	var catFiltersKeys = getKeys(this.catFilters);
	data.cat_filter = catFiltersKeys.join(",");
	data.make = this.make;
	data.model = this.model;
	data.sortby = this.sortBy;
	data.sortorder = this.sortOrder;

	switch(options.mode)
	{
		case 'list':
			data.page = options.page;
			break;

		case 'calendar':
			if(!options.year)
			{
				options.year = this.lastYear;
				options.month = this.lastMonth;
				options.day = this.lastDay;
			}
			options.day = options.day || '';

			data.year = options.year;
			data.month = options.month;
			data.day = options.day;
			break;

		case 'slideshow':
			data.page = options.page;
			data.hash = options.hash || this.ssHash;
			break;
	}

	var rpc = new RPC('ajax.loadphotos.xml.php', {
		parameters: data,
		onSuccess: (function(transport) {
			loading(false);
			this.loadSuccess(transport, options);
		}).bind(this)
	});
	loading(rpc);
}
/**
 * Layout.loadSuccess - updates all components after load
 * @method
 * @param {Transport} transport - HTTP transport object
 * @param {Object} options - Loading options
 */
Layout.prototype.loadSuccess = function(transport, options)
{
	loading(false);
	if(transport.status == 200)
	{
		var xml = transport.responseXML;
//		this.errorAlerts(xml);
		if(options.page) this.page = options.page;
		if(options.session) this.session = options.session;
		this.setViewMode(options.mode);

		for(var i = 0, il = this.components.length; i < il; i++)
			if(this.components[i].update)
				this.components[i].update(xml);

		document.body.className = (this.viewMode == 'slideshow') ? 'slideshow' : '';
	}
	else
	{
		alert('Error ' + transport.status + ': ' + transport.statusText + ' '); //lang
	}
}

/**
 * Layout.sortPhotos - sort photos
 * @method
 * @param {String} sortBy - Sort mode to use
 */
Layout.prototype.sortPhotos = function(sortBy)
{
	this.sortBy = sortBy;
	this.loadData({updateFilters: true});
}
/**
 * Layout.orderPhotos - set sort order
 * @method
 * @param {String} sortOrder - Sort mode to use
 */
Layout.prototype.orderPhotos = function(sortOrder)
{
	this.sortOrder = sortOrder;
	this.loadData({updateFilters: true});
}
/**
 * Layout.setHardware - filter by make and model
 * @method
 * @param {String} makemodel - Make and model to select
 */
Layout.prototype.setHardware = function(makemodel)
{
	if(makemodel != '')
	{
		var mm = makemodel.split(' || ');
		this.make = mm[0];
		this.model = mm[1];
	}
	else
	{
		this.make = '';
		this.model = '';
	}
	this.loadData({mode: 'list', updateFilters: true});
}
/**
 * Layout.setViewMode - change the view mode
 * @param {String} mode - View mode to use
 */
Layout.prototype.setViewMode = function(mode)
{
	if(mode != this.viewMode)
		this.lastViewMode = this.viewMode;
	this.viewMode = mode;
};

Layout.prototype.addView = function(photobox)
{
	if(this.viewArea)
	{
		var p = new Photobox();
		p.init(this, photobox.data, false);
		var view = new View(
			this.viewArea.appendChild(new Element('div')),
			{title: 'Photo view', photobox: p, draggable: true, shadow: true, closeable: true, collapsible: true, floatsToFront: true} //lang
		);
		view.layout = this;
		view.init();
	}
	else
	{
		throw new Error('viewArea not found.');
	}
}

Layout.prototype.comment = function(photobox)
{
	if(this.viewArea)
	{
		var p = new Photobox();
		p.init(this, photobox.data, false);
		var commentBox = new CommentBox(
			this.viewArea.appendChild(new Element('div')),
			{title: language('comments'), photobox: p, draggable: true, shadow: true, closeable: true, collapsible: true, floatsToFront: true} //lang
		);
		commentBox.layout = this;
		commentBox.init();
	}
	else
	{
		throw new Error('viewArea not found.');
	}
}

Layout.prototype.showCat = function(category)
{
	location.href = "index.php?filter=" + category;
}

/**
 * ViewModeMenu - Menu for changing the view mode
 * @extends Component
*/
var ViewModeMenu = Class.create(Component);

ViewModeMenu.prototype.init = function()
{
	this.contents.removeChildren();
	this.contents.appendChild($T(language('view-mode')));
	var menu = this.contents.appendChild(new Element('ul'));
	menu.appendChild(new ConditionalListItem(this.layout.loadData.bind(this.layout, {mode: 'list'}), 'List', this.layout.viewMode == 'list')); //lang
	menu.appendChild(new ConditionalListItem(this.layout.loadData.bind(this.layout, {mode: 'calendar', year: -1}), 'Calendar', this.layout.viewMode == 'calendar')); //lang
	menu.appendChild(new ConditionalListItem(this.layout.loadData.bind(this.layout, {mode: 'slideshow', hash: 'page'}), 'Slideshow', this.layout.viewMode == 'slideshow')); //lang
}

ViewModeMenu.prototype.update = ViewModeMenu.prototype.init;

/**
 * AccessModeMenu - Menu for changing the access mode
 * @extends Component
*/
var AccessModeMenu = Class.create(Component);

AccessModeMenu.prototype.init = function()
{
	this.update();
}

AccessModeMenu.prototype.update = function()
{
	this.contents.removeChildren();
	var menu = this.contents.appendChild(new Element('ul'));
	menu.className = 'menu access';
	menu.appendChild(new ConditionalListItem(this.setPriv.bind(this, true), language('private'), session.setPriv));
	menu.appendChild(new ConditionalListItem(this.setPriv.bind(this, false), language('public'), !session.setPriv));
}

AccessModeMenu.prototype.setPriv = function(mode)
{
	session.setPriv = mode;
	session.priv = mode;
	this.layout.loadData({updateFilters: true, updateRecents: true, updateTrees: true});
}

/**
 * ConditionalListItem - generates a list item, either a link or text if the condition is true
 * @constructor
 * @param {Function} f - function to trigger when link clicked
 * @param {String} text - link text
 * @param {boolean} isSelected - item selected flag
 */
function ConditionalListItem(f, text, isSelected)
{
	var listItem = new Element('li');
	if(isSelected)
	{
		listItem.appendChild(new Span(text));
	}
	else
	{
		listItem.appendChild(new TextButton(f, text));
	}
	return listItem;
}

/**
 * SortMenu - Menu for changing the access mode
 * @extends Component
*/
var SortMenu = Class.create(Component);

/**
 * SortMenu items, multidimensional array [[value, title, function], ... ]
 * {String} value - value identifying sort type
 * {String} title - option text
 * {Function} function - optional, function returning boolean which determines if the option is displayed
 */
SortMenu.prototype.items = [
	['taken', 'Date taken'], //lang
	['added', 'Date added'], //lang
	['views', language('views'), function() { return !settings.disable_stats; }],
	['perday', 'Views per day', function() { return !settings.disable_stats; }], //lang
	['pixels', language('resolution')],
	['aspect', language('aspect-ratio')],
	['bytes', language('filesize')]
];

SortMenu.prototype.init = function()
{
	this.contents.removeChildren();
	this.contents.appendChild($T('Sort by')); //lang
	this.contents.appendChild(new Element('br'));
	var sortSelect = this.contents.appendChild(new Element('select'));
	Event.observe(sortSelect, 'change', (function() { this.layout.sortPhotos(sortSelect.value); }).bind(this));

	for(var i = 0, il = this.items.length; i < il; i++)
		if(typeof this.items[i][2] == 'undefined' || this.items[i][2]())
			sortSelect.appendChild(new OptionItem(this.items[i][0], this.items[i][1], this.layout.sortBy));

	var orderSelect = this.contents.appendChild(new Element('select'));
	Event.observe(orderSelect, 'change', (function() { this.layout.orderPhotos(orderSelect.value); }).bind(this));
	orderSelect.appendChild(new OptionItem('desc', 'Descending', this.layout.sortOrder)); //lang
	orderSelect.appendChild(new OptionItem('asc', 'Ascending', this.layout.sortOrder)); //lang
};

SortMenu.prototype.update = function()
{
	this.setVisibility(this.layout.viewMode == 'list');
};

/**
 * OptionItem - creates an option element for a select list
 * @construtor
 * @param {String} val - option value
 * @param {String} text - option text
 * @param {String} selectedVal - value of selected option in select list
*/
function OptionItem(val, text, selectedVal)
{
	var o = new Element('option');
	o.value = val;
	o.appendChild($T(text));
	if(val == selectedVal)
		o.selected = true;
	return o;
}

/**
 * Permalink - Menu for changing the access mode
 * @extends Component
*/
var Permalink = Class.create(Component);

Permalink.prototype.init = function()
{
	var vars = {};
	var catFiltersKeys = getKeys(this.layout.catFilters);
	if(catFiltersKeys.length > 0)
		vars.filter = catFiltersKeys.join(",");
	if(this.layout.page != 1)
		vars.page = this.layout.page;
	if(this.layout.viewMode != 'list')
		vars.view_mode = this.layout.viewMode;
	if(this.layout.viewMode == 'calendar')
	{
		vars.year = this.layout.lastYear;
		vars.month = this.layout.lastMonth;
		if(this.layout.lastDay)
			vars.day = this.layout.lastDay;
	}
	if(this.layout.viewMode == 'slideshow')
		vars.hash = this.layout.ssHash;

	if(this.layout.sortBy != 'taken')
		vars.sortby = this.layout.sortBy;

	vars.sortorder = this.layout.sortOrder;

	if(this.layout.make != '' || this.layout.model != '')
	{
		vars.make = escape(this.layout.make)
		vars.model = escape(this.layout.model);
	}

	var text = session.linkBase + '?' + $H(vars).toQueryString();

	this.contents.href = text;
	this.contents.innerHTML = text;
}
Permalink.prototype.update = Permalink.prototype.init;

/**
 * ExpandButton - expand/collapse button ([+]/[-])
 * @constructor
 * @param {Function} f - onclick function
 */
var ExpandButton = Class.create();
ExpandButton.prototype.initialize = function(f)
{
	this.img = new Element('img');
	this.img.clickHandler = f;
	this.img.style.cursor = 'pointer';
	this.img.alt = '+/-';
};
/**
 * ExpandButton.getButton - get HTMLObject
 * @method
 * @return {HTMLObject} - the expand button
 */
ExpandButton.prototype.getButton = function()
{
	return this.img;
}
/**
 * ExpandButton.set - set the expand button graphic
 * @method
 * @param {boolean} isExpanded - new state
 * @param {boolean} isNode - item is a node (can't be expanded)
 */
ExpandButton.prototype.set = function(isExpanded, isNode)
{
	var icon = !isNode ? (isExpanded ? 'minus' : 'plus') : 'plusnew';

	this.img.src = settings.images_out[icon];
	this.img.onmouseover = (function() {
		this.src = settings.images_over[icon];
	}).bind(this.img);
	this.img.onmouseout = (function() {
		this.src = settings.images_out[icon];
	}).bind(this.img);
};

/**
 * View - view window
 * @extends Component
 */
var View = Class.create(Component, {
	init: function() {
		//hide metapopups in all PhotoAreas
		if(typeof(PhotoArea) != 'undefined') {
			var photoAreas = $A(this.layout.components).findAll(function(component) { return component instanceof PhotoArea; })
			photoAreas.each(function(photoArea) {
				$H(photoArea.photoBoxes).each(function(pair) {
					var photoBox = pair[1];
					photoBox.metaHide2(true);
				});
			});
		}

		this.innerContainer.className = 'view_window window';
		Position.prepare();
		this.container.style.top = (10 + Position.deltaY) + 'px';
		this.innerContainer.style.width = (this.photobox.viewWidth + 10) + 'px';
		this.container.style.left = -(10 + this.photobox.viewWidth) / 2 + 'px';
		this.container.style.position = 'absolute';
		this.bringToFront();

		var image = this.contents.appendChild(new Element('div'));
		image.className = 'throbber';
		image.style.height = this.photobox.viewHeight + 'px';
		this.contents.appendChild(this.photobox.getButtons({noViewButton: true}));

		var permalink = this.contents.appendChild(new Element('div'));
		permalink.className = 'small';
		permalink.appendChild($T('Link to this image: '));
		var a = permalink.appendChild(new Element('a'));
		a.href = session.linkBase + '?view_mode=slideshow&hash=' + this.photobox.hash;
		a.innerHTML = '...?view_mode=slideshow&hash=' + this.photobox.hash;
		this.redrawShadow();

		new RPC('ajax.loadphotos.xml.php', {
			parameters: {
				mode: 'view',
				hash: this.photobox.hash,
				priv: session.priv ? 1 : 0,
				lang: setLang
			},
			onSuccess: (function(transport) {
				image.appendChild(new ImageButton(this.close.bind(this), this.photobox.getViewSrc(), language('loading'), language('image-close')));
				var xml = transport.responseXML;
				this.contents.appendChild(this.photobox.getMetaBar(xml));
				var photos = xml.getElementsByTagName('photo');
				this.photobox.loadPhotoXML(photos[0]);
				image.removeChildren();
				image.appendChild(new ImageButton(this.close.bind(this), this.photobox.getViewSrc(), '', language('image-close')));
				this.redrawShadow();
			}).bind(this)
		});
	},

	/**
	 * View.close - close the view window
	 * @method
	 */
	close: function() {
		this.layout.viewArea.removeChild(this.container);
	}
});

/**
 * CommentBox - comment box
 * @extends Component
 */
var CommentBox = Class.create(Component, {
	init: function() {
		this.innerContainer.className = 'comments_window window';
		Position.prepare();
		this.container.style.top = (100 + Position.deltaY) + 'px';
		this.innerContainer.style.width = (600 + 10) + 'px';
		this.container.style.left = -(10 + 600) / 2 + 'px';
		this.container.style.position = 'absolute';
		this.bringToFront();
	
		this.contents.appendChild(this.photobox.getPhotobox({noCommentsButton: true}));
		var menu = this.contents.appendChild(new Element('ul'));
		menu.className = 'menu';
		menu.appendChild(new ConditionalListItem(this.loadReadCommentsPanel.bind(this), 'read comments'));
		menu.appendChild(new ConditionalListItem(this.loadWriteCommentsPanel.bind(this), 'add comment'));
	
		this.commentsPanel = this.contents.appendChild(new Element('div'));
		this.commentsPanel.className = 'comments';
		this.photobox.comments ? this.loadReadCommentsPanel() : this.loadWriteCommentsPanel();
	
		this.contents.appendChild(new Lineclear());
		this.redrawShadow();
	},
	
	loadReadCommentsPanel: function() {
		new RPC('ajax.loadmetadata.xml.php', {
			parameters: {
				mode: 'comments',
				hash: this.photobox.hash
			},
			onSuccess: (function(transport) {
				this.updateReadCommentsPanel(transport.responseXML);
			}).bind(this)
		});
		this.redrawShadow();
	},
	
	updateReadCommentsPanel: function(xml) {
		this.commentsPanel.removeChildren();
		var comments = xml.getElementsByTagName('comment');
		if(comments.length)
		{
			for(var i = 0, il = comments.length; i < il; i++)
			{
				var name = comments[i].getAttribute('name');
				var email = comments[i].getAttribute('email');
				var time = comments[i].getAttribute('time');
				var commentData = getNodeValue(comments[i]);
	
				var comment = this.commentsPanel.appendChild(new Element('div'));
				comment.className = 'comment';
				var commentName = comment.appendChild(new Element('div'));
				commentName.className = 'comment_name';
				commentName.appendChild($T(name));
				if(email)
				{
					var emailLabel = commentName.appendChild(new Element('small'));
					emailLabel.appendChild($T(' (' + email + ')'));
				}
				commentName.appendChild($T(':'));
				var commentText = comment.appendChild(new Element('div'));
				commentText.className = 'comment_text';
				commentText.appendChild($T(commentData.unescapeHTML()));
				var commentTime = comment.appendChild(new Element('div'));
				commentTime.className = 'comment_time';
				commentTime.appendChild($T(language('posted') + ': ' + time));
			}
		}
		else
		{
			this.commentsPanel.appendChild($T(language('no-comments')));
		}
		this.redrawShadow();
	},
	
	loadWriteCommentsPanel: function() {
		var label;
		var column;
	
		this.commentsPanel.removeChildren();
		column = this.commentsPanel.appendChild(new Element('div'));
		column.className = 'column';
		label = column.appendChild(new Element('label'));
		label.className = 'small';
		label.appendChild($T('Name:')); //lang
		column.appendChild(new Element('br'));
		this.nameBox = new Element('input');
		this.nameBox.type = 'text';
		this.nameBox.value = session.name || session.userName || '';
		column.appendChild(this.nameBox);
		column.appendChild(new Element('br'));
		this.nameBox.attachLabel(label);
	
		column = this.commentsPanel.appendChild(new Element('div'));
		column.className = 'column';
		label = column.appendChild(new Element('label'));
		label.className = 'small';
		label.appendChild($T('Email:')); //lang
		column.appendChild(new Element('br'));
		this.emailBox = new Element('input');
		this.emailBox.type = 'text';
		this.emailBox.value = session.email || '';
		column.appendChild(this.emailBox);
		column.appendChild(new Element('br'));
		this.emailBox.attachLabel(label);
	
		this.commentBox = this.commentsPanel.appendChild(new Element('textarea'));
	
		var submitButton = new Element('input');
		submitButton.type = 'button';
		this.commentsPanel.appendChild(submitButton)
		submitButton.clickHandler = this.post.bind(this);
		submitButton.value = language('postcomment-button');
		this.redrawShadow();
	},
	
	post: function() {
		if(!this.commentBox.value)
		{
			alert(language('alert-no-comment'));
			return;
		}
		var rpc = new RPC('ajax.postcomment.xml.php', {
			parameters: {
				hash: this.photobox.hash,
				name: this.nameBox.value,
				email: this.emailBox.value,
				comment: this.commentBox.value
			},
			method: 'post',
			onSuccess: (function(transport) {
				this.updateReadCommentsPanel(transport.responseXML);
			}).bind(this)
		});
	},
	
	/**
	 * CommentBox.close - close the comment box
	 * @method
	 */
	close: function() {
		this.layout.viewArea.removeChild(this.container);
	}
});