// Chris Pyper 2006
// Functions for manipulation of content

// Fetch content
function getContent(mode)
{
	debug('getContent()', 'info');

	var turnBackOn = false;

	if(editorOn && !mode && mode != "timed")
	{
		debug('getContent() - Toggling editor OFF to fetch content', 'warn');
		turnBackOn = true;
		stopEditor();
	}
	
	if(!document.getElementById(INNEREDITORID))
	{
		debug('getContent() - Error cannot fetch element id: ' + INNEREDITORID, 'error');
		return false;
	}

	var content =  document.getElementById(INNEREDITORID).innerHTML;

	if(turnBackOn)
        startEditor();

	return content;
}

// Set content
function setContent(content)
{
	debug('setContent()', 'warn');

	var turnBackOn = false;

	if(editorOn)
	{
		debug('setContent() - Toggling editor OFF to set content', 'warn');
		turnBackOn = true;
        stopEditor();
	}

	if(!document.getElementById(INNEREDITORID))
    {
        debug('setContent() - Error cannot fetch element id:' + INNEREDITORID, 'error');
        return false;
    }

	document.getElementById(INNEREDITORID).innerHTML = content;

	if(turnBackOn)
        startEditor();

	return true;
}

// Add background template
function setTemplate(content)
{
	debug('setTemplate()', 'warn');
	
	var turnBackOn = false;

	if(editorOn)
	{
		debug('setTemplate() - Toggling editor OFF to set template', 'warn');
		turnBackOn = true;
        stopEditor();
	}

	document.body.innerHTML = content;

	// Search for a element with the defined ID and replace it with the three required editor tags
	if(document.getElementById(BODYID))
	{
		divOut = document.createElement("div");
    	divOut.id = OUTEREDITORID;

		divMid = document.createElement("div");
    	divMid.id = MIDDLEEDITORID;

		divIn = document.createElement("div");
    	divIn.id = INNEREDITORID;

		divMid.appendChild(divIn);
		divOut.appendChild(divMid);
	
		var docRef = document.getElementById(BODYID);
		docRef.parentNode.replaceChild(divOut, docRef);
	}
	else
		return false;

	if(turnBackOn)
        startEditor();

	return true;
}

// Add style sheet, this may require a reload to call more then once, there are no remove stylesheet methods
function setStyleSheet(url)
{
	debug('setStyleSheet()', 'info');

	var turnBackOn = false;
	
	if(editorOn)
	{
		debug('setStyleSheet() - Toggling editor OFF to set stylesheet', 'warn');
		turnBackOn = true;
        stopEditor();
	}

	var ret = document.styleSheets[0].addImport(url);

	if(turnBackOn)
        startEditor();

	return ret;
}

// Add a element to the editor
function addElement(docRef, top, left, undoRedo, internalCall)
{
	debug('addElement()', 'info');

	if(!editorOn)
	{
		debug('addElement() - Error editor must be on to add element', 'warn');
		return false;
	}

	if(!docRef)
	{
		debug('addElement() - No Element specified', 'error');
		return false;
	}
		
	if(docRef.nodeType != 1 /*Node.ELEMENT_NODE*/)
	{
		debug('addElement() - Element is not a element node', 'error');
		return false;
	}

	if(!document.getElementById(INNEREDITORID))
	{
		debug('addElement() - Cannot find node by id INNEREDITORID', 'error');
		return false;
	}

	// IE won't clone another node that is referenced in a iframe properly, in the case of a undoRedo it is internal
	// so we can use the DOM method cloneNode, it is not effected by the iframe issue.
	if(!ie || undoRedo || internalCall)
		var clone = docRef.cloneNode(true);
	else
	{
		// IE won't clone another node that is referenced in a iframe properly, so we make our own clone
		var clone = document.createElement(docRef.tagName);

		if(docRef.innerHTML)
			clone.innerHTML = docRef.innerHTML;

		// A list of the attributes to copy over
		// ***FIXME*** We need a way to replicat style, right now it return an object not a string so it does not work
		//It's should work for IE style
		clone.style.cssText = docRef.style.cssText;

		var attributes = new Array("name", "id", "className", "style", "src", "width", "height", "ESWID", "onclick", "onload", "alt","img_href", "custom_page");
		for(var i=0; i<attributes.length; ++i)
		{
			var attribute = docRef.getAttribute(attributes[i], 0);
			if(attribute)
				clone.setAttribute(attributes[i], attribute, 0);
			else
				debug("addElement() - attribute not found, skipping : " + attributes[i], 'info');
		}
		
	}

	if(top)
		setStyle(clone, 'top', top, true);
	if(left)
		setStyle(clone, 'left', left, true);
	generateId(clone);
	if (masterMode)
		clone.setAttribute(MASTER_EL_ATTR, "true");

	var docRefId = getId(clone);
	document.getElementById(INNEREDITORID).appendChild(clone);
	var docRef = getElementByESWId(docRefId);
	raiseToTop(docRef);
	if(!undoRedo)
		undoRedoSnapShot(docRef, 'add');
	setStyle(docRef, 'visibility', 'visible');

	// show a little border animation to draw attention to the new element
	if ( docRef.className.indexOf("Plugin") < 0 )
	{
		flashElement(docRef);
//		setTimeout( function() { setStyle(docRef,'border','2px dotted #0289E1'); }, 100 );
//		setTimeout( function() { setStyle(docRef,'border','none'); }, 250 );
//		setTimeout( function() { setStyle(docRef,'border','2px dotted #04B9FF'); }, 350 );
//		setTimeout( function() { setStyle(docRef,'border','none'); }, 500 );
	}

	documentChanged = true;
	return docRefId;
}

function deleteElement(docObj, undoRedo)
{
    debug('deleteElement()', 'info');

    var delDocRef = getElementByESWId(getId(docObj));

	if(delDocRef)
	{
    	// Take undo/redo snapshot
		if(!undoRedo)
    		undoRedoSnapShot(delDocRef, 'delete');

		// Remove from DOM tree
		delDocRef.parentNode.removeChild(delDocRef);
	}
	else
	{
		debug('deleteElement() Error id/name not found, cannot delete', 'error');
		return false;
	}

	documentChanged = true;

    return true;
}

function changeElementId(oldId,newId)
{
	var el = getElementByESWId(oldId);

	if ( el )
	{
		debug("changeElementId(): " + oldId + " becomes " + newId, "info");
		el.id = newId;
		return newId;
	}
	else
	{
		debug("changeElementId(): element not found: " + oldId, "error");
		return oldId;
	}

}

// Edit an element with an external editor
function externalEditSelectedElement(e)
{
	debug("externalEditSelectedElement()", 'info');

    if(!docSourceClone)
    {
        debug('externalEditSelectedElement() no element selected', 'warn');
        return false;
    }

	var docObj = getDocObjFromClone();

	if ( EXTERNAL_EDITORS[docObj.tagName] )
	{
		EXTERNAL_EDITORS[docObj.tagName](docObj);

		documentChanged = true;
		return true;
	}
	else
	{
		debug('No external editor defined for ' + docObj.tagName + ' tag.', 'warn');
		return false;
	}

}


// Delete the object selected for editing
function deleteSelectedElement(e)
{
	debug("deleteSelectedElement()", 'info');

    if(!docSourceClone)
    {
        debug('deleteSelectedElement() no element selected', 'warn');
        return false;
    }

	var docObj = getDocObjFromClone();

	// Shut her down
    if(docSourceClone)
        designModeOff();

	return deleteElement(docObj);
}


// Duplicate the object selected for editing
function duplicateSelectedElement()
{
	debug("duplicateSelectedElement()", 'info');

	if(!docSourceClone)
	{
		debug('duplicateSelectedElement() no element selected', 'warn');
		return false;
	}

	// Clean up spell check if it is on
	removeSpellCheckHighlighting();
	document.getElementById('spellCheck').innerHTML = '';

	var docObj = getDocObjFromClone();

	// Shut her down
	if(docSourceClone)
		designModeOff();


	// content editable off patch for dup in IE
	if (ie)
		docObj.contentEditable = false;

	// Force generation of new unique id
	generateId(docObj, true);


	// Calculate new offset
	var top  = getStyle(docObj, 'top', true);
	var left = getStyle(docObj, 'left', true);

	return addElement(docObj, top + DUPLICATEOFFSET, left + DUPLICATEOFFSET, false, true);
}

// Cache for selcetion and ranges to maintain highlighting between possible focus change of link editing procedure
var cachedLinkRange	= null;

// Begin hyperlink creation progress, receive signal from interface and return reference to existing link if
// cursor or hightlight is placed on it, otherwise take hightlightted text and create blank link object based 
// upon it. Using link object maintains a consistent DOM based interface.
function createLink() 
{
	debug("createLink()", 'info');

	var link = getParentElement();

	// if element is an image, move up the tree one tag
	if (link && /^img$/i.test(link.tagName))
		link = link.parentNode;
	if (link && !/^a$/i.test(link.tagName))
    {
		debug("createLink() No link, found tag: " + link.tagName, 'info');
		link = null;
	}

	// Cache for unfocus, creating and editing links is a two setp process 
	cachedLinkRange = getRange(getSelection());

	var callBacks = fetchInterface();
	// Make call back to determnie edited link parameters, use existing or create if does not exist
	// pass over entire node to maintain consistent DOM node based interface to editor
	if(link)
		callBacks.triggerCallBack('linkCreate', link);
	else
	{
		var linkStub = document.createElement("a");
		linkStub.innerHTML = getSelectionText();
		callBacks.triggerCallBack('linkCreate', linkStub);
	}

	return true;
}

function receiveLink(linkObj)
{
	debug("receiveLink()", 'info');
	
	// Select previously highlighted content. creating and editing links is a two step process, this is done
	// in case of shift in focus on button click
	cachedRange	= cachedLinkRange;

	// Make sure it is highlighted
	highlightSelection();

	var link = getParentElement();

    // if element is an image, move up the tree one tag
    if (link && /^img$/i.test(link.tagName))
        link = link.parentNode;
    if (link && !/^a$/i.test(link.tagName))
    {
        debug("createLink() No link, found tag: " + link.tagName, 'info');
        link = null;
    }	

	var a = link;
	if (!a) 
	{
		if(ie)
		{		
			// Build it
			execCommand("createlink", false, linkObj.href);

			a = getParentElement();
			var sel = getSelection();
			var range = createRange(sel);
			if (!ie) 
			{
				a = range.startContainer;
				if (!/^a$/i.test(a.tagName))
					a = a.nextSibling;
			}
			a.target    = linkObj.target;
			a.title     = linkObj.title;

		}
		else
		{
			// The selection is not preserved in Gecko based browers, we could do this but it would give the 
			// user the impression they can maipulate it, however they can't because fosus is lost during 
			// the link creation process, thus to higlight it again we must use javascript, which under
			// mozilla means certain functionaliyt will not work on javascript generated ranges and selections.

			a = document.createElement('a');
			a.href   = linkObj.href;
			a.target = linkObj.target;
			a.title  = linkObj.title;

			// ***WARNING EXTREMELY IMPORTANT***
			// This is the final result of much pain and suffering.  When an object is highlighted by javascript, not
			// by the user itself, you cannot execCommand() on the range.  Various other function in the range object
			// such as surroundContents() also do not work.  They all throw very bad exceptions or crash the browser.
			// the only way I have discovered to manipulate selection or text ranges created by javascript, not by the
			// user highlighting, was to use the few methods that did work.  I don't know if those methods alwaays
			// did not work, after all the browser is open source, but this works.
			try
			{
				var range = createRange(createSelection());

				a.innerHTML = range.toString();

				range.deleteContents();
				range.insertNode(a);

				// Gecko sucks balls, the link creation process fucks something up so nothing works right after in the 
				// design mode frame, after some messing around it is discovered that toggling on and off design mode
				// on the iframe fixes this  
				//iframe.contentWindow.document.designMode = "off";
				//iframe.contentWindow.document.designMode = "on"; 
				//var frameId = docSourceOrig.id;
				//designModeOff();
				//designModeOn(document.getElementById(frameId));

				// Looks like the issue above is no more with the Firefox 2.x series... commented out the
				// above 2 lines. Pyper's comment preserved for posterity. :)  -- jwm
			}
			catch(e)
			{
				debug("receiveLink() - EXCEPTION THROWN !!!", "error"); 
			}	

		}
	}
	else 
	{
		// Modify existing
		a.href = linkObj.href;
	}
	a.setAttribute(LINK_HREF_ATTR, linkObj.getAttribute(LINK_HREF_ATTR)); // patch for non cklicable links
	a.href = "#"; // patch for non cklicable links
	a.onclick = function(e){e=(window.event || e); if(!e) return; if(e.preventDefault)e.preventDefault(); e.returnValue=false;};


	return true;
}

// Plugins are represented as DIVs which wrap an IFRAME which hosts the plugin
function insertPlugin(pluginName)
{

	debug("insertPlugin(): " + pluginName, "info");

	var pluginContainer = document.createElement("div");
	var pluginLabel = document.createElement("div");
	var pluginLabelText = document.createElement("span");
	var pluginFrame = document.createElement("iframe");
	var pluginDeleteBtn = document.createElement("button");
	
	pluginContainer.className = "editorPlugin draggable";

	pluginLabel.className = "editorPluginLabel";
	pluginLabelText.className = "editorPluginLabel";
	pluginLabelText.appendChild(document.createTextNode(translate("Configure")));
	pluginLabelText.setAttribute("onclick", "configPlugin(this.parentNode.parentNode.lastChild)", 0);
//	pluginLabelText.setAttribute("style", "", 0);
	pluginDeleteBtn.className = "darkButton";
	pluginDeleteBtn.setAttribute("style", "bottom: 5px; left:5px; position:absolute; width:6px;", 0);
	pluginDeleteBtn.style.cssText = 'bottom: 5px; right:5px; position:absolute;';

	pluginDeleteBtn.appendChild(document.createTextNode("X"));
	pluginLabel.appendChild(pluginLabelText);
	generateId(pluginFrame);
	pluginFrame.className = "editorPluginView";
	
	pluginFrame.setAttribute("src", "plugins/" + pluginName + "/view.html?id="+getId(pluginFrame) + "&lang=" + EDITORUSERLANGUAGE, 0);

	pluginContainer.appendChild(pluginLabel);
//	pluginContainer.appendChild(pluginDeleteBtn);
	pluginContainer.appendChild(pluginFrame);

	//generateId(pluginContainer);

	var res = addElement(pluginContainer, 300, 200, false, false);
	
	//pluginDeleteBtn.setAttribute("onclick", "deleteElement('" + res + "')", 0);
//	getEl(getId(pluginFrame)).previousSibling.onclick = function(){deleteElement('" + res + "')};
	return res;
}

function resizePlugin(pluginFrameId)
{
	// Trim any special character from the beginning of the ID
	// Since this function may be called from a plugin iframe who is
	// passing the id from the "hash" portion of its location url,
	// the first character will usually be '#'
	//if ( !pluginFrameId.substring(0,1).match(/[a-z]|[A-Z]/) )
	//	pluginFrameId = pluginFrameId.substring(1,pluginFrameId.indexOf('?')); // everything between # and ?

	var pluginFrame = document.getElementById(pluginFrameId);

	// Resize the iframe
	pluginFrame.style.width = pluginFrame.contentWindow.pluginObject.getPreferredWidth() + "px";
	pluginFrame.style.height = (pluginFrame.contentWindow.pluginObject.getPreferredHeight() -5 ) + "px";
	
	// And resize the plugin container
	if (pluginFrame.parentNode.firstChild.offsetHeight)
	  pluginFrame.parentNode.style.height = parseInt(pluginFrame.style.height) + pluginFrame.parentNode.firstChild.offsetHeight;
	else
	  pluginFrame.parentNode.style.height = pluginFrame.style.height;
	pluginFrame.parentNode.style.width = pluginFrame.style.width;

}

function configPlugin(pluginFrame)
{
	var name = pluginFrame.contentWindow.pluginObject.getName();
	
	// alert('configPlugin: ' + pluginFrame.id);

	if ( pluginFrame.src.indexOf("conf.html") > 0 )
	{
		pluginFrame.style.opacity = "1.0";
		pluginFrame.src = "plugins/" + name + "/view.html?id=" + pluginFrame.id + "&lang=" + EDITORUSERLANGUAGE;
	}
	else
	{
		pluginFrame.style.opacity = "0.9";
		pluginFrame.src = "plugins/" + name + "/conf.html?id=" + pluginFrame.id + "&lang=" + EDITORUSERLANGUAGE;
	}
	return pluginFrame.src;
}

// edit image properties

function editSelectedImageProperties(e)
{
    debug("editImageProperties()", 'info');

    if(!docSourceClone)
    {
        debug('editSelectedImageProperties() no element selected', 'warn');
        return false;
    }

    var docObj = getDocObjFromClone();

    // Shut her down
    if(docSourceClone)
        designModeOff();

	var callBacks = fetchInterface();
	callBacks.triggerCallBack('openImageProperties', docObj);
	return true;
}

function applySelectedImageProperties(id, img_href, alt, new_wind, bStyle, bWidth, bColor )
{

    var imgObjId = document.getElementById(id);

	if (imgObjId == null)
	  return false;

	var imgObj = document.getElementById(id);
	if (imgObj == null)
	  return false;


    imgObj.setAttribute("alt", alt);
    imgObj.setAttribute("img_href", img_href);
    imgObj.setAttribute("new_wind", new_wind);
	imgObj.style.borderStyle = bStyle;
	imgObj.style.borderColor = bColor;
	imgObj.style.borderWidth = bWidth;
	return true;
}

// edit table props
function editSelectedTableProperties(e)
{
    debug("editSelectedTableProperties()", 'info');

    if(!docSourceClone)
    {
        debug('editSelectedTableProperties() no element selected', 'warn');
        return false;
    }

    var docObj = getDocObjFromClone();


	var callBacks = fetchInterface();
	callBacks.triggerCallBack('openTableProperties', docObj);
	return true;
}

function applySelectedTableProperties(id, div)
{
	var contObj = document.getElementById(id);

	if (contObj == null)
		return false;

	contObj.innerHTML = div.innerHTML;
	return true;
}


