/**
 * @author sigr0005
 * @requires jQuery.js
 */

/**
 * Still just a concept.  Save states as modules to use for the Stellent server.
 * 
 * @param {Object} contentType
 * @param {Object} AJAXModule
 */
function OracleModule(contentType, AJAXModule)
{
	return {"contentType" : contentType, "AJAXModule" : AJAXModule};
}

/**
 * Stellent server object for executing service requests.
 * @param {Object} URL	The URL to a Stellent server.
 */
function OracleServer(hostName, scriptPath)
{
	var me					= this;
	var hostName			= hostName;					// The host name from the URL.
	var scriptPath			= scriptPath;				// The path to the script bin.
	var _onReadyStateChange	= null;						// The user defined onReadyStateChange as defined in the execService function.
	
	if(!((hostName && hostName != "") && (scriptPath && scriptPath != "")))
	{
		console.error("Must include host name and script path in Stellent(hostName, scriptPath).");
		return false;
	}
	
	var httpRequest			= new ajax(hostName);
	httpRequest.addEventListener("onReadyStateChange", function()
	{	// Plus whatever else I may need to do here.
		switch(httpRequest.status)
		{
			case "401": console.warn("Access Denied.");	break;
		}
		
		_onReadyStateChange.call(me);
	});
	
	var modules =
	{
		json	: {contentType: "JSON", ajaxModule : new ajaxModule("POST", {}, false, null, scriptPath)},
		soap	: {contentType: "SOAP", ajaxModule : new ajaxModule("POST", {}, false, null, scriptPath)},
		form	: {contentType: "FORM", ajaxModule : new ajaxModule("POST",
						 {"Content-Type" : "application/x-www-form-urlencoded;", // Todo: Needs to allow for " boundary=".
						  "Connection"	 : "close"
						 },
					 	 false, null, scriptPath)},// + "?IdcService=CHECKIN_UNIVERSAL")},
		file	: {contentType: "GET", 	ajaxModule : new ajaxModule("GET",	{}, false, null, scriptPath)}
	};
	
	// Variables to use in SOAP submissions.
	var idc_serviceTag		= "		<idc:service xmlns:idc=\"http://www.stellent.com/IdcService/\" IdcService=\"";
	var idc_documentTag		= "			<idc:document>\n";
	var idc_field_s			= "				<idc:field name=\"";
	var idc_field_e			= "\">";	//<![CDATA[\n	";
	var idc_field_close		= "</idc:field>\n";	//"\n]]>\n"
	var idc_closeDocument	= "			</idc:document>\n" +
							  "		</idc:service>\n";
	
	/**
	 * Adds a form as part of a contributor file.  Each form input tag is used
	 * to fill in a corresponding element within the contributor file.  Lists
	 * are defined as structured tags such as unordered and list item tags or
	 * even tables.  Of course a structured name will also work such as in one
	 * of the examples given below.
	 * 
	 * <table>
	 * <thead>
	 * 	<tr>
	 * 		<th>Parameter</th><th>Description</th>
	 * 	</tr>
	 * </thead>
	 * <tbody>
	 * 	<tr>
	 * 		<td>localResult</td>
	 * 		<td>
	 * 			<p>The local result set as required when making a service call.
	 * 			Some fields in this result set are required to be set such as
	 * 			the content id (dId).
	 * 			</p>
	 * 		</td>
	 * 	</tr>
	 * 	<tr>
	 * 		<td>rowResultSetName</td>
	 * 		<td>
	 * 			<p>The jQuery path to the tag who's name attribute should be used
	 * 			to generate the result set containing list's fields.</p>
	 * 		</td>
	 * 	</tr>
	 * 	<tr>
	 * 		<td>row</td>
	 * 		<td>
	 * 			<p>The row element jQuery path from the element's form that 
	 * 			identifies which tag is part of a row.  Each element of the row
	 * 			will be linked to the descendents of this tag.</p>
	 * 		</td>
	 * 	</tr>
	 * 	<tr>
	 * 		<td>rowName</td>
	 * 		<td>
	 * 			<p>The regular expression to be used to parse an input tag name
	 * 			for its position and list name.</p>
	 * 			<table>
	 * 			<tbody>
	 * 				<tr>
	 * 					<td>nameIndex</td>
	 * 					<td>
	 * 						<p>The index into the regular expression match that
	 * 						identifies the name to be used in generating the list
	 * 						result set.</p>
	 * 					</td>
	 * 				</tr>
	 * 				<tr>
	 * 					<td>positionIndex</td>
	 * 					<td>
	 * 						<p>The index into the regular expression match that
	 * 						identifies the position in the list row set.</p>
	 * 					</td>
	 * 				</tr>
	 * 			</tbody>
	 * 			</table>
	 * 		</td>
	 * 	</tr>
	 * 	<tr>
	 * 		<td>save</td>
	 * 		<td>
	 * 			<ul>
	 * 				<li>onchange</li>
	 * 				<li>onsubmit</li>
	 * 			</ul>
	 * 		</td>
	 * 	</tr>
	 * 	<tr>
	 * 		<td>debug</td>
	 * 		<td>
	 * 			<ul>
	 * 				<li>showResults</li>
	 * 			</ul>
	 * 		</td>
	 * 	</tr>
	 * </tbody>
	 * </table>
	 * @param {Object} formPath		jQuery path to form
	 * @param {Object} parameters	Parameters to use in locating elements
	 */
	this.addContentForm		= function(formPath, parameters)
	{
		/*
		 * 1. Capture form
		 * 	a. If form doesn't exist, exit with error message (fatal)
		 * 2. Collect parameters
		 * 3. Collect elements
		 * 	a. All decendent <input>s of the form are elements in the SSElementData result set
		 * 	b. <table>s and <ul>/<ol>s with id attributes are considered lists in the SSElementData result set
		 * 		i.  The result set for the list element is named with the id attribut and "rs_" prepended to it.
		 * 		ii. The <table>s and <ul>/<ol>s are excluded from entry regarless of their id attribute if they contain no <input>(s)
		 * 	c. <table>s and <ul>/<ol>s without id attributes will be ignored
		 * 
		 * Elements:
		 * 1. form:input:not(form table[id]):not(form ul[id])
		 * 2. form table[id] input
		 * 3. form ul[id] input
		 */
		
		var form			= $(formPath);
		var elements		= $(formPath + " :input :not(" + formPath + " table[id]) :not(" + formPath + " ul[id])");		// 1. form:input:not(form table[id]):not(form ul[id])
		var formInputTest	= $(formPath + " :input");
		var formInputTest2	= $(formPath + " :not(" + formPath + " table[id] :input) :input");
		var formInputTest3	= $(formPath + " :input").not(formPath + " table[id] :input");

		var temp		= "form = \n";
		for(var e in form)
		{
			if(typeof(form[e]) != "function")
				temp	+= e + " = " + form[e] + ",\n";
		}
		alert(temp);
		
		temp		= "elements = \n";
		for(var e in elements)
		{
			if(typeof(elements[e]) != "function")
				temp	+= e + " = " + elements[e] + ",\n";
		}
		alert(temp);

		temp		= "formInputTest = \n";
		for(var e in formInputTest)
		{
			if(typeof(formInputTest[e]) != "function")
				temp	+= e + " = " + formInputTest[e] + ",\n";
		}
		
		temp		+= "\nformInputTest2 = \n";
		for(var e in formInputTest2)
		{
			if(typeof(formInputTest2[e]) != "function")
			{
				if(formInputTest2[e].tagName && formInputTest2[e].tagName.toLowerCase() == "input")
					temp	+= e + " = " + formInputTest2[e] + ": name=\"" + formInputTest2[e].name + "\",\n";
				else
					temp	+= e + " = " + formInputTest2[e] + ",\n";
			}
		}
		
		temp		+= "\nformInputTest3 = \n";
		for(var e in formInputTest3)
		{
			if(typeof(formInputTest3[e]) != "function")
				temp	+= e + " = " + formInputTest3[e] + ",\n";
		}
		
		alert(temp);
	};
	
	this.addEventListener	= function(event, callback)
	{
		switch(event.toLowerCase())
		{
			case "onreadystatechange":
				httpRequest.addEventListener(event, callback);
				break;
		}
	};
	
	/**
	 * Calls a Stellent service.<br />
	 * <b>Parameter Usage:</b><br />
	 * <pre>
	 * {
	 * 	"name" : 
	 * 	{
	 * 		"type"	: /^(text)|(filename)|(hidden)$/, 
	 * 	 	"value"	: <i>[String]</i>
	 * 	}
	 * }
	 * </pre>
	 * Services:
	 * <table>
	 * <tbody>
	 * 	<tr>
	 * 		<th>Service Name</th><th>Description</th><th>Parameters</th>
	 * 	</tr>
	 * 	<tr>
	 * 		<td>
	 * 			SS_SETELEMENTS
	 * 		</td>
	 * 		<td>
	 * 			Sets the elements within a contributor region of a Site Studio content file.
	 * 		</td>
	 * 		<td>
	 * 			ContributorFile<br />
	 * 			<p>The JSON structure of the complete content file.  This will include the
	 * 			"local data" result set</p>
	 * 			Form<br />
	 * 			<p>The form to use to update the JSON structure.  Each field element within
	 * 			the form will be used to set the corresponding values within the JSON
	 * 			object.</p>
	 * 		</td>
	 * 	</tr>
	 * </tbody>
	 * </table>
	 * @param {Object} 		IdcService	The name of the Stellent service to make a HTTP request to.
	 * @param {Object} 		formData	An array for each field name, their type and value.
	 */
	this.execService		= function(IdcService, contentData, asynchronous, onReadyStateChange)
	{
		// Todo: Allow for SOAP submissions as well as Forms.
		// Todo: Validate onReadyStateChange if necessary.
		// Todo: Should all contentData be in the form of {type: "", value: ""}?
		var module;
		
		contentData["IdcService"]	= IdcService;
		
		// Todo: Validate contentData
		switch(IdcService)
		{
			case "SS_SETELEMENTS":		module	= modules.json;	break;	// Is the content meta fields set?
			case "GET_FILE":			module	= modules.file;	break;
			case "GET_SEARCH_RESULTS":	module	= modules.soap;	break;
			//case "CHECK_OUT":			break;
			case "CHECKIN_UNIVERSAL":	module	= modules.soap;	break;	// Check that file was checked out first.
			default:
				console.error("Service not yet supported.");
				return false;
		}
		
		module.asynchronous			= asynchronous;
		_onReadyStateChange			= onReadyStateChange;
		send(module, contentData);
		
		if(!asynchronous)	// Todo: Add more attributes here.
			return { responseText: httpRequest.responseText, status : httpRequest.status };
	};
	
	toURI					= function(contentData)
	{
		var URI	= "";
		for(var content in contentData)	URI	+= content + "=" + encodeURI(contentData[content]) + "&";
		URI	= URI.substring(0, URI.length - 1);
		
		return URI;
	};
	
	setBoundary				= function(formData)
	{
		var boundaryIsNotUnique	= true;
		var boundary			= "_1234567Divider";

		/*
		while(boundaryIsNotUnique)
		{
			
		}
		//*/
		return boundary;
	};
	
	toSoap					= function(contentData)
	{
		var contentSoap	= new soapXml();
		var content		= idc_serviceTag + contentData.IdcService + "\">\r\n" + idc_documentTag;
		var file		= "";
		var fileName	= "";
		
		for(var fieldName in contentData)
		{	// {"<i>[Field Name]</i>" : "<i>[Filed Contents]</i>"}
			if(fieldName != "" && fieldName != "IdcService" && fieldName != "fileName")
			{
				if(fieldName == "primaryFile")
				{
					fileName = contentData.fileName.replace(/\\/g, "/");
					file	 = contentData.primaryFile;
					content += "<idc:file name=\"" + fieldName + "\" href=\"cid:" + fileName + "\" />\r\n";
//					content += "<idc:field name=\"" + fieldName + "\" href=\"" + fileName + "\" />\r\n";
//					content += "<idc:field name=\"" + fieldName + "\">" + fileName + "</idc:field>\r\n";
				}
				else
				{
					content	+= "<idc:field name=\"" + fieldName + "\">";
					content	+= contentData[fieldName].replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
					content	+= idc_field_close;
				}
			}
		}
		content		   += idc_closeDocument;
		
		contentSoap.appendBody(content);
		
		if(file != "")
		{			
			var boundary	= setBoundary(content + file);
			httpRequest.setRequestHeader("MIME-Version",	"1.0");
			httpRequest.setRequestHeader("Content-Type",	"multipart/related; type=text/xml; start=\"<AHC_DELETE_ME@this.com>\"; boundary=" + boundary);// + "\"");
			//httpRequest.setRequestHeader("SOAPAction",	hostName + scriptPath);
			
			var send		= "--" + boundary + "\r\n";
			send		   += "Content-ID: <AHC_DELETE_ME@this.com>\r\n";
			send		   += "Content-Type: application/soap+xml; charset=UTF-8\r\n";
			send		   += "Content-Transfer-Encoding: 8bit\r\n\r\n";
			send		   += contentSoap.toString() + "\r\n";
			send		   += "--" + boundary + "\r\n";
			send		   += "Content-Disposition: attachment; name=\"primaryFile\"; filename=\"" + fileName + "\"\r\n";
			send		   += "Content-Transfer-Encoding: 8bit\r\n";
			send		   += "Content-ID: <" + fileName + ">\r\n";
			send		   += "Content-Location: " + fileName + "\r\n";
			send		   += "Content-Type: text/xml; charset=UTF-8\r\n\r\n" + file + "\r\n";
			send		   += "--" + boundary + "--";
			
//			count			= send.length;
//			header			= "Content-Type: multipart/related; type=text/xml; start=\"<AHC_DELETE_ME@this.com>\"; boundary=" + boundary + "\r\n";
//			header		   += "Content_Length: " + send.length + "\r\n\r\n";
//			send			= header + "--" + boundary + "\r\n" + send;
			
			return send;
		}
		else
		{
			return contentSoap.toString();
		}
	};
	
	toForm					= function(contentData)
	{
		var boundary	= setBoundary(contentData);
//		httpRequest.setRequestHeader("Content-Type",	"multipart/form-data; boundary=" + boundary);
		
		content			= "";//"--" + boundary;
		content 	   += "Content-Disposition: form-data; name=\"IdcService\"\nContent-Type: text/plain\n\nCHECKIN_UNIVERSAL\n";
		for(var fieldName in contentData)
		{
			content += "--" + boundary + "\n" + "Content-Disposition: form-data; name=\"" + fieldName + "\"";
			
			if(fieldName == "primaryFile")
			{
				content += "; filename=\"" + "comments.xml" + "\"\n";
				content += "Content-Type: text/xml";
			}
			else	content	+= "\nContent-Type: text/plain";
			
			content	+= "\n\n" + contentData[fieldName] + "\n";
		}	
		content += "--" + boundary + "--";
		
		head			= "Content-Type: multipart/form-data; boundary=" + boundary + "\n";
		head		   += "Content-Length: " + content.length + "\n\n";
		
		alert(head + "--" + boundary + "\n" + content);
		return head + "--" + boundary + "\n" + content;
	};
	
	send					= function(module, contentData)
	{
		// Todo: If the server returns an error then display responseText in a new window.
		httpRequest.setModule(module.ajaxModule);
		
		var content	= "";
		switch(module.contentType.toUpperCase())
		{
			case "JOSN":	content	= json(contentData);	break;	// Assume the content is the JSON string.
			case "GET":		content	= toURI(contentData);	break;
			case "SOAP": 	content	= toSoap(contentData);	break;
			case "FORM": 	content	= toForm(contentData);	break;
			default:		console.error("stellent: content type not supported yet.");
							return false;
		}
		
		httpRequest.send(content);
	};
}
