/**
 * CatTree
 * @extends Component
 *
 * @private {Leaf[]} leaves - indexed array of all loaded leaves
 * {Leaf} reparentRoot - leaf for the root, shown when reparenting
 * {int} moveCategory - index for leaf to be reparented
 */
var CatTree = Class.create(Component);

CatTree.prototype.init = function()
{
	this.leaves = {};
	this.moveCategory = -1;

	var root = new this.leafClass(this);
	root.category = 0;
	root.catName = 'root';
	this.leaves[0] = root;

	this.contents.removeChildren();
	this.contents.appendChild(root.getLeaf());
	root.expand(true, true);
}

CatTree.prototype.slideOptions = {
	before: null,
	duration: 0.4,
	queue: {
		position: 'end',
		scope: 'CatTree'
	}
};
/**
 * CatTree.updateTree - update modified leaves of the tree
 * @method
 * @param {XMLNode} xml - XML data
 */
CatTree.prototype.updateTree = function(xml)
{
	var categories = xml.getElementsByTagName('category');
	$A(categories).each(function(cat) {
		var category = parseInt(cat.getAttribute('category'));
		if(this.leaves[category]) {
			this.leaves[category].init(cat);
			this.leaves[category].expand(true, true);
		}
	}, this);
};
/**
 * CatTree.writeBranches - write a branch of leaves
 * @method
 * {XML} xml - XML request data
 * {boolean} noAnim - flag to disable animation (slide effect)
 */
CatTree.prototype.writeBranches = function(xml, noAnim)
{
	var children = xml.getElementsByTagName('children');
	$A(children).each(function(cats) {
		var category = parseInt(cats.getAttribute('category'));
		var parentLeaf = this.leaves[category];
		parentLeaf.loaded = true;
		parentLeaf.branch.removeChildren();
		this.writeCategories(parentLeaf, cats);

		if(noAnim)
		{
			parentLeaf.branch.show();
			parentLeaf.slide.show();
		}
		else
		{
			this.slideOptions.beforeStart = function() {
				parentLeaf.slide.hide()
			}
			new Effect.SlideDown(parentLeaf.slide, this.slideOptions);
		}
	}, this);
}

CatTree.prototype.writeCategories = function(parentLeaf, children)
{
	var parentCat = parseInt(children.getAttribute('category'));
	var parentName = children.getAttribute('name');

	var categories = children.getElementsByTagName('category');
	if(categories.length)
	{
		for(var i = 0, il = categories.length; i < il; i++)
		{
			var leaf = new Leaf(parentLeaf.catTree, categories[i]);
			this.leaves[leaf.category] = leaf;
			parentLeaf.branch.appendChild(leaf.getLeaf());
		}
	}
	else
	{
		var leafNotice = parentLeaf.branch.appendChild(new Element('li'));
		leafNotice.className = 'leaf notice';
		leafNotice.innerHTML = language('no-public-photos');
	}
}

/**
 * Leaf - class to represent a leaf node
 * @constructor
 * @param {CatTree} catTree - containing category tree
 * @param {XMLNode} xml - initalising XML data
 *
 * {CatTree} catTree - containing category tree
 * {boolean} expanded, loaded - state of the leaf
 * {boolean} located, hasCords - category properties
 * {boolean} isLeaf - is node a leaf node (no children)
 * {String} catName - category name
 * {int} category - category Id
 * {HTMLObject} slide, branch - containers for branch
 * {HTMLObject} textbox - pointer to name textbox input (edit mode)
 */
var Leaf = Class.create();
Leaf.prototype.initialize = function(catTree, xml)
{
	this.catTree = catTree;
	if(xml)
		this.init(xml)
}
/**
 * Leaf.init - intialise leaf
 * @method
 * @param {XMLNode} xml - XML data
 */
Leaf.prototype.init = function(xml)
{
	this.expanded = false;
	this.loaded = false;
	this.catName = xml.getAttribute('name');
	this.category = parseInt(xml.getAttribute('category'));
	this.isLeaf = parseInt(xml.getAttribute('isleaf')) ? true : false;
	this.located = parseInt(xml.getAttribute('located')) ? true : false;
	this.hasCoords = parseInt(xml.getAttribute('hascoords')) ? true : false;
};
/**
 * Leaf.getLeaf - renders the leaf node
 * @method
 * @return {HTMLObject} - the leaf node HTMLObject
 */
Leaf.prototype.getLeaf = function()
{
	this.slide = new Element('div');
	this.slide.hide()
	var nest = this.slide.appendChild(new Element('div'));
	this.branch = nest.appendChild(new Element('ul'));

	var leafItem = new Element('li');
	leafItem.className = 'leaf';

	if(this.category)
	{
		this.branch.className = 'branch';

		this.writeExpandButton(leafItem);
		this.writeLeafText(leafItem);
	}
	else
	{
		this.branch.className = 'tree';
		this.catTree.reparentRoot = leafItem.appendChild(new Element('span'));
		this.catTree.reparentRoot.appendChild($T('root'));
		this.catTree.reparentRoot.hide();
		this.textbox = this.catTree.reparentRoot;
	}
	if(this.makeDroppable)
		this.makeDroppable(leafItem);
	leafItem.appendChild(this.slide);
	return leafItem;
};

Leaf.prototype.writeExpandButton = function(leafItem)
{
	if(!this.isLeaf)
	{
		this.expandButton = new ExpandButton(this.expand.bind(this, false, false));
		this.expandButton.set(false, this.isLeaf);
		leafItem.appendChild(this.expandButton.getButton());
	}
	else
	{
		var nodeButton = leafItem.appendChild(new Element('img'));
		nodeButton.src = settings.images_out.empty;
		nodeButton.alt = ' ';
	}
};

Leaf.prototype.writeLeafText = function(leafItem)
{
	leafItem.appendChild(new TextButton(this.catTree.layout.showCat.bind(this.catTree.layout, this.category), this.catName));
	if(this.located && settings.google_maps_key)
		leafItem.appendChild(new ImageButton(this.catTree.layout.geoTag.bind(this.catTree.layout, this.category), 'generated/icons/' + (this.hasCoords ? 'geotag' : 'located') + '.png', 'geotag', 'Geotag', 'generated/icons/hover_' + (this.hasCoords ? 'geotag' : 'located') + '.png')); //lang
};

/**
 * Leaf.expand - expand/collapse the leaf node
 * @method
 * @param {boolean} noAnim - disable animation (slide effect)
 * @param {boolean} forceOpen - expand the leaf regardless of current state
 */
Leaf.prototype.expand = function(noAnim, forceOpen)
{
	if(this.isLeaf)
	{
		if(forceOpen)
		{
			//category has just been made childless
			this.setExpand(false);
			this.branch.removeChildren();
		}
		else
		{
			this.catTree.addChild(this.category, this.catName);
		}
		return;
	}
	if(!this.expanded || forceOpen)
	{
		if(!this.loaded)
		{
			new RPC('ajax.loadchildren.xml.php', {
				parameters: {
					category: this.category,
					priv: session.priv ? 1 : 0
				},
				onSuccess: (function(transport) {
					this.catTree.writeBranches(transport.responseXML, noAnim);
				}).bind(this)
			});
		}
		else
		{
			if(noAnim)
			{
				this.branch.show();
				this.slide.show();
			}
			else
			{
				this.catTree.slideOptions.beforeStart = (function() {
					this.slide.hide()
				}).bind(this);
				new Effect.SlideDown(this.slide, this.catTree.slideOptions);
			}
		}
		this.setExpand(true);
	}
	else
	{
		this.catTree.slideOptions.beforeStart = this.setExpand.bind(this, false);
		new Effect.SlideUp(this.slide, this.catTree.slideOptions);
	}
};
/**
 * Leaf.setExpand - set expand state and update icon
 * @method
 * @param {boolean} isExpanded - new state
 */
Leaf.prototype.setExpand = function(isExpanded)
{
	this.expanded = isExpanded;
	if(this.expandButton)
		this.expandButton.set(isExpanded, this.isLeaf);
}

CatTree.prototype.leafClass = Leaf;
