/**
 * Basic global functions for use by all scripts in XpanceNET; every function
 * should be prefixed by "xpn" to prevent identifier clashing.
 *
 * @author Shawn MacDonald
 * @version 1.0
 *
 * TODO: add copyright notice!
 */

// Page preference hash.
var Preferences = {};

/****************************************************************************
 *  setPreferences
 *   Registers a preference name with a value.
 *
 *  Preconditions:
 *   - theCollection, theAction, thePreference, theValue, sendMessage != null
 *   - theCollection is a string, the collection name for the preference
 *   - theAction is a string, the action name for the preference
 *   - thePreference is a string, the label of the preference
 *   - theValue is a string
 *   - sendMessage is boolean, if true an XMLHttpRequest will be sent to
 *     save the preferences
 *
 *  Postconditions:
 *   - If a message is to be sent, then the server will save the settings,
 *     otherwise they will only be stored locally in the Preferences hash
 ****************************************************************************/
function setPreference(theCollection, theAction, thePreference, theValue, sendMessage) {
	// Maintain simple data for values.
	if (typeof theValue == "boolean") {
		theValue = theValue ? 1 : 0;
	}

	if (typeof Preferences[theCollection] == "undefined") {
		Preferences[theCollection] = {};
	}

	if (typeof Preferences[theCollection][theAction] == "undefined") {
		Preferences[theCollection][theAction] = {};
	}

	Preferences[theCollection][theAction][thePreference] = theValue;

	if (! sendMessage) { return; }

	var preferenceXMLHttp = null;
	// Send out message to set the preference server-side
	if (typeof ActiveXObject != "undefined") {
		preferenceXMLHttp = new ActiveXObject("Msxml2.XMLHTTP");
	} else if (typeof XMLHttpRequest != "undefined") {
		preferenceXMLHttp = new XMLHttpRequest();
	} else {
		alert( "WARNING! Your browser does not support background \
			requests! This feature is required for this page \
			to work properly." );
		return;
	}

	preferenceXMLHttp.onreadystatechange = function() {
		if (4 == preferenceXMLHttp.readyState && 200 == preferenceXMLHttp.status) {
			var theData = preferenceXMLHttp.responseText;
			if (/OK/.test(theData)) {
				// Everything is fine
			} else {
				/* Disabling warning for now
				alert(
					"The server could not properly save your " +
					"settings. This is not a critical error, " +
					"so you need not be worried."
				);
				*/
			}
		} else if (4 == preferenceXMLHttp.readyState) {
			/* Disabling this message for now.
			alert(
				"There was a problem communicating with the " +
				"server while saving your preferences. This " +
				"is not a critical error, so you need not " +
				"be worried."
			);
			*/
		}
	};

	var theURL = URI_BASE + "/preferences/store_xmlhttp/"
		+ "?collection=" + theCollection
		+ "&action=" + theAction
		+ "&" + thePreference + "=" + theValue;

	preferenceXMLHttp.open('POST', theURL, true);
	preferenceXMLHttp.send('');
}

/****************************************************************************
 *  lookupPreference
 *   Special function for walking through the preference hash.
 ****************************************************************************/
function lookupPreference(theCollection, theAction, thePreference) {
	var items = [ theCollection, theAction, thePreference ];

	var result  = null;
	var success = true;
	var walker  = Preferences;

	// Walk through preference hierarchy
	for (var i = 0; i < items.length; i++) {
		if (typeof walker[ items[i] ] == "undefined") {
			success = false;
			break;
		} else {
			walker = walker[ items[i] ];
		}
	}

	if (success) {
		result = walker;
	}

	return result;
}
var activeHelpNode = null;

var active = {
	help : {
		header : null,
		body   : null
	}
};

var mouseIsOverHelp = false;
var helpIsOpen = false;
var helpHideTimer = null;

xpnEventCallback( window, "onclick", function()
{
	if ( helpIsOpen && !mouseIsOverHelp )
		xpnRemoveHelp();
});

// Global collection of environment variables.
var xpnEnvironment = {
	get : function( key )
	{
		if ( typeof this[key] == "undefined" )
			return false;
		else
			return this[key];
	},
	set : function( key, value )
	{
		this[key] = value;
	}
};

/*
Object.extend = function( child, parent )
{
	for ( property in parent.prototype )
		if ( typeof child[property] == "undefined" )
			child[property] = parent.prototype[property];
	
    child.xpnSuper = parent;
	
	child.xpnSuper();
	
	return child;
}
*/

String.ucFirst = function( string )
{
    return string.charAt(0).toUpperCase() + string.substring( 1, string.length );
}

/**
 * Creates an HTMLElement and decorates it as specified;
 */
function xpnCreateElement( params )
{
	var element = document.createElement( params.tagName );

	var apply = function( source, destination )
	{
		for ( var attrib in source ) {
			if ( typeof source[attrib] == "object" ) {
				// destination[attrib] = new Object();
				apply( source[attrib], destination[attrib] );
			} else {
				destination[attrib] = source[attrib];
			}
		} // for
	}; // apply

	delete params.tagName;

	apply( params, element );

	return element;
} // xpnCreateElement

/**
 * Forces a constructor to be abstract (non-inheritable) by simply throwing
 * an exception if called.
 *
 * @throws String Quick exception message.
 */
function xpnAbstract() { throw "XPN_CREATE_ABSTRACT_OBJECT_EXCEPTION"; }

/**
 * Register a callback function to be executed when a specified event occurs.
 *
 * @param host The host object to attach the event to.
 * @param event A string specifying the event type to monitor (i.e. "onclick")
 * @param callback The function to call when the event fires.
 */
function xpnEventCallback( host, event, callback )
{
	if ( typeof host.addEventListener != "undefined" ) {    // mozilla, etc
		event = event.replace( /^on/, "" );
		host.addEventListener( event, callback, false );
	} else if ( typeof host.attachEvent != "undefined" ) {  // microsoft
		host.attachEvent( event, callback );
	} else {
		alert( "Could not register event!" );
	} // if
} // xpnEventCallback

/**
 * Creates a unique ID for an HTML element based on the text string provided.
 *
 * @param from A string containing a phrase that will be used to generate the
 *             unique ID.
 *
 * @return String representing an unique ID.
 */
function xpnCreateUniqueId( from )
{
	var candidate = from.replace( / /g, "_" ).toLowerCase();
	var candidateBase = candidate;
	
	var i = 0;
	while ( xpnElementExists( candidate ) ) {
		candidate = candidateBase + "_" + i;
		i++;
	} // while
	
	return candidate;
} // xpnCreateUniqueId

/**
 * Quick test to see if an element with the specified ID exists.
 *
 * @param id The ID of the element to look up.
 *
 * @return true if element exists, false otherwise.
 */
function xpnElementExists( id )
{
	var el = document.getElementById( id );
	return ( typeof el != "undefined" && el != null ) ? true : false;
} // xpnElementExists

/**
 * Retrieve a reference to an HTML element.
 *
 * @param id Either a string specifying the ID of the element, or a
 *           reference to the element.
 *
 * @return A reference to the HTML element.
 */
function xpnGetElement( id )
{
	if ( typeof id == "string" && xpnElementExists( id ) )
		return document.getElementById( id );
	else if ( typeof id == "object" && typeof id.id != "undefined" )
		return id;
	else
		return null;
} // xpnGetElement

function xpnInstallComponent( htmlElement, xpnComponent )
{
	htmlElement = xpnGetElement( htmlElement );

	htmlElement.xpnComponent = xpnComponent;
	xpnComponent.htmlElement = htmlElement;

	var methods = [
		{
			name : "onClick",
			body : function() { xpnComponent.onClick(); }
		},
		{
			name : "onMouseOver",
			body : function() { xpnComponent.onMouseOver(); }
		}
	];

	for ( var i = 0; i < methods.length; i++ )
		if ( typeof xpnComponent[methods[i].name] == "function" )
			xpnEventCallback( htmlElement, methods[i].name.toLowerCase(), methods[i].body );

	if ( typeof xpnComponent.onInstall == "function" )
		xpnComponent.onInstall();
} // xpnInstallComponent

function xpnAssert( condition, message )
{
	if ( !condition )
		alert( message );
}

function xpnPosition( element )
{
	var curleft = 0;
	var curtop = 0;
	var obj = xpnGetElement( element );

	// Walk up the DOM tree to our parent, their parent, etc. in order
	// to accumulate the proper offset.
	if ( obj.offsetParent ) {
		while ( obj.offsetParent ) {
			curleft += obj.offsetLeft;
			curtop += obj.offsetTop;

			obj = obj.offsetParent;
		} // while
	} else if ( obj.x ) {
		curleft += obj.x;
		curtop += obj.y;
	} // if-else

	return { x: curleft, y: curtop };
}

function xpnIsOver( position, element )
{
	var elementPosition = xpnPosition( element );

	if ( position.x > elementPosition.x &&
		 position.x < elementPosition.x + element.offsetWidth &&
		 position.y > elementPosition.y &&
		 position.y < elementPosition.y + element.offsetHeight )
		return true;
	else
		return false;
}

function xpnGetHelpDefinition ( elemId )
{

    var xpnHelpDefinitions = {
            ads_to_proof: "Those Ads available for annotation and approval.",
            ads_awaiting_internal_approval: "Those Ads available to Newspaper Individuals (sales, assistants, proof readers) to annotate and approve before releasing to Advertisers.", 
            ads_awaiting_approval: "Those Ads available to annotate and approve.",
            ads_returned_from_advertiser: "Those Ads returned from Individuals (Newspaper and/or Advertisers) with annotations or changes.",
            ad_schedule: "Those Ads booked for a selected insertion date. Shows where Ads are in the Newspaper Workflow.",
            spec_ads: "A preliminary layout showing the position of illustrations and text of a proposed ad.",
            spec_ads_built_for_you: "A preliminary layout showing the position of illustrations and text of a proposed ad.",
            ads_to_upload: "Those Ads that have a reservation number (Ad Number) that can be submitted to the Newspaper.",
            update_your_profile: "Allows changes to your profile, including your contact information, as well as your XpanceNET login information.",
            search: "Available fields or options to find information about and Ad or a group of Ads.",
            faq: "Frequently Asked Questions are answered in this area.",
            final_check_list: "A step-by-step confirmation that the file(s) you are submitting meet the minimum requirements for quality reproduction.",
            file_preparation: "A step-by-step process that shows how to prepare files you are submitting meet the minimum requirements.",
            deadlines: "A date and time that materials are to be submitted or a time that materials are to be approved by.",
            demographics: "Information provide by the Newspaper to give information about their readership.",
            rate_card: "Information about cost and distribution of Advertisements with the Newspaper.",
            credit_application: "Information to be provided to the Accounting Department for establishing credit.",
            downloadable_files: "Available Files or Templates to help in the creation and/or generation of Ads."
    }

    if ( xpnHelpDefinitions[elemId] != null ) {
        return xpnHelpDefinitions[elemId];
    } else {
        return "No help topic is available for this function.";
    }
}

function xpnCreateHelp( elemId )
{
	xpnRemoveHelp();

	/*
	if ( active.help.header != null || active.help.body != null ) {
		document.body.removeChild( active.help.header );
		document.body.removeChild( active.help.body );
	} // if
	 */

/*
    if ( activeHelpNode != null ) {
        document.body.removeChild ( activeHelpNode );
    }

    var el = xpnCreateElement({
                tagName: "div",
                className: "helpItem",
                style: {
                    position: "absolute",
                    left: xpnPosition(elemId).x + 20 + "px",
                    top: xpnPosition(elemId).y + "px"
                },
                id: elemId + "_help"
    });
 */

	/*
	var helpContainer = xpnCreateElement({
		tagName : "div",
		className : "helpContainer",
		style : {
			position : "absolute",
			left : xpnPosition( elemId ).x + "px",
			top  : xpnPosition( elemId ).y + "px"
		},
		id : elemId + "_helpContainer"
	});
	*/

	var helpHeader = xpnCreateElement({
		tagName : "div",
		className : "helpHeader",
		style : {
			position : "absolute",
			left : xpnPosition( elemId ).x + "px",
			top  : xpnPosition( elemId ).y + "px",
			display : "block"
		},
		id : elemId + "_helpHeader"
	});

	helpHeader.innerHTML = "<span>&gt;&gt;&gt;</span>";

	var helpBody = xpnCreateElement({
		tagName : "div",
		className : "helpBody",
		style : {
			position : "absolute",
			left : xpnPosition( elemId ).x + 20 + "px",
			top  : xpnPosition( elemId ).y + 15 + "px"
//			margin : "0px 0px 0px 20px"
		},
		id : elemId + "_helpBody"
	});

    var thisTitle = elemId.split("_");
    thisTitle.each( function (s, i) {
        thisTitle[i] = String.ucFirst(s);
    });
    
    var codeFragment = "<p class=\"helpBodyTitle\">" + thisTitle.join(" ") + "</p>";
	codeFragment    += "<p>" + xpnGetHelpDefinition( elemId ) + "</p>";

	helpBody.innerHTML = codeFragment;

//	helpContainer.appendChild( helpHeader );
//	helpContainer.appendChild( helpBody );

//	document.body.appendChild( helpContainer );
//	activeHelpNode = helpContainer;

	document.body.appendChild( helpHeader );
	document.body.appendChild( helpBody );
	active.help.header = helpHeader;
	active.help.body = helpBody;

	helpIsOpen = true;
	mouseIsOverHelp = true;

	var mouseOver = function()
	{
		mouseIsOverHelp = true;

		if ( helpHideTimer != null ) {
			window.clearTimeout( helpHideTimer );
			helpHideTimer = null;
		} // if
	};

	var mouseOut = function()
	{
		mouseIsOverHelp = false;

		if ( helpHideTimer == null )
			helpHideTimer = window.setTimeout( xpnRemoveHelp, 1000 );
	};

	xpnEventCallback( helpHeader, "onmouseover", mouseOver );
	xpnEventCallback( helpHeader, "onmouseout", mouseOut );
	xpnEventCallback( helpBody, "onmouseover", mouseOver );
	xpnEventCallback( helpBody, "onmouseout", mouseOut );

	/*
    var tableElem = xpnCreateElement({ tagName: "table", className: "helpTable", cellPadding: "0", cellSpacing: "0"});
    var tableBody = xpnCreateElement({ tagName: "tbody" });
    var tableHeader = xpnCreateElement({ tagName: "tr", className: "helpTableHeader"});
    var tableMain = xpnCreateElement({ tagName: "tr", className: "helpTableMain"});
    var tableHeaderCell1 = xpnCreateElement({ tagName: "td", className: "helpTableCellLeft"});
    var tableHeaderCell2 = xpnCreateElement({ tagName: "td", className: "helpTableCellMiddle"});
    var tableHeaderCell3 = xpnCreateElement({ tagName: "td", className: "helpTableCellRight"});
    var helpCloseAnchor = xpnCreateElement({ tagName: "a", href: "javascript:xpnRemoveHelp();" });

    tableHeaderCell2.appendChild(
        document.createTextNode( String.ucFirst( elemId.replace( /_/g, " " ) ) )
    );

    var tableMainCell = xpnCreateElement({ tagName: "td", className: "helpTableCellMain", colSpan: "3" });
    tableMainCell.appendChild(
        document.createTextNode( xpnGetHelpDefinition( elemId ) )
    );
    
    tableElem.appendChild(tableBody);
    tableBody.appendChild(tableHeader);
    tableBody.appendChild(tableMain);

    tableHeaderCell1.appendChild( xpnCreateElement({ tagName: "img", src: "/images/helpTop1.gif", alt: "Help Top Image 1" }) );
    helpCloseAnchor.appendChild( xpnCreateElement({ tagName: "img", src: "/images/helpTop2.gif", alt: "Help Top Image 2" }) );

    tableHeaderCell3.appendChild( helpCloseAnchor );
    tableHeaderCell3.appendChild( xpnCreateElement({ tagName: "img", src: "/images/helpTop3.gif", alt: "Help Top Image 3" }) );
    
    tableHeader.appendChild(tableHeaderCell1);
    tableHeader.appendChild(tableHeaderCell2);
    tableHeader.appendChild(tableHeaderCell3);

    tableMain.appendChild(tableMainCell);

    el.appendChild(tableElem);
    
    document.body.appendChild(el);
    activeHelpNode = el;
    */
} // xpnCreateHelp()

function xpnRemoveHelp()
{
	if ( active.help.header != null && active.help.body != null ) {
		document.body.removeChild( active.help.header );
		document.body.removeChild( active.help.body );

		active.help.header = null;
		active.help.body = null;

		helpIsOpen = false;
		window.clearTimeout( helpHideTimer );
		helpHideTimer = null;
	} // if
} // xpnRemoveHelp()

function validateQuickSearch( form )
{
	if ( /^ *$/.test( form.ad_number.value ) )
		return false;

	return true;
} // validateQuickSearch()
