/*************************************************************************
*
* ADOBE CONFIDENTIAL
* ___________________
*
*  Copyright 2010 Adobe Systems Incorporated
*  All Rights Reserved.
*
* NOTICE:  All information contained herein is, and remains
* the property of Adobe Systems Incorporated and its suppliers,
* if any.  The intellectual and technical concepts contained
* herein are proprietary to Adobe Systems Incorporated and its
* suppliers and are protected by trade secret or copyright law.
* Dissemination of this information or reproduction of this material
* is strictly forbidden unless prior written permission is obtained
* from Adobe Systems Incorporated.
**************************************************************************/


//************************GLOBALS**************************

//Booleans to check for resources and guard against redundancy.
var hasJqmJavascriptSource = false;
var hasJqmJquerySource = false;
var hasJqmCSSSource = false;

//Markup variables
var markupArr;
var markupHead, markupContent, markupFoot;
var widgetMarkup, widgetId;

//******************* API **********************

//--------------------------------------------------------------------
// FUNCTION:
//   addMarkup
//
// DESCRIPTION:
//	 Wrapper function for checking validity of insertion point and inserting
//	 markup if valid. Alerts error message to get warning window rather than
//	 error window.
//--------------------------------------------------------------------
function addMarkup() {
	var errMsg = checkSelection();
   
	//Is the insertion point valid?
	if (errMsg == "") {
		insertMarkup();
	} else {
		alert(errMsg);
	}
}

//--------------------------------------------------------------------
// FUNCTION:
//   checkSelection
//
// DESCRIPTION:
//   Check to see if selection is in a valid place. Current
//	 validation requires selection to be within any <div> with data-role= "page".
//
// RETURNS:
//   String containing error message if position is invalid.
//--------------------------------------------------------------------
function checkSelection() {
	//Reusable variables
	var i, len, node;
   
	var dom = dw.getDocumentDOM();
	var curPos = dom.getSelection()[0];
	var jqmElements = dom.getElementsByAttributeName("data-role");
	len = jqmElements.length;                                         
   
	var attr, offsetArr;
	var errMsg = "";
   
	offsetArr = [];
	errMsg = dw.loadString("Commands/jQM/generic/alert/pageDivError");
	for (i = 0; i < len; i ++) {
		node = jqmElements[i];
		attr = node.getAttribute("data-role");
		if (attr == "page") {
			offsetArr.push(node);
		}
	}
	len = offsetArr.length;
   
	//Are there any good <div>'s?
	if (len > 0) {
		var id;

		//Check to see if cursor is inside any of them.
		for (i = 0; i < len; i ++) {
			node = dom.nodeToOffsets(offsetArr[i]);
			if (curPos > node[0] && curPos < node[1]) {
				return "";
			}
		}
	}
	return errMsg;
}

//--------------------------------------------------------------------
// FUNCTION:
//   insertMarkup
//
// DESCRIPTION:
//   Inserts markup at current selection point. Assumes that current position
//	 is a valid point of insertion.
//--------------------------------------------------------------------
function insertMarkup() {
	var dom = dw.getDocumentDOM();
   
	//Current position of the cursor               
	var curPos = dom.getSelection()[0];
	var docEl = dom.documentElement;
	var docElOuterHTML = docEl.outerHTML;
	docEl.outerHTML = docElOuterHTML.substring(0, curPos) + widgetMarkup + docElOuterHTML.substring(curPos);

	if (!checkForResources(dom)) {
		//Add resources if we're missing some
		addResources(dom);
	}
	highlightNode();
}

//--------------------------------------------------------------------
// FUNCTION:
//   highlightNode
//
// DESCRIPTION:
//   Highlight the main inserted widget markup.
//--------------------------------------------------------------------
function highlightNode() {
	var dom = dw.getDocumentDOM();
	var page, i, offsets;
	
	//Node type to scrape through.
	var nodeType = "div";

	//Trim down DOM scraping by isolating special cases
	if (widgetId.indexOf("jQMList") != -1) {
		nodeType = "ul";
	} else if (widgetId.indexOf("jQMLinkBtn") != -1) {
		nodeType = "a";
	} else if (widgetId.indexOf("jQMButtonBtn") != -1) {
		nodeType = "button";
	} else if (widgetId.indexOf("jQMInputBtn") != -1) {
		nodeType = "input";
	} else if (widgetId.indexOf("Ordered") != -1) {
		nodeType = "ol";
	}
	
	var theNodes = dom.getElementsByTagName(nodeType);
	var len = theNodes.length;

	for (i = 0; i < len; i ++) {
		page = theNodes[i];
		if (page.getTranslatedAttribute('transId') == widgetId) {
			offsets = dom.nodeToOffsets(page);
			dom.setSelection(offsets[0], offsets[1]);	
		}
	}
}

//--------------------------------------------------------------------
// FUNCTION:
//   checkForResources
//
// DESCRIPTION:
//   Checks the elements of <head> to see if any of the jQuery Mobile scripts are already included.
//
// ARGUMENTS:
//   dom - DOM object of the user's current page.
//
// RETURNS:
//   Boolean of whether all of the required files are present.
//--------------------------------------------------------------------
function checkForResources(dom) {
   
	//Reset booleans.
	hasJqmJavascriptSource = false;
	hasJqmJquerySource = false;
	hasJqmCSSSource = false;
   
	srcChecker(dom);

	return hasJqmJquerySource && hasJqmJavascriptSource && hasJqmCSSSource;
}

//--------------------------------------------------------------------
// FUNCTION:
//   srcChecker
//
// DESCRIPTION:
//   Scrapes the <head> looking for <script> and <link> with the correct jQM references
//	 and updates if they exist, in addition to returning an array with references to the
// 	 node (For deletion).
//
// ARGUMENTS:
//   dom - DOM object of the user's current page.
//
// RETURNS:
//   Array of the nodes matching the jQuery Mobile resources.
//--------------------------------------------------------------------
function srcChecker(dom) {
	var head = dom.getElementsByTagName("head")[0];
	var headChildren = head.childNodes;
	var len = headChildren.length;
	
	var i, src, node;
	var srcArr, fileName, coreFile;
	var srcNodes = new Array();

	for (i = 0; i < len; i ++) {
		node = headChildren[i];
		
		//Skip over comment node.
		if (node.nodeType == document.COMMENT_NODE) {
			continue;
		}

		src = node.getAttribute("src");
		//Do we have a JS file?
		if (src) {
			srcArr = src.split("/");
			fileName = srcArr[srcArr.length-1];
		} else {
			//What about the CSS file?
			src = node.getAttribute("href");

			if (src) {
				srcArr = src.split("/");
				fileName = srcArr[srcArr.length-1];
			} else {
				//No src, move onto next node.
				continue;
			}
		}
	
		//Search for remote script tags as workaround to duplicate insertion.
		if (validFileName(fileName, "js")) {
			hasJqmJavascriptSource = true;
			srcNodes.push(node);
			continue;
		}
		
		if (validFileName(fileName, "jq")) {
			hasJqmJquerySource = true;
			srcNodes.push(node);
			continue;
		}
	   
		if (validFileName(fileName, "css")) {
			hasJqmCSSSource = true;
			srcNodes.push(node);
		}
	}

	return srcNodes;	
}

//--------------------------------------------------------------------
// FUNCTION:
//   idCheck
//
// DESCRIPTION:
//   Check the validity of the ID.
//
// ARGUMENTS:
//   id - String consisting of the ID of an element.
//
// RETURNS:
//   Boolean determining if the ID is W3C valid or not.
//--------------------------------------------------------------------
function idCheck(id) {
	var regExp = new RegExp('[a-zA-Z][\\w\-\:\.]*');
	return (regExp.exec(id) == id);
}

//--------------------------------------------------------------------
// FUNCTION:
//   addResources
//
// DESCRIPTION:
//   Writes out any missing resource tags in the document. Uses boolean checks as a workaround to prevent
//	 adding any duplicate tags.
//
// ARGUMENTS:
//   dom - DOM object of the user's current page.
//--------------------------------------------------------------------
function addResources(dom) {
	var assets = [];
	var obj = {}; 
	var linkTypeValue = dw.getPreferenceString(PREF_SECTION, PREF_LINK_TYPE, PREF_LINK_REMOTE);
	var cssDest, jsDest, jqDest;

	var jsSrc, cssSrc, jqSrc;
	var blank = "";

	linkTypeValue = parseInt(linkTypeValue);
	switch (linkTypeValue) {
		case PREF_LINK_REMOTE:
			var jsSrc = dw.getPreferenceString(PREF_SECTION, REMOTE_JS, jqmJavascriptSource);
			var cssSrc = dw.getPreferenceString(PREF_SECTION, REMOTE_CSS, jqmCSSSource);
			var jqSrc = dw.getPreferenceString(PREF_SECTION, REMOTE_JQ, jqmJquerySource);
			
			cssDest = blank;
			jsDest = blank;
			jqDest = blank;
			
			break;
		case PREF_LINK_LOCAL:
			//Default file paths.
			var libPath = dw.getConfigurationPath() + "/" + assetDir;
			var locJS = libPath + localJS;
			var locCSS = libPath + localCSS;
			var locJQ = libPath + localJQ;
			var iconDir = libPath + localIconDir;
			
			var libSrc = dw.getPreferenceString(PREF_SECTION, PREF_JQLIB_SOURCE_FOLDER, libPath);
			var iconSrc = libSrc;
			if (libSrc[libSrc.length-1] != "/") {
				iconSrc += "/";
			}
			iconSrc += localIconDir;
			
			//Get preferences
			var jsSrc = dw.getPreferenceString(PREF_SECTION, PREF_JQM_JS_SRC, locJS);
			var cssSrc = dw.getPreferenceString(PREF_SECTION, PREF_JQM_CSS_SRC, locCSS);
			var jqSrc = dw.getPreferenceString(PREF_SECTION, PREF_JQ_JS_SRC, locJQ);
			var jsDest = dw.getPreferenceString(PREF_SECTION, PREF_JQM_JS_DEST, jqmDir+localJS);
			var cssDest = dw.getPreferenceString(PREF_SECTION, PREF_JQM_CSS_DEST, jqmDir+localCSS);
			var jqDest = dw.getPreferenceString(PREF_SECTION, PREF_JQ_JS_DEST, jqmDir+localJQ);
			var iconDest = dw.getPreferenceString(PREF_SECTION, PREF_ICON_DIR, jqmDir+localIconDir);
			
			//Check file validity, defaulting to defaults if source is invalid. (For the case of quick insertion, no dialog)
			if (!dwscripts.isFile(jsSrc)) {
				jsSrc = libPath + localJS;
			}
			if (!dwscripts.isFile(cssSrc)) {
				cssSrc = libPath + localCSS;
			}
			if (!dwscripts.isFile(jqSrc)) {
				jqSrc = libPath + localJQ;
			}
			if (!dwscripts.isFolder(iconSrc)) {
				iconSrc = iconDir;
			}

			obj = {};
			obj.srcURL = iconSrc;
			obj.refType = "";
			obj.destURL = iconDest;
			obj.useDefaultFolder = false;
			obj.documentRelative = false;
			assets.push(obj);
			
			break;
	}
   
	if (!hasJqmCSSSource) {
		obj = {};
		obj.srcURL = cssSrc;
		obj.refType = "link";
		obj.destURL = cssDest;
		obj.useDefaultFolder = false;
		obj.documentRelative = false;
		assets.push(obj);
	}

	if (!hasJqmJquerySource) {
		obj = {};               
		obj.srcURL = jqSrc;
		obj.refType = "javascript";
		obj.destURL = jqDest;
		obj.useDefaultFolder = false;
		obj.documentRelative = false;  
		assets.push(obj);
	}
   
	if (!hasJqmJavascriptSource) {
		obj = {};
		obj.srcURL = jsSrc;
		obj.refType = "javascript";
		obj.destURL = jsDest;
		obj.useDefaultFolder = false;
		obj.documentRelative = false;
		assets.push(obj);
	}
	
	dom.copyAssets(assets);
}

//--------------------------------------------------------------------
// FUNCTION:
//   delFunc
//
// DESCRIPTION:
//   Function handler to do cleanup of resources upon removal of the last jQM-related 
//	 element upon sync between the two views.
//
// ARGUMENTS:
//   dom - DOM object of the user's current page.
//--------------------------------------------------------------------
function delFunc(dom) {
	return function(e) {
		var eles = dom.getElementsByAttributeName("data-role");
		var numEles = eles.length;

		//Is this the last jQM-related element?
		if (numEles == 1) {
			var srcNodes = srcChecker(dom);
			var len = srcNodes.length;
			
			var node;
			for (var i = 0; i < len; i ++) {
				node = srcNodes[i];
				removeNode(node, dom);
			}
		}
	}
}

//--------------------------------------------------------------------
// FUNCTION:
//   validFileName
//
// DESCRIPTION:
//   Given a file name and type, checks to see if it conforms to our pattern.
//
// ARGUMENTS:
//   fileName - String consisting of the name of the file.
//	 fileType - String indicating which type of file to match against.
//
// RETURNS:
//   Boolean of whether or not the file name matches the pattern for the file type.
//--------------------------------------------------------------------
function validFileName(fileName, fileType) {
	/** Base Name + [Version Number] + [Minified] + ExtensionName 
	  * Bracketed items are optional, version number begins with '-' and accounts for alpha/beta versions. */
	var fileBase = "jquery";
	var mobileBase = ".mobile";
	var fileExt = '.' + fileType;
	
	if (fileType == "jq") {
		mobileBase = "";
		fileExt = ".js";
		
	}
	var regExpBase = ".*";
	var re = fileBase + mobileBase + regExpBase+fileExt;
	var regExp = new RegExp(re, 'g');
	
	return regExp.test(fileName);
}

//--------------------------------------------------------------------
// FUNCTION:
//   getUniqueNameForTag
//
// DESCRIPTION:
//   Given a tag type and a base name, checks tags of the same type
//   to determine a unique name.  Unique names are formed by adding a
//   count to the base name only if provided name is not already taken.
//	 Minor modification of dwscripts.getUniqueNameForTag
//
// ARGUMENTS:
//   tagType - string - the type of tags to search for matching names
//   baseName - string - the root variable name, to which the count
//     will be added.
//
// RETURNS:
//   string
//--------------------------------------------------------------------

function getUniqueNameForTag(tagType, baseName) {
  var dom = dw.getDocumentDOM();
  var tagCounter = 1;
  var possName = baseName;

  var objArray = dom.body.getElementsByTagName(tagType.toUpperCase());
  var objNames = new Array();
  var objName;

  if (objArray.length > 0) {
    // create the list of object names
    for (var i=0; i < objArray.length; i++) {
      objName = objArray[i].getAttribute("name");
      if (objName) {
        objNames.push(objName);
      }

      objName = objArray[i].getAttribute("id");
      if (objName) {
        objNames.push(objName);
      }
    }
	
	//Check for baseName usage first, before adding on number.
	if (dwscripts.findInArray(objNames, baseName) != -1) {
		possName += tagCounter;
		while (dwscripts.findInArray(objNames,possName) != -1) {
		  tagCounter++;
		  possName = baseName+tagCounter;
		}
	}
  }

  return possName;
}