﻿function TEditor()
{
	//private
	    var self = this;
		var designTool = 0;
		var htmlHelper = null;
		var rootDocument = null;
		var rootContainer = null; //window or frame, needed for key event readout
		var designMode = true;
		var guideLinesEnabled = false; //should editor set guidelines to new inserted objects
		var htmlCode = ''; //holds html code since last OnHTMLCodeChanged was called
		var initializeRunning = true;

		function getUniqueDOMID(baseName)
		{
			var baseCounter = 1;

			while (rootDocument.getElementById(baseName+'_'+baseCounter) || rootDocument.getElementsByName(baseName+'_'+baseCounter)[0])
			{
				baseCounter++;			
			}

			return baseName+'_'+baseCounter;
		}

		function getEditorElementFromSelection(rootDocument)
		{
			var object = null;
			var result = null;
			var type = "";
			var range = null;

			if (rootDocument.selection)
			{
				type = rootDocument.selection.type;

				if (type == "Text" || type == "None") //None is returned when changing cursor with keyboard
				{
					object = rootDocument.selection.createRange();
					range = object;
				}
				else
				if (type == "Control") //handle control range object
				{
					object = rootDocument.selection.createRange();
					range = object;

					var controls = object;
					if (controls.length > 0)
					{
						object = controls.item(0);
					}
				}
			}
			else
			{
				//mozilla
				selection = rootContainer.getSelection();
				if (selection.rangeCount > 0)
				{
					object = selection.getRangeAt(0);
					range = object;
					type = "Text";

					var fragment = object.cloneContents();

					if (fragment.firstChild && fragment.lastChild)
					{
						if ((fragment.firstChild === fragment.lastChild) && fragment.firstChild.tagName)
						{
							object = fragment.firstChild;
							type = "Control";
						}
					}
				}
			}

			if (object)
			{	
				result = new TEditorElement();
				result.initialize(rootDocument,object,type,self,range);
			}

			return result;	
		}

	//public
		this.selectedObject = new TEditorElement; //TEditorElement;
		this.blockEvents = false;
		this.htmlCodeEditable = false;

		//event functions
		this.registerEvent = function(object,eventName,eventHandler)
		{
			if (object)
			{
				//object.preventDefault;
				//alert(object.attachEvent);
				if (object.attachEvent) 
				{ return object.attachEvent('on'+eventName,eventHandler); } else
				{ return object.addEventListener(eventName,eventHandler,false); }
			}
			else
			{
				return false;
			}
		}
		
		this.unregisterEvent = function(object,eventName,eventHandler)
		{
			if (object)
			{
				if (object.detachEvent) 
				{ return object.detachEvent('on'+eventName,eventHandler); } else
				{ return object.removeEventListener(eventName,eventHandler,false); }
			}
		}

		//checks wether selected object is control or not
		this.selectedControl = function()
		{
			var result = null;

			if (this.selectedObject.isValid())
			{
				if (this.selectedObject.isControl())
				{
					result = this.selectedObject.getObject();	
				}
			}

			return result;
		}

		//updates selectedObject property
		this.refreshSelection = function()
		{
			this.handleElementSelectNotification(rootDocument);
		}

		//handles the selection of an object and stores a reference of the object to private variable and raises event
		this.handleElementSelectNotification = function(rootDocument)
		{
			var typeChanged = true;
			var idChanged = true;
			var obj = getEditorElementFromSelection(rootDocument);

			if (obj)
			{
				if (obj && this.selectedObject.isValid())
				{
					//handle selection changed between different selection types like Control and Text
					typeChanged = (obj.getType() != this.selectedObject.getType()) || (obj.getType() == "Control" && obj.getID() != this.selectedObject.getID());
					idChanged = (obj.getID() != this.selectedObject.getID());
				}
			
				this.selectedObject.assign(obj);

				if ( !this.blockEvents && (
						(obj.getType() != "Control") || 
						(obj.getType() == "Control" && (idChanged || typeChanged)) //we need this comparision to ensure the user can resize controls
					)
				) { this.OnElementSelected(this.selectedObject,typeChanged); }
			}
		}

		//enables or disables usage of guidelines
		this.enableGuideLines = function(value)
		{
			if (guideLinesEnabled != value)
			{
				guideLinesEnabled = value;
				this.setGuideLines(null,value);
			}
		}

		//returns if guidlines are enabled for DOM element or if undefined passed of editor
		this.getGuideLines = function(elementDOM)
		{
			if (elementDOM)
			{
				return elementDOM.style.borderStyle == 'dashed';
			}
			else
			{
				return guideLinesEnabled;
			}	
		}

		//shows or hides guidelines of and DOM element or if undefined passed of all DOM table elements
		this.setGuideLines = function(elementDOM,visible)
		{
			if (elementDOM)
			{
				if (visible)
				{
					if (elementDOM.style.borderStyle != 'dashed')	
					{ 
						elementDOM.style.borderStyle = 'dashed';
						elementDOM.style.borderWidth = '1';
						elementDOM.style.borderColor = '#AAAAAA';
					}
				}
				else
				{
					if (elementDOM.style.borderStyle == 'dashed')	
					{
						elementDOM.style.borderStyle = '';
						elementDOM.style.borderWidth = '';
						elementDOM.style.borderColor = '';
					}
				}
			}
			else
			{
				var tables = rootDocument.getElementsByTagName('table');
				var c = 0;
				while (c <= tables.length-1)
				{
					this.setGuideLines(tables[c],visible);
					c++;
				}

				var td = rootDocument.getElementsByTagName('td');	
				var c = 0;
				while (c <= td.length-1)
				{
					this.setGuideLines(td[c],visible);
					c++;
				}
			}
		}

		this.filterHTMLCode = function(value)
		{
			var result = value;
			
			//override to filter HTML code to your needs

			return result;
		}

		//is design mode enabled?
		this.getDesignMode = function()
		{
			return designMode;
		}

		//enables or disabled design mode
		this.setDesignMode = function(value)
		{
			if (value != designMode)
			{
				if (value == false)
				{
					//show html code
					this.selectedObject.reset();

					if (document.all)
					{
						rootDocument.body.innerText = this.filterHTMLCode(rootDocument.body.innerHTML);
					}
					else
					{
						rootDocument.body.textContent = this.filterHTMLCode(rootDocument.body.innerHTML);
					}

					rootDocument.body.className = 'bodyEditorHTMLMode';

					if (!this.htmlCodeEditable)
					{
						rootDocument.body.contentEditable = false;
						if (!document.all) { 
							rootDocument.designMode = 'off';
						}
					}

					designTool = 0;
				} 
				else					
				{
					//edit document in design mode
					
					if (!initializeRunning)
					{
						rootDocument.body.innerHTML = this.filterHTMLCode((document.all)?rootDocument.body.innerText:rootDocument.body.textContent);
					}

					rootDocument.body.contentEditable = true;
					if (!document.all) { 
						rootDocument.designMode = 'on'; //only needed for firefox 2, causes not working script in ie, http://devedge-temp.mozilla.org/viewsource/2003/midas/01/index_en.html
					}

					rootDocument.body.className = 'bodyEditorDesignMode';
				}
	
				designMode = value;
			}

			this.setNotifications(value);
			if (!this.blockEvents) { this.OnDesignerChanged(true); }
		}

		this.setDesignTool = function(value)
		{
			if (value != designTool)
			{
				designTool = value;
				if (!this.blockEvents) { this.OnDesignerChanged(false); }
			}
		}

		this.getDesignTool = function()
		{
			var result;

			//wenn kein designmodus oder kein element selektiert dann auch keine palette
			if (this.getDesignMode() && this.selectedObject.isValid()) { result = designTool; }  else { result = 0; }

			return result;
		}


		this.getDocumentHTMLCode = function()
		{
			var result = "";

			if (!this.getDesignMode())
			{
				result = (document.all)?rootDocument.body.innerText:rootDocument.body.textContent;		
			} 
			else					
			{
				result = rootDocument.body.innerHTML;
			}

			return result;
		}
		
		this.getDocumentFormFields = function()
		{
			var result = new Array();

			elements = rootDocument.getElementsByTagName('input');
			for (c=0;c<=elements.length-1;c++) { result.push(elements[c]); }

			elements = rootDocument.getElementsByTagName('select');
			for (c=0;c<=elements.length-1;c++) { result.push(elements[c]); }

			elements = rootDocument.getElementsByTagName('textarea');
			for (c=0;c<=elements.length-1;c++) { result.push(elements[c]); }

			return result;
		}

		this.getDocument = function()
		{
			return rootDocument;
		}

		this.getContainer = function()
		{
			return rootContainer;
		}

		this.raiseHTMLCodeChanged = function()
		{
			currentHTMLCode = this.getDocumentHTMLCode();

			if (htmlCode != currentHTMLCode)
			{
				htmlCode = currentHTMLCode;
				if (!this.blockEvents) { this.OnHTMLCodeChanged(); }
			}
		}
		
		this.onMouseUpHandler = function(eventObject)
		{
			var event = eventObject;
			var keyCode = null;

			if (!event) { event = rootContainer.event; }

			if ((document.all && !window.opera && event.button == 1) || ((!document.all || window.opera) && event.button == 0)) //allow left mouse button only
			{
				if (!getEditorElementFromSelection(rootDocument))
				{
					//alert('Bitte klicken Sie zuerst an eine freie Stelle im Formular bevor Sie zum ersten mal ein Element auswählen.');
					//alert(document.elementFromPoint(event.x, event.y).outerHTML)
					//document.elementFromPoint(event.x, event.y).setActive();
					//document.elementFromPoint(event.x, event.y).focus();
					self.selectElement(null);
				}
				else
				{
				    self.refreshSelection();
				}
			}
		}
		
		this.onKeyUpHandler = function(eventObject)
		{
		    var event = eventObject;
		    var keyCode = null;

		    if (!event) { event = rootContainer.event; }
		    if (event.which) { keyCode = event.which; } else { keyCode = event.keyCode; }

		    if (keyCode)	
		    {
			    //http://msdn.microsoft.com/workshop/author/dhtml/reference/events/onkeyup.asp
    			
			    self.OnKeyUp(keyCode);
			    if (
				    keyCode == 13 || 	//enter
				    keyCode == 46 || 	//delete
				    keyCode == 37 || 	//left
				    keyCode == 38 || 	//up
				    keyCode == 39 || 	//right
				    keyCode == 40 || 	//bottom
				    keyCode == 36 || 	//pos
				    keyCode == 35 || 	//end
				    keyCode == 34 || 	//pgdn
				    keyCode == 33		//pgup
			    ) 	{ self.refreshSelection(); }
			    else 	
				{ self.raiseHTMLCodeChanged(); }
		    }
		}

		this.setNotifications = function(value)
		{
			if (value)
			{
				//register notifications
				this.registerEvent(rootDocument.body,'mouseup',this.onMouseUpHandler);
				this.registerEvent(rootDocument.body,'keyup',this.onKeyUpHandler);
			}
			else
			{
				//unregister notifications
				this.unregisterEvent(rootDocument.body,'mouseup', this.onMouseUpHandler);
				this.unregisterEvent(rootDocument.body,'keyup', this.onKeyUpHandler);
			}
		}
	
		//first method that should be called, container is window or frame
		this.initialize = function(container,enableDesignMode,enableGuideLines,designTool)
		{
			htmlHelper = new THTMLHelper;
			rootContainer = container;
			rootDocument = rootContainer.document;

			rootDocument.body.MultipleSelection = false;

			designMode = !enableDesignMode;

			this.setDesignMode(enableDesignMode);
			this.enableGuideLines(enableGuideLines);
			this.setDesignTool(designTool);

			initializeRunning = false;
		}

		//inserts object nearby an existing element passed to parameter nearestElement
		this.insertElement = function(nearestElement,elementID)
		{
			var result = null;

			if (nearestElement.getObject().execCommand)
			{
				var location = nearestElement.getObject();
				var uniqueID = getUniqueDOMID(elementID);

				if (elementID == 'upload') { location.execCommand('InsertInputImage',false,uniqueID); } else
				if (elementID == 'text') { location.execCommand('InsertInputText',false,uniqueID); } else
				if (elementID == 'hidden') { location.execCommand('InsertInputHidden',false,uniqueID); } else
				if (elementID == 'password') { location.execCommand('InsertInputPassword',false,uniqueID); } else
				if (elementID == 'dropdown') { location.execCommand('InsertSelectDropdown',false,uniqueID); } else
				if (elementID == 'submit') { location.execCommand('InsertInputSubmit',false,uniqueID); } else
				if (elementID == 'reset') { location.execCommand('InsertInputReset',false,uniqueID); } else
				if (elementID == 'textarea') { location.execCommand('InsertTextArea',false,uniqueID); } else
				if (elementID == 'checkbox') { location.execCommand('InsertInputCheckbox',false,uniqueID); } else
				if (elementID == 'radio') { location.execCommand('InsertInputRadio',false,uniqueID); } else
				if (elementID == 'file') { location.execCommand('InsertInputFileUpload',false,uniqueID); } else
				if (elementID == 'button') { location.execCommand('InsertInputButton',false,uniqueID); } else
				if (elementID == 'table') { 
					elementArray = htmlHelper.createTable(rootDocument);

					this.setGuideLines(elementArray[0],this.getGuideLines(null)); //table
					this.setGuideLines(elementArray[3],this.getGuideLines(null)); //tcell

					nearestElement.getObject().pasteHTML(elementArray[0].outerHTML); 
				}

				result = getEditorElementFromSelection(rootDocument);
				if (elementID == 'checkbox') { result.setValue(1); }
				if (elementID == 'upload') { result.setSource('/images/controls/upload.gif'); }

				if (result)
				{
					if (!this.blockEvents) { this.OnElementInserted(result,elementID); }
					this.refreshSelection();
				}
			}

			return result;
		}

		this.selectElement = function(element)
		{
			if (element) 
			{
				element.select();
			} 
			else
			{
				if (rootDocument.selection)
				{
					rootDocument.selection.empty();
				}
				this.selectedObject.reset();
			}

			this.refreshSelection();
		}

		this.deleteElement = function(element)
		{
			if (element)
			{
				//todo,element direkt löschen
			}
			else
			{
				if (rootDocument.selection) 
				{
					if (this.selectedObject)
					{
						var elementID = this.selectedObject.getID();

						this.selectedObject.select();
						rootDocument.selection.createRange().select();
						rootDocument.selection.createRange().execCommand('Delete',false,null);
						
						this.selectElement(null);
						if (!this.blockEvents) { this.OnElementDeleted(elementID); }
					}
				}
			}
		}
				
		//events, override to customize handling
		//typeChanged means that previously selected element had another type
		this.OnElementSelected = function(element,typeChanged)
		{
			
		}

		this.OnElementInserted = function(element,elementID)
		{

		}

		this.OnElementDeleted = function(elementID)
		{
			
		}

		this.OnDesignerChanged = function(refreshProperties)
		{
	
		}

		this.OnKeyDown = function(keyCode)
		{
			return true; //don't cancel event chain		
		}

		this.OnKeyUp = function(keyCode)
		{
	
		}

		this.OnHTMLCodeChanged = function()
		{

		}
}
