/*! Help & Manual WebHelp 3 Script functions
Copyright (c) 2015-2018 by Tim Green. All rights reserved. Contact tg@it-authoring.com
*/

function xMsg(ogn) {

	// Debugging variable for checking which page the function is running from, intialize with an ID for the page
	var thisOrigin = ogn + ": ",
		xAnchor = /^https??:\/\//im.test(document.location) ? "\?" : "\!";
	
	// We need the domain and protocol when online but not when running locally 
	var docDomain = document.domain;
		if (docDomain !== "" && location.protocol !== "file:")  {
			docDomain = location.protocol + "//" + docDomain + (location.port !== "" ? ":" + location.port : "");
			}
			else {
				docDomain = "*";
			}
	
	// Basic sendmessage function, we don't usually call postMessage directly because the callback needs to be formatted
	function sendmessage(target, message, callback) {
		try {
			var t = typeof target !== "string" ? target : target === "parent" ? parent : target.indexOf("parent.") === 0 ? parent.frames[target.substr(7)].contentWindow : document.getElementById(target).contentWindow;
			if (typeof message == "object") {
				t.postMessage(message,docDomain);
				} else if (typeof message == "string") {
			//console.log("SENDMESSAGE WARNING: Deprecated postMessage with string message: " + message + (callback ? "," + callback : "") + " target: " + target.toString());
			t.postMessage(message + (callback ? "," + callback : ""),docDomain);
				}
			} catch(e) {
			console.log(thisOrigin + "SENDMESSAGE ERROR: " + target + " / " + message + " / " + callback + " / "  + e.message);
			}
		}

	// Handle special starred arguments passed as strings	
	function starArg(a){
		var b;
		a = a.replace(/^\*/,"");
		switch(a){
			case "true":
			return true;
			case "false":
			return false;
			case "null":
			return null;
			case "undefined":
			return undefined;
			default:
			b = parseFloat(a,10);
			if (!isNaN(b))
				return b;
			else
				return a;
		}
	}
	// Execute messaged functions by name without eval or new Function
	function executeFunctionByName(functionName, context ) {
	  var theseargs = typeof arguments[2] == "object" ? arguments[2] : [].slice.call(arguments,2);
	  var namespaces = functionName.split(".");
	  var func = namespaces.pop();
	  for(var i = 0; i < namespaces.length; i++) {
	    context = context[namespaces[i]];
	  }
	  return context[func].apply(context, theseargs);
	}

	// Get and set variables/object properties by name
	function getSetVarByName(varName, varVal) {
		var thisObject = window,
			namespaces = varName.split('.'),
			varname = namespaces.pop();
		for (var i=0; i < namespaces.length; i++)
			thisObject = thisObject[namespaces[i]];
		if (typeof varVal != "undefined") {
			if (typeof varVal == "string")
				thisObject[varname] = starArg(varVal);
			else
				thisObject[varname] = varVal;
			}
		else
			return thisObject[varname];
	}

	var topicCallback = function(t,f,a) {
			var thistopic = t;
			var iterations = 0;
			var docallback = setInterval(function(){
				iterations++;
					if (hmFlags.hmCurrentPage === thistopic) {
						clearInterval(docallback);
				iterations = 0;
						executeFunctionByName(f,window,a);
						//callback();
					} 
				// Quit if we don't get a confirmation after 20 iterations
				if (iterations > 20) {
						clearInterval(docallback);
						iterations = 0;
		}
	
				},3);

		};
		
		// Main listener function for parsing and executing postMessage events
		function doParse(event) {
			event = event || window.event;
			
			// Prevent access from any but the current domain when on a web server
			// Full communication is allowed on local because X-Domain attacks are not possible there
			var currentProtocol = document.location.protocol, func, callback;
			if (currentProtocol.substr(0,4) === "http" && event.origin != docDomain) return;

		/******** Object Data *********/
		// Preferred postMessaging method
		if (typeof event.data == "object") {
			if (!event.data.action) return;
			switch (event.data.action) {
				
				case "setnavlinks":
				hmWebHelp.tocNav(event.data);
				break;
				
				case "setmobnavlinks":
				hmWebHelp.mobNavLinks(event.data);
				break;
				
				case "breadcrumbs":
				hmWebHelp.tocNav({action: "bread", crumbs: event.data});
				break;

				case "loadtopic":
				hmWebHelp.tocNav({action: "set", href: event.data.href, bs: event.data.bs, ac: event.data.ac});
				if (typeof event.data.cbf == 'string') {
					topicCallback(event.data.href,event.data.cbf,event.data.cba);
				}
				break;
				
				case "loadtopicnonav":
				hmWebHelp.tocNav({action: "load", href: event.data.href, bs: event.data.bs });
				if (typeof event.data.cbf == 'string') {
					topicCallback(event.data.href,event.data.cbf,event.data.cba);
				}
				break;
				
				case "callfunction":
				executeFunctionByName(event.data.fn,window,event.data.fa);
				break;
				
				case "href":
				var hrefTarget = event.data.href.replace(/\?anchor\=/,"\#");//lastIndexOf("\?");
				tocSource.findElement(hrefTarget);
				break;
				
				case "bs":
				tocSource.findElement(event.data.bs);
				break;

				// Respond to a setvalue request from another frame
				case "setvalue":
				getSetVarByName(event.data.vn,event.data.vv);
				break;

				// Respond to a getvalue request from another frame
				case "getvalue":
				sendmessage(event.source,{action: "returnvalue", vn: event.data.vn.replace(/\./g,"_"), vv: getSetVarByName(event.data.vn), cbf: event.data.cbf});
				break;

				// Write a received value from the other frame to the returnvalues object
				case "returnvalue":
				executeFunctionByName(event.data.cbf,window,event.data.vv);
				break;

			}
			
		} 
			
		/******** String Data *********/
		// Treat as deprecated
		else if (typeof event.data == "string") 
		console.log("ERROR: xMessage call with deprecated string argument " + event.data);
			
		
			} // doParse()

		if (window.addEventListener) {
			window.addEventListener('message', doParse, false);
		} else {
			(window.attachEvent('onmessage', doParse));
			}

		// Expose object functions as methods for calling 
			return {
				sendObject: sendmessage,
				sendMessage: sendmessage
		};
		
	
		}
