/**
 * @filename
 *     public.js
 *
 * @author
 *    Julian Turner, Ripley, Derbyshire, England
 *    http://www.baconbutty.com
 *
 * @copyright 
 *    (c) Julian Turner 2007
 *
 * @version
 *    1 (developed 2007)
 *
 * @fileoverview
 *    public.js contains a number of functions used by
 *    all of the web pages on http://www.baconbutty.com,
 *    where additional JavaScript functionality is offered,
 *    such as the CodePlay, HTMLPlay and PagePlay features.
 *
 * @dependencies
 *    public.js is not dependent on any other js file.
 *    
 * @licence
 *    Your only permission is to download and run
 *    this code in your browser as part of the HTML 
 *    page you are viewing at http://www.baconbutty.com.
 *    All other rights are reserved.
 */var DOMAIN = "http://www.baconbutty.com/";function CodePlay_Edit(
	elementId /*: String*/
) /*: void*/
{
	var element /*: HTMLElement*/ = document.getElementById(elementId);

	if (!element)
	{
		return;
	}

	if (element.getAttribute("activated") == "true")
	{
		return;
	}
	else
	{
		element.setAttribute("activated", "true");
	}

	var code /*: String*/ = HTMLElement_InnerText(element);

	var height /*: int*/ = element.offsetHeight - 2;
	height = 200;
	
	var div1 /*: HTMLDivElement*/ = document.createElement("div");
	div1.className = "edit-div-1";

	var div2 /*: HTMLDivElement*/ = document.createElement("div");
	div2.className = "edit-div-2";

	var div3 /*: HTMLDivElement*/ = document.createElement("div");
	div3.className = "edit-div-3";

	var textarea /*: HTMLTextAreaElement*/ = document.createElement("textarea");
	textarea.className = "edit-area";
	textarea.id = element.id;
	textarea.value = code;
	textarea.style.height = height + "px";

	HTMLElement_AttachEvent(textarea, "onkeydown", HTMLTextAreaElement_InsertTab);

	div1.appendChild(div2);
	div2.appendChild(div3);
	div3.appendChild(textarea);

	element.parentNode.insertBefore(div1, element);

	element.parentNode.removeChild(element);
}function CodePlay_Play(
	elementId /*: String*/
) /*: void*/
{
	var element /*: HTMLElement*/ = document.getElementById(elementId);

	if (!element)
	{
		return;
	}


	var code /*: String*/ = HTMLElement_InnerText(element);
	code = CodePlay_ConvertHeredoc(code);

	var data /*: Object*/ = CodePlay_GetDataRegions(code);
	
	eval(code);
}function CodePlay_GetDataRegions(
	code /*: String*/
) /*: Object*/
{
	var data /*: Object*/ = {};
	var dataRegionStartPattern /*: RegExp*/ = /\/\*(\w+)/gi;

	var dataRegionName /*: String*/ = "";
	var dataRegionEndMarker /*: String*/ = "";

	var dataRegionStart /*: int*/ = 0;
	var dataRegionInnerStart /*: int*/ = 0;
	var dataRegionContents /*: String*/ = "";
	var dataRegionInnerEnd /*: int*/ = 0;
	var dataRegionEnd /*: int*/ = 0;

	var execResult /*: Array*/ = [];
	var overflow /*: int*/ = 100;
	
	while(overflow--)
	{
		dataRegionStartPattern.lastIndex = dataRegionEnd;

		execResult = dataRegionStartPattern.exec(code);

		if (!execResult)
		{
			break;
		}

		dataRegionName = execResult[1];
		dataRegionEndMarker = dataRegionName + "*/";
		dataRegionStart = execResult.index;
		dataRegionInnerStart = dataRegionStartPattern.lastIndex;

		dataRegionInnerEnd = code.indexOf(dataRegionEndMarker, dataRegionInnerStart);

		if (dataRegionInnerEnd == -1)
		{
			dataRegionEnd = dataRegionInnerStart;
			continue;
		}

		dataRegionEnd = dataRegionInnerEnd + dataRegionEndMarker.length;

		dataRegionContents = code.substring(dataRegionInnerStart, dataRegionInnerEnd);
		dataRegionContents = dataRegionContents.replace(/^\s\s*/g,"").replace(/\s*\s$/g,"");

		data[dataRegionName] = dataRegionContents;
	}

	return data;
}function CodePlay_ConvertHeredoc(
	code /*: String*/
) /*: String*/
{
	var convertedCode /*: Array*/ = [];

	var heredocStartPattern /*: RegExp*/ = /<<<(\w+)/gi;
	var heredocEndPattern /*: RegExp*/ = null;

	var heredocIdentifier /*: String*/ = "";

	var heredocStart /*: int*/ = 0;	
	var heredocInnerStart /*: int*/ = 0;
	var heredocContents /*: String*/ = "";
	var heredocInnerEnd /*: int*/ = 0;
	var heredocEnd /*: int*/ = 0;	

	var execResult /*: Array*/ = [];
	var overflow /*: int*/ = 100;
	
	while(overflow--)
	{
		heredocStartPattern.lastIndex = heredocEnd;

		execResult = heredocStartPattern.exec(code);

		if (!execResult)
		{
			convertedCode[convertedCode.length] = code.substring(heredocEnd, code.length);	
			break;
		}

		heredocIdentifier = execResult[1];
		heredocStart = execResult.index;
		heredocInnerStart = heredocStartPattern.lastIndex;

		convertedCode[convertedCode.length] = code.substring(heredocEnd, heredocStart);	
	
		heredocEndPattern = new RegExp("(\\r|\\n)" + heredocIdentifier + ";", "g");
		heredocEndPattern.lastIndex = heredocInnerStart;

		execResult = heredocEndPattern.exec(code);

		if (!execResult)
		{
			alert("Could not find end of identifier " + heredocIdentifier);
			return "";
			break;
		}

		heredocInnerEnd = execResult.index;
		heredocEnd = heredocEndPattern.lastIndex;

		heredocContents = code.substring(heredocInnerStart, heredocInnerEnd);
		heredocContents = heredocContents.replace(/^\s\s*/g,"").replace(/\s*\s$/g,"");
		heredocContents = String_ToStringLiteral(heredocContents);
		
		convertedCode[convertedCode.length] = "\"" + heredocContents + "\";\r\n";
	}

	return convertedCode.join("");
}function HTMLPlay_Edit(
	elementId /*: String*/
)
{
	var element /*: HTMLElement*/ = document.getElementById(elementId);

	if (!element)
	{
		return;
	}

	if (element.getAttribute("activated") == "true")
	{
		return;
	}
	else
	{
		element.setAttribute("activated", "true");
	}

	var html /*: String*/ = HTMLElement_InnerText(element);

	var height /*: String*/ = element.offsetHeight - 2;
	height = 200;
	
	var div1 /*: HTMLDivElement*/ = document.createElement("div");
	div1.className = "edit-div-1";

	var div2 /*: HTMLDivElement*/ = document.createElement("div");
	div2.className = "edit-div-2";

	var div3 /*: HTMLDivElement*/ = document.createElement("div");
	div3.className = "edit-div-3";

	var textarea /*: HTMLTextAreaElement*/ = document.createElement("textarea");
	textarea.className = "edit-area";
	textarea.id = element.id;
	textarea.value = html;
	textarea.style.height = height + "px";

	HTMLElement_AttachEvent(textarea, "onkeydown", HTMLTextAreaElement_InsertTab);


	div1.appendChild(div2);
	div2.appendChild(div3);
	div3.appendChild(textarea);

	element.parentNode.insertBefore(div1, element);

	element.parentNode.removeChild(element);
}function HTMLPlay_Play(
	elementId /*: String*/
)
{
	var element /*: HTMLElement*/ = document.getElementById(elementId);

	if (!element)
	{
		return;
	}


	var html /*: String*/ = HTMLElement_InnerText(element);

	var display /*: HTMLElement*/ = document.getElementById(elementId + "DISPLAY");

	if (!display)
	{
		return;
	}

	display.style.display = "block";

	display.innerHTML = html;
}function PagePlay_Edit(
	elementId /*: String*/
)
{
	var element /*: HTMLElement*/ = document.getElementById(elementId);

	if (!element)
	{
		return;
	}

	if (element.getAttribute("activated") == "true")
	{
		return;
	}
	else
	{
		element.setAttribute("activated", "true");
	}

	var code /*: String*/ = HTMLElement_InnerText(element);

	var height /*: String*/ = element.offsetHeight - 2;
	height = 200;
	
	var div1 /*: HTMLDivElement*/ = document.createElement("div");
	div1.className = "edit-div-1";

	var div2 /*: HTMLDivElement*/ = document.createElement("div");
	div2.className = "edit-div-2";

	var div3 /*: HTMLDivElement*/ = document.createElement("div");
	div3.className = "edit-div-3";

	var textarea /*: HTMLTextAreaElement*/ = document.createElement("textarea");
	textarea.className = "edit-area";
	textarea.id = element.id;
	textarea.value = code;
	textarea.style.height = height + "px";

	HTMLElement_AttachEvent(textarea, "onkeydown", HTMLTextAreaElement_InsertTab);


	div1.appendChild(div2);
	div2.appendChild(div3);
	div3.appendChild(textarea);

	element.parentNode.insertBefore(div1, element);

	element.parentNode.removeChild(element);
}function PagePlay_Play_NewWindow(
	elementId /*: String*/
)
{
	var element /*: HTMLElement*/ = document.getElementById(elementId);

	if (!element)
	{
		return;
	}

	var code /*: String*/ = HTMLElement_InnerText(element);

	code = CodePlay_ConvertHeredoc(code);

	var screenWidth /*: int*/ = screen.availWidth;
	var screenHeight /*: int*/ = screen.availHeight;

	if (screenWidth)
	{
		var border /*: int*/ = 200;
		var height /*: int*/ = screenHeight - (border * 2);
		var width /*: int*/ = screenWidth - (border * 2);
		var left /*: int*/ = border;
		var top /*: int*/ = border;
	}
	else
	{
		var height /*: int*/ = 300;
		var width /*: int*/ = 500;
		var left /*: int*/ = 0;
		var top /*: int*/ = 0;
	}		

	var win /*: Window*/ = window.open("", "", "status=yes,height=" + height + ",width=" + width + ",left=" + left + ",top=" + top + ",resizable=yes,scrollbars=yes");

	if (win.document)
	{
		var doc /* HTMLDocument*/ = win.document;
		doc.open();
		doc.write(code);
		doc.close();
	}
	else
	{	
		var count /*: int*/ = 10;

		var interval /*: HostObject*/ = window.setInterval(function()
		{
			if (!count--)
			{
				window.clearInterval(interval); 
				return;
			}
	
			if (!win.document)
			{
				return;
			}

			var doc /* HTMLDocument*/ = win.document;
			doc.open();
			doc.write(code);
			doc.close();

			window.clearInterval(interval);
		},200);
	}
}function PagePlay_Play_IFrame(
	elementId /*: String*/
)
{
	var element /*: HTMLElement*/ = document.getElementById(elementId);

	if (!element)
	{
		return;
	}


	var html /*: String*/ = HTMLElement_InnerText(element);

	html = CodePlay_ConvertHeredoc(html);

	var div /*: HTMLDivElement*/ = document.getElementById(elementId + "DISPLAY");
	div.style.display = "block";

	var iframe /*: HTMLIFrameElement*/ = document.getElementById(elementId + "IFRAME");

	if (!iframe)
	{
		return;
	}

	var win /*: Window*/ = iframe.contentWindow || document.frames[elementId + "IFRAME"];
	var doc /*: HTMLDocument*/ = win.document;

	doc.open();
	doc.write(html);
	doc.close();
}function HTMLElement_InnerText(
	element /*: HTMLElement*/
) /*: String*/
{
	if (!element)
	{
		return "";
	}

	if (element.nodeName.toLowerCase() == "textarea" || element.nodeName.toLowerCase() == "input")
	{
		return element.value;
	}

	var innerText /*: String*/ = "";
	var childNodes /*: NodeList*/ = element.childNodes;
	var node /*: Node*/ = null;

	for (var i /*: int*/ = 0; i < childNodes.length; i++)
	{
		node = childNodes[i];

		if (node.nodeType == 1)
		{
			if (node.nodeName.toLowerCase() == "textarea" || node.nodeName.toLowerCase() == "input")
			{
				innerText += node.value;
			}
			else
			{
				innerText += HTMLElement_InnerText(node);
			}
		}

		if (node.nodeType == 3)
		{
			innerText += node.nodeValue;
		}

		if (node.nodeType == 4)
		{
			innerText += node.nodeValue;
		}
	}

	return innerText;
}function HTMLElement_AttachEvent(
	element /*: HTMLElement*/, 
	eventType /*: String*/, 
	handler /*: Function*/, 
	capturePhase /*: Boolean*/
) /*: void*/
{
	if (typeof handler != "function")
	{
		return;
	}

	capturePhase = capturePhase || false;

	if (typeof element.addEventListener !== "undefined")
	{
		eventType = eventType.replace(/^on/, "");
		element.addEventListener(eventType, handler, capturePhase);
	}
	else if (typeof element.attachEvent !== "undefined")
	{
		if (!/^on/.test(eventType))
		{
			eventType = "on" + eventType;
		}

		element.attachEvent(eventType, handler);
	}
}function HTMLTextAreaElement_InsertTab(
	event /*: Event*/
) /*: void*/
{
	event = event || window.event;

	var textarea /*: HTMLTextAreaElement*/ = event.srcElement || event.target;

	if (event.keyCode == 9)
	{
		if (typeof textarea.selectionStart !== "undefined")
		{
			event.stopPropagation();
			event.preventDefault();

			/* Collapse Insertion Point */
			//textarea.setSelectionRange(textarea.selectionEnd, textarea.selectionEnd);
			//textarea.focus();

			/* Insert Tab */
			var selStart /*: int*/ = textarea.selectionStart;
			var selEnd /*: int*/ = textarea.selectionEnd;
			var currentScroll /*: int*/ = textarea.scrollTop;
			var contents /*: String*/ = textarea.value;
	
			textarea.value = contents.substring(0, selStart) + "\t" + contents.substring(selEnd, contents.length);

			textarea.scrollTop = currentScroll;
			textarea.setSelectionRange(selEnd + 1, selEnd + 1);

			textarea.focus();
	
			//window.setTimeout(function(){
			//	textarea.focus();
			//}, 0);

			return false;
		}
		else if (document.selection)
		{
			var range /*: HostObject(TextRange)*/ = document.selection.createRange();
			range.collapse();
			range.text = String.fromCharCode(9);
			range.collapse();
			range.select();

			event.returnValue = false;
		}
	}

}function String_ToStringLiteral(
	s /*: String*/
) /*: String*/
{	
	var escapedCharacters /*: RegExp*/ = /(\f|\n|\r|\t|'|"|\\|[\x00-\x1F]|[\x7F-\x9F])/gi;

	var overflow /*: int*/ = 10000;
	var execResult /*: Array*/;
	var stringLiteralBuffer /*: Array.<String>*/ = [];
	var previousIndex /*: int*/ = 0;
	var escaped /*: String*/ = "";
	var charCode /*: int*/;

	escapedCharacters.lastIndex = 0;

	while(overflow-- )
	{
		execResult /*: Array*/ = escapedCharacters.exec(s);

		if (!execResult)
		{
			break;
		}

		stringLiteralBuffer[stringLiteralBuffer.length] = s.substring(previousIndex, escapedCharacters.lastIndex - 1);

		escaped = "";

		switch(execResult[0])
		{
			case "\f":  /*FORM FEED(12)*/
				escaped = "\\f";
				break;

			case "\n": /*LINE FEED(10)*/
				escaped = "\\n";
				break;

			case "\r": /*CR(13)*/
				escaped = "\\r";
				break;

			case "\t":
				escaped = "\\t";
				break;

			case "\'":
				escaped = "\\\'";
				break;

			case "\"":
				escaped = "\\\"";
				break;

			case "\\":
				escaped = "\\\\";
				break;

			default:
				charCode = execResult[0].charCodeAt(0);

				if (charCode < 256)
				{
					escaped = "\\x" + LZ(charCode.toString(16), 2);
				}
				else
				{					
					escaped = "\\u" + LZ(charCode.toString(16), 4);
				}
				break;
		}

		stringLiteralBuffer[stringLiteralBuffer.length] = escaped;

		previousIndex = escapedCharacters.lastIndex;
	}

	stringLiteralBuffer[stringLiteralBuffer.length] = s.substring(previousIndex, s.length);

	return stringLiteralBuffer.join("");

	function LZ(
		s /*: String*/, 
		overflow /*: int*/
	) /*: String*/
	{
		var zeros /*: String*/ = "00000000000000000000";
	
		if (s.length < overflow)
		{
			return zeros.substr(0, overflow - s.length) + s;
		}
		else
		{
			return s;
		}
	}
}
