// Version AdvanceFeature 1.0

cy={};

cy.documentdomain=window.document.domain;
cy.locationpathname=window.location.pathname;
cy.documentreferrer=window.document.referrer;

cy_defaults={};
cy_defaults.PageName="";
cy_defaults.FunnelLevel="0";
cy_defaults.Section="";
cy_defaults.UserId="";
cy_defaults.Product="";
cy_defaults.Quantity=0;
cy_defaults.Value=0.0;
cy_defaults.ReturnToLink="";
cy_defaults.Custom1="";
cy_defaults.Custom2="";
cy_defaults.Custom3="";
cy_defaults.Custom4="";

cy.WAIT_DURATION=100;
cy.UPPER_LIMIT_WAIT_DURATION=2000;

cy.CUSTOMERCODE='5114714077';

var _cyImages={};

_cyGetUniqueId = (function() {
	var id=0; 
	return function(){ return "_" + id++; };
})();

var cySessionIdDetails;

function cyResetCYToDefaults()
{
	cy.documentdomain=window.document.domain;
	cy.locationpathname=window.location.pathname;
	cy.documentreferrer=window.document.referrer;

	cy_defaults.PageName="";
	cy_defaults.FunnelLevel="0";
	cy_defaults.Section="";
	cy_defaults.UserId="";
	cy_defaults.Product="";
	cy_defaults.Quantity=0;
	cy_defaults.Value=0.0;
	cy_defaults.ReturnToLink="";
	cy_defaults.Custom1="";
	cy_defaults.Custom2="";
	cy_defaults.Custom3="";
	cy_defaults.Custom4="";
}

var _cyBrowser = {
isMicrosoft: navigator.appName.indexOf("Microsoft") != -1
};

// On all versions of Internet Explorer, setting the document.location to load a new page results in the document.referrer on the
// new page not being set. This function provides a workaround to that problem.
function _cyNavigate(url)
{
	if (_cyBrowser.isMicrosoft === true)
	{
		var referLink = document.createElement('a');
		referLink.href = url;
		document.body.appendChild(referLink);
		referLink.click();
	}
	else
	{
		window.location=url;
	}
}

function _cyGetCookie(c_name, suffix_allowed)
{
	// Search case-insensitive
	if (document.cookie.length>0)
	{
		if (suffix_allowed === false)
		{
			// Look for a complete word match
			c_start = document.cookie.toLowerCase().indexOf(c_name.toLowerCase() + "=");

			if (c_start != -1)
			{
				c_start = c_start + c_name.length + 1;
				c_end = document.cookie.indexOf(";", c_start);

				if (c_end == -1)
				{
					c_end = document.cookie.length;
				}

				return decodeURIComponent(document.cookie.substring(c_start, c_end));
			}
		}
		else
		{
			// Look for a partial word match
			regexp = c_name.toLowerCase() + "(.*)=";

			c_start = document.cookie.toLowerCase().search(regexp);

			if (c_start != -1)
			{
				// create new string with our search criteria at the beginning
				s1 = document.cookie.slice(c_start);

				// Search from the beginning of this new string for "="
				c_start = s1.indexOf("=") +1;

				if (c_start != -1)	// overkill
				{
					c_end = s1.indexOf(";");

					if (c_end == -1)
					{
						c_end = s1.length;
					}

					return decodeURIComponent(s1.substring(c_start, c_end));
				}
			}
		}

	}

	return "";
}

function _cyConvertCYPropertyNamesToUpperCase()
{
	var propertyValue = "";
	for (var propertyName in cy)
	{
		propertyValue = cy[propertyName];
		delete cy[propertyName];
		cy[propertyName.toUpperCase()] = propertyValue;
	}
	return "";
}

function _cyGetWaitDuration()
{
	return cy.WAIT_DURATION;
}

function cySetWaitDuration(millis)
{
	cy.WAIT_DURATION = millis;
}

function _cyGetUpperLimitWaitDuration()
{
	return cy.UPPER_LIMIT_WAIT_DURATION;
}

function cySetUpperLimitWaitDuration(millis)
{
	cy.UPPER_LIMIT_WAIT_DURATION = millis;
}

function _cyOnImageLoad(elementId)
{
	_cyImages[elementId].loadingComplete = true;
}

function _cyGetLoaded(elementId)
{
	return _cyImages[elementId].loadingComplete;
}

function _cyOnImageAbort(elementId)
{
	_cyImages[elementId].loadingComplete = false;
}

// The doCreateHandlers parameter is an optional boolean value that, if true, means that an onLoad and onAbort handler should be
// added to the created image. In general, a value of true will be passed when an actual image is being requested and we are to
// wait on the image being loaded before carrying out the action in question.
function _cyCreateImage(doCreateHandlers)
{
	// Note - images are not removed from the document when they are no longer required. There will be only one image
	// created in most circumstances, and never enough in a realistic scenario to cause a problem.
	var cy_image = document.createElement("img");

	cy_image.id = _cyGetUniqueId();

	var createHandlers = false;
	if (doCreateHandlers && typeof(doCreateHandlers) == "boolean")
	{
		createHandlers = doCreateHandlers;
	}
	
	if (createHandlers === true)
	{
		cy_image.onload = function(){_cyOnImageLoad(cy_image.id);};
		cy_image.onabort = function(){_cyOnImageAbort(cy_image.id);};
	}
	
	cy_image.width = 1;
	cy_image.height = 1;
	cy_image.border = 0;

	document.getElementsByTagName("body")[0].appendChild(cy_image);

	return cy_image;
}

function _cySetCYProperties(/* optional */ ocy, /* optional */ cysetter)
{
	if (ocy)
	{
		for (var p in ocy)
		{
			cy[p] = ocy[p];
		}
		_cyConvertCYPropertyNamesToUpperCase();
	}
	
	if (cysetter && typeof(cysetter) == "function")
	{
		cysetter();
		_cyConvertCYPropertyNamesToUpperCase();
	}
}

function _cyTimeoutSubmit(thisForm, elementId, resetTimeout)
{
	if (resetTimeout === true && _cyIsImageLoadedOrTimedOut(elementId) === false)
	{
		// If resetTimeout = true, then we have to wait for the image to be returned from our server before
		// submitting the form. So if we haven't yet loaded the image from our server, reset the timeout function
		// so that we come back in here to check in a little while.
		
		setTimeout(function(){_cyTimeoutSubmit(thisForm, elementId, true);}, _cyGetWaitDuration());
		_cyImages[elementId].totalWaitTime += _cyGetWaitDuration();
	}
	else
	{
		// If resetTimeout is false, then we are not required to wait for the image to be returned from our server (in
		// fact, in that case, no image is actually returned). So in this case, submit the form.
		// Also, it may be that we are required to wait for the image to be loaded from our server, and that image has
		// now loaded. In this case, submit the form.
		
		thisForm.submit();
	}
}

// thisForm - the form to be submitted
// wait - boolean. If true, send our request, return actual image, wait for image to come back, wait in increments up to max duration
//                 if false, send our request (do not return an image), wait for 100ms (or whatever is configured), submit the form
function _cyOnSubmit(thisForm, wait)
{
	try
	{
		var cy_image = _cyCreateImage(wait);

		if (wait === true)
		{
			// Set a property of the _cyImages object. The property name is cy_image.id. The value of the property is an
			// object. That object has two properties, totalWaitTime and loadingComplete. These are given initial values
			// of 0 and false respectively.
			_cyImages[cy_image.id] = {totalWaitTime:0, loadingComplete:false};
		
			cy_image.src = _cyGetElementSrc("seewhy.gif");
		}
		else
		{
			cy_image.src = _cyGetElementSrc("seewhy.nogif");
		}
	
		setTimeout(function(){_cyTimeoutSubmit(thisForm, cy_image.id, wait);}, _cyGetWaitDuration());		
	}
	catch(err){}
	
	return false;
}

function cyOnSubmit(thisForm, /* optional */ doWait, /* optional */ ocy, /* optional */ cysetter)
{
	try
	{
		_cySetCYProperties(ocy, cysetter);

		waitOnImage = false;
		if (doWait && typeof(doWait) == "boolean")
		{
			waitOnImage = doWait;
		}
	}
	catch(err){}
	
	return _cyOnSubmit(thisForm, waitOnImage);
}

function _cyIsImageLoadedOrTimedOut(elementId)
{
	//TODO - I am very tempted to remove the check on the image.complete property as I have seen chatter that it is unreliable.
	//       Anyway, the cyGetLoaded check should be enough.
	
	if ((_cyImages[elementId].totalWaitTime > _cyGetUpperLimitWaitDuration()) ||
	    (document.getElementById(elementId).complete === true && _cyGetLoaded(elementId) === true))
	{
		return true;
	}

	return false;
}

// This function should not be used with impunity
function _cyWait(millis)
{
	var start = new Date().getTime();
	while(new Date().getTime() < (start+millis)) {
	}
}

function cyOnPageLoad(/* optional */ isBlocking, /* optional */ doDelay, /* optional */ ocy, /* optional */ cysetter)
{
	var block = false;
	if (isBlocking && typeof(isBlocking) == "boolean")
	{
		block = isBlocking;
	}

	try
	{
		_cySetCYProperties(ocy, cysetter);
		
		if (block === true)
		{
			src = _cyGetElementSrc("seewhy.js");

			// Doing a document.write requires that it be done before the page has finished loading (otherwise we will completely
			// overwrite the page with the output of the document.write call).

			if (document.readyState)
			{
				if (document.readyState != "complete")
				{
					document.write('<script type="text/javascript" src="',src,'"><\/script>');
				}
			}
			else
			{
				document.write('<script type="text/javascript" src="',src,'"><\/script>');
			}
		}
		else
		{
			var cy_image = _cyCreateImage(false);

			cy_image.src = _cyGetElementSrc("seewhy.nogif");
		}

		var delay = false;
		if (doDelay && typeof(doDelay) == "boolean")
		{
			delay = doDelay;
		}

		if (delay === true)
		{
			_cyWait(_cyGetWaitDuration());
		}
	}
	catch(err){}
}

function _cyTimeoutLink(anchor, elementId, resetTimeout)
{
	if (resetTimeout === true && _cyIsImageLoadedOrTimedOut(elementId) === false)
	{
		setTimeout(function(){_cyTimeoutLink(anchor, elementId, true);}, _cyGetWaitDuration());
		_cyImages[elementId].totalWaitTime += _cyGetWaitDuration();
	}
	else
	{
		if (anchor && anchor.href)
		{
			_cyNavigate(anchor.href);
		}
	}
}

function cyOnLink(anchor, /* optional */doWait, /* optional */ ocy, /* optional */ cysetter)
{
	wait = false;
	if (doWait && typeof(doWait) == "boolean")
	{
		wait = doWait;
	}
	
	try
	{
		_cySetCYProperties(ocy, cysetter);
		
		var cy_image = _cyCreateImage(wait);

		if (wait)
		{
			_cyImages[cy_image.id] = {totalWaitTime:0, loadingComplete:false};
			cy_image.src = _cyGetElementSrc("seewhy.gif");
		}
		else
		{
			cy_image.src = _cyGetElementSrc("seewhy.nogif");
		}
		
		setTimeout(function(){_cyTimeoutLink(anchor, cy_image.id, wait);}, _cyGetWaitDuration());
	}
	catch(err){}
	
	// Returning false stops the browser from following the link as a consequence of the user clicking the link. The link will
	// be followed when the timeout code is invoked.
	return false;
}

function cyOnClick(/* optional */ doDelay, /* optional */ ocy, /* optional */ cysetter)
{
	try
	{
		_cySetCYProperties(ocy, cysetter);
		
		var cy_image = _cyCreateImage(false);

		cy_image.src = _cyGetElementSrc("seewhy.nogif");

		var delay = false;
		if (doDelay && typeof(doDelay) == "boolean")
		{
			delay = doDelay;
		}
		
		if (delay)
		{
			_cyWait(_cyGetWaitDuration());
		}
	}
	catch(err){}
}

function cyOnChange(/* optional */ doDelay, /* optional */ ocy, /* optional */ cysetter)
{
	try
	{
		_cySetCYProperties(ocy, cysetter);

		var cy_image = _cyCreateImage(false);

		cy_image.src = _cyGetElementSrc("seewhy.nogif");

		var delay = false;
		if (doDelay && typeof(doDelay) == "boolean")
		{
			delay = doDelay;
		}
		
		if (delay)
		{
			_cyWait(_cyGetWaitDuration());
		}
	}
	catch(err){}
}

function _cyGetElementSrc(res)
{
	var resource="seewhy.gif";
	if (res)
	{
		resource = res;
	}

	_cyConvertCYPropertyNamesToUpperCase();
	var protocol;
	var port;
	var swd='abandonment.saas.seewhy.com';
	var path='/abandonment2/WE/' +resource;
	var ssl = window.location.protocol.toLowerCase().indexOf('https') >= 0;
	if (ssl)
	{
		protocol='https';
		port=8443;
	}
	else
	{
		protocol='http';
		port=8080;
	}
	var swi = protocol+'://'+swd+':'+port+path;
	var rn = Math.random();

	var sessionId = _cyGetSessionId();

	var queryString="?Event=WebEvent"+
			"&CustomerCode=" +cy.CUSTOMERCODE+
			"&Server=" +cy.DOCUMENTDOMAIN+
			"&DefaultPageName=" +encodeURIComponent(cy.LOCATIONPATHNAME)+
			"&Referrer=" +encodeURIComponent(cy.DOCUMENTREFERRER)+
			"&SessionID=" +encodeURIComponent(sessionId)+
			"&FunnelLevel=" +encodeURIComponent((cy.FUNNELLEVEL==undefined) ? cy_defaults.FunnelLevel : cy.FUNNELLEVEL)+
			"&Section=" +encodeURIComponent((cy.SECTION==undefined) ? cy_defaults.Section : cy.SECTION)+
			"&UserID=" +encodeURIComponent((cy.USERID==undefined) ? cy_defaults.UserId : cy.USERID)+
			"&Product=" +encodeURIComponent((cy.PRODUCT==undefined) ? cy_defaults.Product : cy.PRODUCT)+
			"&Quantity=" +encodeURIComponent((cy.QUANTITY==undefined) ? cy_defaults.Quantity : cy.QUANTITY)+
			"&Value=" +encodeURIComponent((cy.VALUE==undefined) ? cy_defaults.Value : cy.VALUE)+
			"&PageName=" +encodeURIComponent((cy.PAGENAME==undefined) ? cy_defaults.PageName : cy.PAGENAME)+
			"&ReturnToLink=" +encodeURIComponent((cy.RETURNTOLINK==undefined) ? cy_defaults.ReturnToLink : cy.RETURNTOLINK)+
			"&Custom1=" +encodeURIComponent((cy.CUSTOM1==undefined) ? cy_defaults.Custom1 : cy.CUSTOM1)+
			"&Custom2=" +encodeURIComponent((cy.CUSTOM2==undefined) ? cy_defaults.Custom2 : cy.CUSTOM2)+
			"&Custom3=" +encodeURIComponent((cy.CUSTOM3==undefined) ? cy_defaults.Custom3 : cy.CUSTOM3)+
			"&Custom4=" +encodeURIComponent((cy.CUSTOM4==undefined) ? cy_defaults.Custom4 : cy.CUSTOM4);

	var src = swi+"/"+rn+queryString;
	
	return src;
}

function cySetSessionDetails(sessionIdName, /* optional */ suffixAllowed)
{
	isSuffixAllowed = false;
	if (suffixAllowed && typeof(suffixAllowed) == "boolean")
	{
		isSuffixAllowed = suffixAllowed;
	}
	cySessionIdDetails = {sessionKeyName:sessionIdName, sessionKeySuffixAllowed:isSuffixAllowed};
}

function _cyGetSessionId()
{
	var sessionId;

	if (cy.SESSIONID != null)
	{
		sessionId = cy.SESSIONID;
	}
	else
	{
		if (cySessionIdDetails && cySessionIdDetails.sessionKeyName)
		{
			sessionId = _cyGetCookie(cySessionIdDetails.sessionKeyName, cySessionIdDetails.sessionKeySuffixAllowed);
		}
		else
		{
			var sessionId = _cyGetCookie("JSESSIONID", false);
			if (sessionId == "")
			{
				sessionId = _cyGetCookie("ASPSESSIONID", true);
			}
			if (sessionId == "")
			{
				sessionId = _cyGetCookie("PHPSESSID", false);
			}
			if (sessionId == "")
			{
				sessionId = _cyGetCookie("ASP.NET_SessionId", false);
			}
			if (sessionId == "")
			{
				sessionId = _cyGetCookie("sid", false);
			}
			if (sessionId == "")
			{
				sessionId = _cyGetCookie("SESS", true);
			}
		}
	}
	
	return sessionId;
}

// Backwards compatibility. The cy_getImageSrc function is used for Page Load events. Page Load events do not require an image event
// handler, and therefore there is no need to add one dynamically here.
function cy_getImageSrc()
{
	// Non-blocking, non-waiting call used in the backwards compatibility version
	cyOnPageLoad(false, false);
}

