﻿var gShowCheckbox = false;		// show/hide checkboxes within the outlines
var gIsEditable = true;			// read-only as on ideas page or fully editable
var gHandleClicked = false;		// this is to block click throughs to row container divs. Sort of a hack :(
var _row_id = 0;				// i have put the _ prefix so that we don't change this value by mistake.

var gCurrentWidth = 320;
var gCounter = 1;
var gExpandedRows = new Array();
var gSelectedRow = "";
var gOutlines = new Array();
var gColor = '#000';			// Row colour.
var gSelectedColor = '';		// colour selected by user. takes effect only when adding a row
var gKeyboard = true;			// true: key board shortcuts enabled
								// false: ekyboard shortcuts disabled (used when focus is on edit box)
								// shortcuts are handled in outliner_shortcuts.js
							
							
function OutlinerInit()
{
var outliner = document.getElementById('outliner');
	
	if (Element.hasClassName(outliner, 'editable'))
	{
		GetOPML();
		SetActionButtonStates();
		gSelectedColor = GetColorFromIndex(gColorIdx);			// gColorIdx is set from server, based on value stored in cookie
	}
	else
	{
		gIsEditable = false;		
	}
	
	if (window.addEventListener)
		window.addEventListener('click', HandleClick, false);
	else document.attachEvent('onclick', HandleClick);
	
	if (navigator.userAgent.match(/iPhone/i))
	{
		setInterval(UpdateLayout, 300);
    }
}

function GetOutlineById(id)
{
	for (var i = 0; i < gOutlines.length; i++)
	{
		if (gOutlines[i].getId() == id)
			return gOutlines[i];
	}
}

function GetNewId()
{
	_row_id++;
	return _row_id;
}

// this function gets called once when the page loads
function GetOPML()
{
/*	new Ajax.Request("/complete/getOPML.php",
	{
		method:'post',
		onSuccess: LoadOPML,
		parameters: { key: gDocKey },
		onFailure: function(){ alert('Something went wrong...'); }
	});	
*/
	
}

// completion code for GetOPML
function LoadOPML(t)
{
var response = t.responseXML.documentElement;
var opml_title = response.getElementsByTagName('title')[0].firstChild.data;
var opml_body = response.getElementsByTagName('body')[0];
var expansionState = response.getElementsByTagName('expansionState')[0].firstChild.data;		 // we need to use this to collapse rows

	gExpandedRows = (expansionState != "0") ? expansionState.split(',') : new Array();

	DeselectRow();
	ClearOutliner();

var children = new Array();
var n = opml_body.firstChild;

	while (n)
	{
		if (n.nodeType == 1)
			children[children.length] = n;
		n = n.nextSibling;
	}

var	parent_stack = new Array();
	parent_stack[0] = '-1';
	GenerateOutliner(parent_stack, children);

	PaintBackground();

	// now that the data is loaded, we can show the container divs
	document.getElementById('outliner').style.display = "block";

	if (gIsEditable)
	{		
		document.getElementById('comments').style.display = "block";

		if (gUserAgent != 'iphone')															// on iPhone we don't want to show edit box
		{
			document.getElementById('edit-box').style.display = "block";
			initStatLyr();
		}
	}
	gHandleClicked = false;								
}

function Snag()
{
var opml_title = xmlDoc.getElementsByTagName('title')[0].firstChild.data;
var opml_body = xmlDoc.getElementsByTagName('body')[0];
var expansionState = xmlDoc.getElementsByTagName('expansionState')[0].firstChild.data;		 // we need to use this to expand rows

//	document.getElementById('meta-title').innerHTML = opml_title;

	gExpandedRows = (expansionState != "0") ? expansionState.split(',') : new Array();

	DeselectRow();
	ClearOutliner();

var children = new Array();
var n = opml_body.firstChild;

	while (n)
	{
		if (n.nodeType == 1)
			children[children.length] = n;
		n = n.nextSibling;
	}

	parent_stack = new Array();
	parent_stack[0] = '-1';
	GenerateOutliner(parent_stack, children);

	PaintBackground();
}


function GenerateOutliner(parent_stack, children)
{
	for (var i = 0; i < children.length; i++)
	{
		gCounter++;

	var txt = (children[i].getAttribute('text')) ? children[i].getAttribute('text') : "";
	var	row = CreateRow(txt);

		// dump attributes into gOutlines array.
	var lOutline = new Outline();
	var attrs = children[i].attributes;

		lOutline.setId(row.id);

		for(var a=0; a<attrs.length; a++)
        	lOutline.setAttribute(attrs[a].name, NormaliseText(attrs[a].value, 'opml2attr'));

		gOutlines[gOutlines.length] = lOutline;

		AppendAsChild(parent_stack[parent_stack.length-1], row);
		IndentRow(row, parent_stack.length);

		// check if _status is checked, if yes, then show row as checked
		cur_outline = GetOutlineById(row.id);
		if (cur_outline.getAttribute('_status') == 'checked')
			SetRowStatus(row.id, 'checked');

		// set color of the text
		if (cur_outline.getAttribute('_color'))
			SetRowColor(row.id, cur_outline.getAttribute('_color'));

		// set handle image for the new row
		ChangeRowHandle(row, 'leaf');

		if (children[i].hasChildNodes() && CountChildren(children[i]) != 0)					// row has children
		{
			parent_stack[parent_stack.length] = row.id;
			CreateContainerForChildren(row);

			HideChildren(row.id, false);							// default status is collapsed.

			for (var j = 0; j < gExpandedRows.length; j++)			// check if this row should be expanded
			{
				if (row.id == gExpandedRows[j])
					ShowChildren(row.id, false);
			}

			// create children array
			c = new Array();
			n = children[i].firstChild;
			while (n)
			{
				if (n.nodeType == 1)
					c[c.length] = n;
				n = n.nextSibling;
			}

			GenerateOutliner(parent_stack, c);
			p = parent_stack.pop();
		}
	}
}

function CountChildren(row)
{
	if (row.hasChildNodes())
	{
	var child = row.firstChild;
	var num_children = 0;
		while (child)
		{
			if (child.nodeType == 1)
				num_children++;

			child = child.nextSibling;
		}
		return num_children;
	}
	else return 0;
}

function SaveAsOPML()
{
	root = document.getElementById('outliner-root');
	gExpandedRows = new Array();						// empty the array
	gCounter = 1;

	var children = new Array();
	var n = root.firstChild;
	while (n)
	{
		if (n.nodeType == 1)
			children[children.length] = n;
		n = n.nextSibling;
	}

	var content = GenerateOPML(children);
	var expansionState = gExpandedRows.join();
	if (!expansionState)
		expansionState = 0;

	var code =  '<opml version="1.0">\r\n';
		code += '<head>\r\n';
		code += '<title>Untitiled Outline</title>\r\n';
		code += '<expansionState>' + expansionState + '</expansionState>\r\n';
		code += '</head>\r\n';
		code += '<body>\r\n';
		code += content;
		code += '</body>\r\n';
		code += '</opml>\r\n';

	SendOPML(code);
}

function GenerateOPML(children)
{
	var code = "";
	for (var i = 0; i < children.length; i++)
	{
		if (Element.hasClassName(children[i], 'children'))
			continue;
		else
		{
			next_row = children[i].nextSibling;
			if (next_row && Element.hasClassName(next_row, 'children'))
			{
				if (children[i].nextSibling.style.display == 'block')
					gExpandedRows.push(gCounter);

				gCounter++;
				cur_outline = GetOutlineById(children[i].id)
				row_attributes = cur_outline.getAttributesAsString();
				code += '<outline ' + row_attributes + '>\r\n';

				// create children array
				c = new Array();
				n = children[i].nextSibling.firstChild;

				while (n)
				{
					if (n.nodeType == 1)
						c[c.length] = n;
					n = n.nextSibling;
				}

				code += GenerateOPML(c);
				code+= '</outline>\r\n';
			}
			else
			{
				try
				{
					cur_outline = GetOutlineById(children[i].id)
					row_attributes = cur_outline.getAttributesAsString();
					code += '<outline ' + row_attributes + '/>\r\n';

					gCounter++;
				}
				catch(err)
				{

				}
			}
		}
	}
	return code;
}

// called each time we have some data that has changed
function SendOPML(opml_code)
{
var parser;
var doc;

	if (window.ActiveXObject)											// code for IE
	{
		doc = new ActiveXObject("Microsoft.XMLDOM");
		doc.async = "false";
		doc.loadXML(opml_code);
	}
	else																// code for Mozilla, Firefox, Opera, etc.
	{
		parser = new DOMParser();
		doc = parser.parseFromString(opml_code,"text/xml");
	}
	
	gResponse = doc.documentElement;

	new Ajax.Request("/complete/getOPML.php",
	{
		method:'post',
		parameters: { opml:opml_code, key: gDocKey, color: gColor },
		onFailure: function(){ alert('Something went wrong...'); }
	});
}

function CreateCheckbox(row_div)
{
var checkbox = document.createElement('img');
	checkbox.id = "check" + new_id;
	checkbox.src = "/images/icn_chk_unchecked.png";
	checkbox.className = "checkbox";

	row_div.appendChild(checkbox);
}

function SetCheckboxStatus(row_id, status)
{
var row_chkbox = document.getElementById('check'+row_id);

	if (status == 'checked')
		row_chkbox.src = "/images/icn_chk_checked.png";
	else row_chkbox.src = "/images/icn_chk_unchecked.png";
}

function CreateRow(txt)
{
var	content = NormaliseText(txt, 'opml2attr');
var	disp_content = (!content) ? "&nbsp;" : NormaliseText(content, 'html');
var lparent;

	if (gSelectedRow)		// a row is selected
	{
		sel = document.getElementById(gSelectedRow);
		lparent = sel.parentNode;
	}
	else lparent = document.getElementById('outliner-root');

	new_id = GetNewId();

var bullet_img = document.createElement('img');
	bullet_img.id = "handle" + new_id;

var txt_span = document.createElement('span');

	txt_span.id='r'+new_id;
	txt_span.innerHTML = disp_content;

	var wrapper_div =  document.createElement('div');
	wrapper_div.id = 'div'+new_id;
	wrapper_div.className = 'row';

	wrapper_div.appendChild(bullet_img);
	if (gShowCheckbox) CreateCheckbox(wrapper_div);
	wrapper_div.appendChild(txt_span);

//	wrapper_div.setAttribute('onClick',"SelectRow('" + new_id + "')");
//	wrapper_div.setAttribute('onmouseOver',"ShowHolder('div" + new_id + "')");
//	wrapper_div.setAttribute('onmouseOut',"HideHolder('div" + new_id + "')");

	wrapper_div.onclick = function(evt) { SelectRow(getTargetElement(evt).id.replace(/(r|div|handle)(.*)/g, '$2')); };
	wrapper_div.onmouseover = function(evt) { ShowHolder('div'+getTargetElement(evt).id.replace(/(r|div|handle)(.*)/g, '$2')); };
	wrapper_div.onmouseout = function(evt) { HideHolder('div'+getTargetElement(evt).id.replace(/(r|div|handle)(.*)/g, '$2')); };

	var div = document.createElement('div');
	div.id = new_id;
	div.style.display = 'block';

	div.appendChild(wrapper_div);

	return div;
}

function AddRow()
{		
var row = CreateRow('');
var lOutline = new Outline();
	lOutline.setId(row.id);
	lOutline.setAttribute('text', '');
	
var lparent;
	if (gSelectedRow)		// a row is selected
	{
		sel = document.getElementById(gSelectedRow);
		lparent = sel.parentNode;
	}
	else lparent = document.getElementById('outliner-root');

	gOutlines[gOutlines.length] = lOutline;

	if (gSelectedRow)
	{
		next_row = GetNextElementSibling(sel);

		if (Element.hasClassName(next_row, 'children'))			// selected row has children, insert new one as child to this one
		{
			if (next_row.style.display == 'block')					// if sel is expanded, we add as child
				next_row.insertBefore(row, next_row.firstChild);
			else lparent.insertBefore(row, sel.nextSibling.nextSibling);		// else add below it
		}
		else lparent.insertBefore(row, sel.nextSibling);
	}
	else lparent.appendChild(row);

	ChangeRowHandle(row, 'leaf');											// set handle image for the new row
	
	var sel_row = document.getElementById(gSelectedRow);

	ReIndentChildren(lparent);
	SelectRow(row.id);
	PaintBackground();
	SetTextBoxColor(gSelectedColor);
	UpdateCompletionStatus(sel_row);
	SaveAsOPML();
}

function DeleteRow()
{
	if (gSelectedRow)
	{
		sel = document.getElementById(gSelectedRow);
		next_row = GetNextElementSibling(sel);
		prev_row = GetPreviousElementSibling(sel);
		prev_sibling = null;
		if (prev_row)
		{
			if (Element.hasClassName(prev_row, 'children'))
				prev_sibling = GetPreviousElementSibling(prev_row);
			else prev_sibling = prev_row;
		}
		
		lparent = sel.parentNode;
		if (lparent && lparent.id != 'outliner-root')
			parent_row = lparent.previousSibling;
		else parent_row = null;											// top level row

		var agreed = true;
		var new_selection = null;
		if (next_row)
		{
			if (Element.hasClassName(next_row, 'children'))				// row has children
			{
				if (GetNextElementSibling(next_row))					// there is a sibling after the children
					new_selection = GetNextElementSibling(next_row);
				else if (prev_sibling)
					new_selection = prev_sibling;						// no next row, select previous sibling
				else if (parent_row)
					new_selection = parent_row;							// no siblings; select parent		
			}
			else new_selection = next_row;								// no children, there is a sibling, select it
			
			if (Element.hasClassName(next_row, 'children'))
				agreed = window.confirm("This item contains children which will also get deleted if you proceed. Do you want to continue?");
		}
		else if (prev_sibling)
			new_selection = prev_sibling;								// no next row, select previous sibling
		else if (parent_row)
			new_selection = parent_row;									// no next row, select parent

		if (agreed)
		{
			DeselectRow();												// first deselect the row; this will also disable buttons
			lparent = sel.parentNode;
			lparent.removeChild(sel);

			if (lparent)
				parent_row = lparent.previousSibling;

			if (next_row && Element.hasClassName(next_row, 'children'))	// selected row contained children, delete them too
				lparent.removeChild(next_row);

			if (lparent != document.getElementById('outliner-root'))	// if the deleted row was the only child for the parent, delete the ul also.
			{
				grandparent = lparent.parentNode;						// grandparent DIV

				if (!lparent.hasChildNodes())
				{
					grandparent.removeChild(lparent);

					if (parent_row)
						ChangeRowHandle(parent_row, 'leaf');
				}
				UpdateCompletionStatus(parent_row);
			}
			
			if (new_selection)
			{
				SelectRow(new_selection.id);
			}

			ReIndentChildren(lparent);
			PaintBackground();
			SaveAsOPML();
		}
	}
}

function TabRow()
{
var sel = document.getElementById(gSelectedRow);
var prev_row = GetPreviousElementSibling(sel);
var next_row = GetNextElementSibling(sel);
var has_children = false;

	if (prev_row)												// make this row a child of the previous row
	{
		rootleft = document.getElementById('outliner').offsetLeft;
		wrapper_div = document.getElementById('div'+gSelectedRow);
		newleft = document.getElementById('r'+gSelectedRow).offsetLeft - rootleft;
		
		if (next_row && Element.hasClassName(next_row, 'children'))			// if selected row had children, dump them into children_li
		{
			has_children = true;
			var children = sel.nextSibling;
		}

		if (Element.hasClassName(prev_row, 'children'))			// prev row already has children, so we append to that list
		{
			prev_row.appendChild(sel);
			if (has_children)
				prev_row.appendChild(children);
		}
		else													// prev row doesn't have any children as yet, this is the first one
		{
		var children_div = document.createElement('div');
			AddClass(children_div, 'children');
			children_div.style.display = 'block';
			children_div.appendChild(sel);

			lparent = prev_row.parentNode;
			lparent.insertBefore(children_div, prev_row.nextSibling);
			if (has_children)
				sel.parentNode.insertBefore(children, sel.nextSibling);

			// change handle icon for parent li
			ChangeRowHandle(prev_row, 'expanded');
		}
	}

	var siblingNodes = sel.parentNode.childNodes;
	for (var i = 0; i < siblingNodes.length; i++)
		UpdateCompletionStatus(siblingNodes[i]);

	ReIndentChildren(sel.parentNode);
	PaintBackground();
	SaveAsOPML();
}

function ShiftTabRow()
{
var sel = document.getElementById(gSelectedRow);
var prev_row = GetPreviousElementSibling(sel);
var next_row = GetNextElementSibling(sel);
var lparent = sel.parentNode;
var children_div;
var has_children = false;

	if (lparent.parentNode)
		var parent_row = lparent.previousSibling;

	if (sel.parentNode.id != 'outliner-root')								// this row is not at the root level
	{
		if (next_row && Element.hasClassName(next_row, 'children'))			// if selected row had children, dump them into children_li
		{
			has_children = true;
			children_div = sel.nextSibling;
		}
		var parent_div = sel.parentNode;

		sel.parentNode.parentNode.insertBefore(sel, parent_div.nextSibling);
		if (has_children)
			sel.parentNode.insertBefore(children_div, sel.nextSibling);
		
		if (!parent_div.hasChildNodes())				// remove the chidlren div incase it has been emptied
		{
			sel.parentNode.removeChild(parent_div);
			ChangeRowHandle(parent_row, 'leaf');
		}
	}

	var siblingNodes = sel.parentNode.childNodes;
	for (var i = 0; i < siblingNodes.length; i++)
		UpdateCompletionStatus(siblingNodes[i]);

	ReIndentChildren(sel.parentNode);
	PaintBackground();
	SaveAsOPML();
}

function MoveUp()
{
var sel = document.getElementById(gSelectedRow);
var prev_row = GetPreviousElementSibling(sel);
var next_row = GetNextElementSibling(sel);
var parent_div = sel.parentNode;
var lparent = sel.parentNode;
var has_children = false;

	if (lparent.parentNode)
		parent_row = lparent.previousSibling;

	if (next_row && Element.hasClassName(next_row, 'children'))			// if selected row had children, dump them into children_div
	{
		has_children = true;
	var children_div = sel.nextSibling;
	}

	if (!(!prev_row && sel.parentNode.id == 'outliner-root'))		// we can't move up if there is no previous row
	{
		if (prev_row)
		{
			if (Element.hasClassName(prev_row, 'children'))			// prev row already has children, so we append to that list
			{
				if (prev_row.style.display == 'block')				// prev row is expanded
				{
					prev_row.appendChild(sel);
					if (has_children)
						prev_row.appendChild(children_div);
				}
				else
				{
					sel.parentNode.insertBefore(sel, prev_row.previousSibling);
					if (has_children)
						sel.parentNode.insertBefore(children_div, sel.nextSibling);
				}
			}
			else						// prev row doesn't have children, so we put it above the previous row
			{
				sel.parentNode.insertBefore(sel, prev_row);
				if (has_children)
					sel.parentNode.insertBefore(children_div, sel.nextSibling);
			}
		}
		else			// no prev row. move 1 level up
		{
		var parent = sel.parentNode;
			parent.parentNode.insertBefore(sel, parent.previousSibling);
			if (has_children)
				parent.parentNode.insertBefore(children_div, sel.nextSibling);
		}
	}

	// remove the children div, incase it has been emptied
	if (!parent_div.hasChildNodes())
	{
		parent_div.parentNode.removeChild(parent_div);
		if (parent_row)
			ChangeRowHandle(parent_row, 'leaf');
	}

	var siblingNodes = sel.parentNode.childNodes;
	for (var i = 0; i < siblingNodes.length; i++)
		UpdateCompletionStatus(siblingNodes[i]);

	ReIndentChildren(sel.parentNode);
	PaintBackground();
	SaveAsOPML();
}

function MoveDown()
{
var sel = document.getElementById(gSelectedRow);
var next_row = GetNextElementSibling(sel);
var parent_div = sel.parentNode;
var lparent = sel.parentNode;
var has_children = false;

	if (lparent.parentNode)
		parent_row = lparent.previousSibling;

	if (next_row && Element.hasClassName(next_row, 'children'))		// if selected row had children, dump them into children_div
	{
		has_children = true;
		children_div = sel.nextSibling;
	}

	if (CanMoveDown(sel))
	{
		if (has_children)		// selected contains children, next row is the row after the children
			next_row = next_row.nextSibling;

		if (next_row)		// selected row is not the last row of its parent
		{
			if (next_row.nextSibling && Element.hasClassName(next_row.nextSibling, 'children'))		// next row already has children, so we append to that list
			{
				if (next_row.nextSibling.style.display == 'block')		// next row is expanded, append as child
				{
					next_row.nextSibling.insertBefore(sel, next_row.nextSibling.firstChild);

					if (has_children)
						next_row.nextSibling.insertBefore(children_div, sel.nextSibling);
				}
				else			// next row is collapsed, put it below that
				{
					sel.parentNode.insertBefore(sel, next_row.nextSibling.nextSibling);
					if (has_children)
						sel.parentNode.insertBefore(children_div, sel.nextSibling);
				}
			}
			else			// next row doesn't have children, so we put it after the next row
			{
				sel.parentNode.insertBefore(sel, next_row.nextSibling);
				if (has_children)
					sel.parentNode.insertBefore(children_div, sel.nextSibling);
			}
		}
		else			// no rows below selected row, move to 1 level up
		{
			var parent = sel.parentNode;
			parent.parentNode.insertBefore(sel, parent.nextSibling);

			if (has_children)
				sel.parentNode.insertBefore(children_div, sel.nextSibling);
		}

		// change the handle if required
		if (!parent_div.hasChildNodes())
		{
			parent_div.parentNode.removeChild(parent_div);
			if (parent_row)
				ChangeRowHandle(parent_row, 'leaf');
		}
	}

	var siblingNodes = sel.parentNode.childNodes;
	for (var i = 0; i < siblingNodes.length; i++)
		UpdateCompletionStatus(siblingNodes[i]);

	ReIndentChildren(sel.parentNode);
	PaintBackground();
	SaveAsOPML();
}

function CanMoveDown(row)
{
	var c_row = row;
	var root = document.getElementById('outliner-root');

	var has_children = false;
	if (row.nextSibling && Element.hasClassName(row.nextSibling, 'children'))
		has_children = true;

	if (!has_children && row.nextSibling)		// simplest case: no children and there is a row below
		return true;

	if (row.parentNode != root)
		return true;
		
	if (row.nextSibling.nextSibling)
		return true;

	return false;
}

function SelectRow(id)
{
	if (gHandleClicked == true)
	{
		gHandleClicked = false;
		return;
	}
	
	if (gSelectedRow)
		RemoveClass(document.getElementById('div'+gSelectedRow), 'selected');

	gSelectedRow = id;
	AddClass(document.getElementById('div'+gSelectedRow), 'selected');

	if (gIsEditable)
	{
		LoadText();
		SetActionButtonStates();
		FocusTextBox();
	}
}

function SelectNextRow()
{
	var sel;
	var next_row = sel.nextSibling;
	if (gSelectedRow)
	{
		sel = document.getElementById(gSelectedRow);
		if (sel.nextSibling)		// there is a row below this one
		{
			if (Element.hasClassName(next_row, 'children'))
			{
		//		if (sel.nextSibling.style.display == 'none')
		//			SelectRow(sel.nextSibling.nextSibling.id);
		//		else
		//		{
					var first = sel.nextSibling.firstChild;
					SelectRow(first.id);
		//		}
			}
			else SelectRow(next_row.id);
		}
 		else						// no row below this one, select parent's next row
 		{
 			var parent = sel.parentNode;
 			while(parent.id != 'outliner-root')
 			{
 				if (parent.nextSibling)
 				{
 					SelectRow(parent.nextSibling.id);
 					break;
 				}
 				else parent = parent.parentNode;
 			}
 		}
	}
}

function SelectPreviousRow()
{
	var sel;
	var prev_row = sel.previousSibling;
	if (gSelectedRow)
	{
		sel = document.getElementById(gSelectedRow);
		if (sel.previousSibling)		// there is a row above this one
		{
			if (Element.hasClassName(prev_row, 'children'))
			{
			//	if (sel.previousSibling.style.display == 'block')
			//	{
					var last = sel.previousSibling.lastChild;
					while (Element.hasClassName(last, 'children'))
						last = last.lastChild;

					SelectRow(last.id);
			//	}
			//	else SelectRow(sel.previousSibling.previousSibling.id);
			}
			else SelectRow(sel.previousSibling.id);
		}
		else						// no row above this one, select parent row
		{
			if (sel.parentNode.id != 'outliner-root')
 				SelectRow(sel.parentNode.previousSibling.id);
 		}
	}
}

function DeselectRow()
{
	if (gSelectedRow)
		RemoveClass(document.getElementById('div'+gSelectedRow), 'selected');

	gSelectedRow = '';

	if (gIsEditable)
	{
		UnloadText();
		DisableActionButtons();
	}
}

function ShowHolder(id)
{	
	if (id != 'div')												// href's within a span don't return correct ids
		AddClass(document.getElementById(id), 'mouse-hover');
}

function HideHolder(id)
{
	if (id != 'div')
		RemoveClass(document.getElementById(id), 'mouse-hover');
}

function AddClass(p_element, p_class)
{
	if (!p_element.className)
		p_element.className = p_class;
	else
	{
		l_classes = new Array();
		l_classes = p_element.className.split(' ');
		for (var i = 0; i < l_classes.length; i++)
			if (l_classes[i] == p_class)
				return;
		p_element.className += ' ' + p_class;
	}
}

function RemoveClass(p_element, p_class)
{
	if (p_element.className)
	{
		l_classes = new Array();
		l_classes = p_element.className.split(' ');
		for (var i = 0; i < l_classes.length; i++)
			if (l_classes[i] == p_class)
				l_classes.splice(i, 1);
		p_element.className = l_classes.join(' ');
	}
}

function GetPreviousElementSibling(n)
{
var x=n.previousSibling;
	while (x && x.nodeType != 1)	// 1 is id for element
		x=x.previousSibling;
	return x;
}

function GetNextElementSibling(n)
{
var x=n.nextSibling;
	while (x && x.nodeType != 1)	// 1 is id for element
		x=x.nextSibling;
	return x;
}

function CreateContainerForChildren(l_parent)
{
	next_row = l_parent.nextSibling;
	if (!next_row || !Element.hasClassName(next_row, 'children'))
	{
	var children_div = document.createElement('div');
  		children_div.style.display = 'block';
  		AddClass(children_div, 'children');

		l_parent.parentNode.insertBefore(children_div, l_parent.nextSibling);
	}
}

function AppendAsChild(parent, child)
{
var children;
	if (parent == -1)
		children = document.getElementById('outliner-root');
	else children = document.getElementById(parent).nextSibling;

	children.appendChild(child);
}

function IndentRow(row, depth)
{
var wrapper_div = document.getElementById('div'+row.id);

	wrapper_div.style.paddingLeft = (depth - 1) * 15 + 5+"px";
}

function ReIndentRow(row)
{
	if (row)
	{
		num_parents = GetNumParents(row.id);
		IndentRow(row, num_parents);
	}
}

// this function indents all the rows under the row passed
function ReIndentChildren(ul_row)
{
var n = ul_row.firstChild;
	while (n)
	{
		if (Element.hasClassName(n, 'children'))
			ReIndentChildren(n);
		else ReIndentRow(n);

		n = n.nextSibling;
	}
}

function GetNumParents(id)
{
var num_parents = 1;
	curr_row = document.getElementById(id);
	parent_ul = curr_row.parentNode;
	while (parent_ul.id != 'outliner-root')
	{
		parent_ul = parent_ul.parentNode;
		num_parents++;
	}
	return num_parents;
}

function ClearOutliner()
{
var element = document.getElementById("outliner-root");
var lOutline;

	while (element.firstChild)
		element.removeChild(element.firstChild);

	for (outline in gOutlines)
		delete outline;
		
	_row_id = 0;		// we need to reset this value when we are reloading the outliner
	gCounter = 1;
}

function PaintBackground()
{
var n = document.getElementById('outliner-root').firstChild;

	// check if children are exist. if not, don't call paintSiblings
	if (n)
		PaintSiblings(n, 0);
}

// recursive function that paints the rows of a UL
function PaintSiblings(firstNode, counter)
{
var parent;

	n = firstNode;
	try
	{
		while(n)
		{
			if (n.style.display != 'none')
			{
				if (Element.hasClassName(n, 'children'))
				{
					n = n.firstChild;
					counter = PaintSiblings(n, counter);
				}
				else
				{
					if (counter % 2)
					{
						RemoveClass(n,'oddrow');
						AddClass(n,'evenrow');
					}
					else
					{
						RemoveClass(n,'evenrow');
						AddClass(n,'oddrow');
					}
					counter++;
				}
			}
			parent = n.parentNode;
			n = n.nextSibling;
		}
	}
	catch(err)
	{
	}

	n = parent;

	return counter;
}

// paramenter 'save' is passed optionally. used when we load the page and collapse some rows, we don't want to save
// save value: true/false
function ShowChildren(row_id, save)
{	
	gHandleClicked = true;
	
	if (typeof save === "undefined")
		save = true;

	row = document.getElementById(row_id);
	next_row = row.nextSibling;
	if (next_row && Element.hasClassName(next_row, 'children'))
	{
		next_row.style.display = 'block';
		ChangeRowHandle(row, 'expanded');
	}

	PaintBackground();

	if (gIsEditable && save)
		SaveAsOPML();
}

// paramenter 'save' is passed optionally. used when we load the page and collapse some rows, we don't want to save
// save value: true/false
function HideChildren(row_id, save)
{
	gHandleClicked = true;
	
	if (typeof save === "undefined")
		save = true;

	row = document.getElementById(row_id);
	next_row = row.nextSibling;
	if (next_row && Element.hasClassName(next_row, 'children'))
	{
		next_row.style.display = 'none';
		ChangeRowHandle(row, 'collapsed');
	}

	PaintBackground();

	if (gIsEditable && save)
		SaveAsOPML();
}

function ShowAll()
{
var children = new Array();
	can_show = false;
	if (gSelectedRow)
	{
		var nxt = document.getElementById(gSelectedRow).nextSibling;
		if (nxt && Element.hasClassName(nxt, 'children'))
		{
			can_show = true;
			n = nxt.firstChild;
			while (n)
			{
				if (n.nodeType == 1)
					children[children.length] = n;
				n = n.nextSibling;
			}
		}
	}
	else								// now row has been selected. expand /
	{
		can_show = true;
		root_ul = document.getElementById('outliner-root');
		n = root_ul.firstChild;
		while (n)
		{
			if (n.nodeType == 1)
				children[children.length] = n;
			n = n.nextSibling;
		}
	}

	if (can_show)
	{
		ShowAllRec(children);
		PaintBackground();
		if (gIsEditable)
			SaveAsOPML();
	}

	if (gSelectedRow)		// special case: expand the selected row (if it is collapsed)
		ShowChildren(gSelectedRow, true);
}

// recursively show all children. called by ShowAll()
function ShowAllRec(children)
{
	for (var i = 0; i < children.length; i++)
	{
		if (!Element.hasClassName(children[i], 'children'))
		{
			next_row = children[i].nextSibling;
			if (next_row && Element.hasClassName(next_row, 'children'))
			{
				ShowChildren(children[i].id, false);				// show this row. don't save to file. we will save at the end

				mychildren = new Array();
				n = children[i].nextSibling.firstChild;
				while (n)
				{
					if (n.nodeType == 1)
						mychildren[mychildren.length] = n;
					n = n.nextSibling;
				}
				ShowAllRec(mychildren);
			}
		}
	}
}

function HideAll()
{
var children = new Array();
	can_hide = false;
	if (gSelectedRow)
	{
		var nxt = document.getElementById(gSelectedRow).nextSibling;
		if (nxt && Element.hasClassName(nxt, 'children'))
		{
			can_hide = true;
			n = nxt.firstChild;
			while (n)
			{
				if (n.nodeType == 1)
					children[children.length] = n;
				n = n.nextSibling;
			}
		}
	}
	else								// now row has been selected. expand /
	{
		can_hide = true;
		root_ul = document.getElementById('outliner-root');
		n = root_ul.firstChild;
		while (n)
		{
			if (n.nodeType == 1)
				children[children.length] = n;
			n = n.nextSibling;
		}
	}

	if (can_hide)
	{
		HideAllRec(children);
		PaintBackground();
		if (gIsEditable)
			SaveAsOPML();
	}
}

// recursively hide all children. called by HideAll()
function HideAllRec(children)
{
	for (var i = 0; i < children.length; i++)
	{
		if (!Element.hasClassName(children[i], 'children'))
		{
			next_row = children[i].nextSibling;
			if (next_row && Element.hasClassName(next_row, 'children'))
			{
				HideChildren(children[i].id, false);				// hide this row. don't save to file. we will save at the end

				mychildren = new Array();
				n = children[i].nextSibling.firstChild;
				while (n)
				{
					if (n.nodeType == 1)
						mychildren[mychildren.length] = n;
					n = n.nextSibling;
				}
				HideAllRec(mychildren);
			}
		}
	}
}

function ChangeRowHandle(row, state)
{
var handle = document.getElementById('handle'+row.id);
var path_to_handles = navigator.userAgent.match(/iPhone/i) ? "/images/iphone/" : "/images/";

	switch(state)
	{
	default:
	case 'leaf':		img_src = 'leafrowhandle.gif';
						break;

	case 'expanded':	img_src = 'expanded.gif';
						handle.onclick = function(evt) { HideChildren(getTargetElement(evt).id.replace(/handle(.*)/g, '$1')); };
						break;

	case 'collapsed':	img_src = 'collapsed.gif';
						handle.onclick = function(evt) { ShowChildren(getTargetElement(evt).id.replace(/handle(.*)/g, '$1')); };
						break;
	}
	// set image to be displayed
	document.getElementById('handle'+row.id).src = path_to_handles + img_src;
}

function SaveText()
{
var row_txt = document.getElementById('r'+gSelectedRow);
var txt_area = document.getElementById('edit_textarea');
var form_chk = document.getElementById('edit_status');
var completed = (form_chk.checked == true) ? true : false;

var create_multiple = document.getElementById('create_mulitple');

	if (document.getElementById('create_mulitple') && create_multiple.checked == true)			// Multiple Rows selected
	{
		new_rows = new Array;
		new_rows = txt_area.value.split('\n');
		
		for (i = 0; i < new_rows.length; i++)
		{
			if (new_rows[i] == "")
				new_rows.splice(i, 1);
		}

		if (new_rows.length)
		{
		var text = NormaliseText(new_rows[0], 'opml');
			row_txt.innerHTML = NormaliseText(text, 'html');
			
			SetRowColor(gSelectedRow, gColor);
			
			// add attributes to Outline object
		var sel_outline = GetOutlineById(gSelectedRow);
		
			sel_outline.setAttribute('text', text);
			sel_outline.setAttribute('_color', gColor);
			
			// if completed is checked, mark all rows as completed
			if (completed)
			{
				sel_outline.setAttribute('_status', 'checked');
				SetRowStatus(gSelectedRow, 'checked');
			}
			else
			{
				sel_outline.setAttribute('_status', '');
				SetRowStatus(gSelectedRow, '');
			}
	
			lparent = document.getElementById('outliner-root');
			for (i = 1; i < new_rows.length; i++)
			{
				if (new_rows[i] == "")				// check that row contains some text
					continue;
				
			var row = CreateRow(new_rows[i]);
			var lOutline = new Outline();
				lOutline.setId(row.id);
				lOutline.setAttribute('text', new_rows[i]);
				lOutline.setAttribute('_color', gColor);
								
			var lparent;
				sel = document.getElementById(gSelectedRow);
				lparent = sel.parentNode;
			
				gOutlines[gOutlines.length] = lOutline;
			
				lparent.insertBefore(row, sel.nextSibling);		// else add below it
				
				SetRowColor(row.id, gColor);
				
				// if completed is checked, mark all rows as completed
				if (completed)
				{
					sel_outline.setAttribute('_status', 'checked');
					SetRowStatus(row.id, 'checked');
				}
				else
				{
					sel_outline.setAttribute('_status', '');
					SetRowStatus(row.id, '');
				}

			
				ChangeRowHandle(row, 'leaf');											// set handle image for the new row	
				SelectRow(row.id);
			}
			
			ReIndentChildren(lparent);
		}
	}
	else								// Multiple Rows not selected
	{
	var text = NormaliseText(txt_area.value, 'opml');
		row_txt.innerHTML = NormaliseText(text, 'html');
		
		SetRowColor(gSelectedRow, gColor);
		
		// add attributes to Outline object
		try
		{
		var sel_outline = GetOutlineById(gSelectedRow);
	
			sel_outline.setAttribute('text', text);
			sel_outline.setAttribute('_color', gColor);
		}
		catch(err)
		{
	
		}

	}

	SaveAsOPML();
	
	if (gUserAgent == 'iphone')
	{
		HideEditBox();
	}
}

function LoadText()
{
var sel_row = document.getElementById(gSelectedRow);
var sel_outline = GetOutlineById(gSelectedRow);
var text = sel_outline.getAttribute('text');

	txt_area = document.getElementById('edit_textarea');
	txt_area.value = NormaliseText(text, 'edit');
	txt_area.readOnly = false;

var chk_box = document.getElementById('check'+gSelectedRow);
var form_chk = document.getElementById('edit_status');

var sel_outline = GetOutlineById(gSelectedRow);

	try
	{
		SetTextBoxColor(sel_outline.getAttribute('_color'));
	}
	catch(err)
	{
		SetTextBoxColor('');
	}
	
	// multiple rows
	if (document.getElementById('create_mulitple'))
	{
	var create_multiple = document.getElementById('create_mulitple');
		create_multiple.checked = false;
		create_multiple.disabled = false;
	}
	
	// check box
	try
	{
		form_chk.disabled = false;
		if (sel_outline.getAttribute('_status') == 'checked')
			form_chk.checked = true;
		else form_chk.checked = false;

		// if row is a parent, disable the check box
		if (isParent(sel_row))
			form_chk.disabled = true;
	}
	catch(err)
	{
		form_chk.checked = false;
	}

	// disable keyboard shortcuts since we are typing in the box
//	EnableKeyBoardShortCuts('disable');
}

function UnloadText()
{
	txt_area = document.getElementById('edit_textarea');
	txt_area.readOnly = true;
	txt_area.value = "Please select a row to edit its content, or click on 'Add Row' to add a new row...";
	SetTextBoxColor('#999');
	
	if (document.getElementById('create_mulitple'))
	{
		create_multiple = document.getElementById('create_mulitple');
		create_multiple.checked = false;
		create_multiple.disabled = true;
	}
	
	chkbox = document.getElementById('edit_status');
	chkbox.checked = false;
	chkbox.disabled = true;

	// enable keyboard shortcuts since we have finished with the exit box
//	EnableKeyBoardShortCuts('enable');
}

function GetColorFromIndex(idx)
{
var color = '';
	
	switch(idx)
	{
	case 1:		color = '';
				break;
	case 2:		color = '#009900';
				break;
	case 3:		color = '#0060BF';
				break;
	case 4:		color = '#EA5200';
				break;
	default: 	color = '';
	}
	return color;
}

function SetColor(idx)
{
var path_to_swatches = navigator.userAgent.match(/iPhone/i) ? "/images/iphone/" : "/images/";

	if (document.getElementById('color-palette'))
		document.getElementById('color-palette').src = path_to_swatches+"outline_colors"+idx+".gif";
	gSelectedColor = gColor = GetColorFromIndex(idx);

	if (gSelectedRow)
		SetTextBoxColor(gColor);						// now change the color of the textbox
	Set_Cookie( 'color', idx, 30, '/', '', '' );		// remember color in cookie
}

function RemoveAllColors()
{
	var agreed = window.confirm("This will permanently remove any colours you have applied to your outline. Do you want to continue?");

	if (agreed)
	{
		for (var i = 0; i < gOutlines.length; i++)
			gOutlines[i].setAttribute('_color', '');

		SaveAsOPML();
		GetOPML();					// we get data from the file so that even the display doesnt show any colors
	}
}

function SetTextBoxColor(color)
{
	txt_area = document.getElementById('edit_textarea');
	gColor = txt_area.style.color = color;
}

function SetRowColor(row_id, color)
{
	var row_txt = document.getElementById('r'+row_id);
	row_txt.style.color = color;
}

function ToggleRowStatus()
{
var form_chk = document.getElementById('edit_status');

	if (form_chk.checked == true)
	{
		var sel_outline = GetOutlineById(gSelectedRow);
		sel_outline.setAttribute('_status', 'checked');

		SetRowStatus(gSelectedRow, 'checked');
	}
	else
	{
		var sel_outline = GetOutlineById(gSelectedRow);
		sel_outline.setAttribute('_status', '');

		SetRowStatus(gSelectedRow, '');
	}

	var sel_row = document.getElementById(gSelectedRow);
	UpdateCompletionStatus(sel_row);
	SaveAsOPML();
}

function SetRowStatus(row_id, status)
{
var row = document.getElementById(row_id);
var row_text = document.getElementById('r'+row_id);

	if (status == 'checked')
	{
		AddClass(row_text, 'strike');
	}
	else
	{
		RemoveClass(row_text, 'strike');
	}
	if (gShowCheckbox) SetCheckboxStatus(row_id, status);
}

function isParent(row)
{
var next_row = row.nextSibling;
	if (next_row && Element.hasClassName(next_row, 'children'))
		return true;
	else return false;
}

function UpdateCompletionStatus(row)
{	
var root_ul = document.getElementById('outliner-root');
var ancestors = new Array();
	ancestors[0] = row;			// insert row into ancestors array
	
	try
	{
	var parent = row.parentNode;				// build list of ancestors for this row.
	while(parent.id != 'outliner-root')			// the 1st element of the array is the imediate parent, and the last, the furthest fore-father
	{
		ancestors[ancestors.length] = parent.previousSibling;
		parent = parent.parentNode;
	}

	// update the status of all parents
	for (var i = 0; i < ancestors.length; i++)
		EvaluateChildrenStatus(ancestors[i]);
	}
	catch(err)
	{
	}
}

function EvaluateChildrenStatus(row)
{
	// row doesn't contain children, just return its status
	if (!isParent(row))
	{
		if (!row.id)
			return false;

		var this_outline = GetOutlineById(row.id);
		if (this_outline.getAttribute('_status') == 'checked')
			return true;
		else return false;
	}

	// build array containing children of row
	var children = new Array();
	n = row.nextSibling.firstChild;
	while (n)
	{
		if (n.nodeType == 1)
			children[children.length] = n;
		n = n.nextSibling;
	}

	// iterate thru the children and count the number of completed rows
	var num_children = children.length;
	var completed_children = 0;
	for (var i = 0; i < children.length; i++)
	{
		if (!Element.hasClassName(children[i], 'children'))		// this is an actual child
		{
			var this_outline = GetOutlineById(children[i].id);
			if (this_outline.getAttribute('_status') == 'checked')
				completed_children++;
		}
		else num_children--;					// this div contains the children of the prev div. it isn't an actual child
	}

	// if all (actual) children are completed, mark row as completed
	var sel_outline = GetOutlineById(row.id);
	if (completed_children == num_children)		// all children are completed, mark row as completed
	{
		sel_outline.setAttribute('_status', 'checked');
		SetRowStatus(row.id, 'checked');
		return true;
	}
	else										// not all children are completed, mark row as incomplete
	{
		sel_outline.setAttribute('_status', '');
		SetRowStatus(row.id, '');
		return false;
	}
}

function getTargetElement(evt)
{
var elem;

	if (window.event)
	{
		elem = window.event.srcElement;
	}
	else
	{
		elem = (evt.target.nodeType == 3) ? evt.target.parentNode : evt.target;	// if textnode return parent, else return self
	}
	return elem;
}

if (window.addEventListener)
	window.addEventListener('load', OutlinerInit, false);
else window.attachEvent('onload', OutlinerInit);