/**
 * Base class for exchange of data between GSI and Jive.
 * All properties and methods will be static.
 * @constructor
 */
var JiveDataExchange = function() {};


/** The root URL for loading data */
JiveDataExchange.proxyURL = "/gsi/";

/** URLs for Loading Data */
JiveDataExchange.dataLoaders = {
	corporatePublicPage: {
		url: "corporate-public-page.jsa",
		useRootURL: true
	},
	cmmList: {
		url: "view-communityMarketingManagers.jsa",
		useRootURL: true
	},
	calendar: {
		url: "calendar-data.jsa",
		useRootURL: true
	},
	announcementCalendar: {
		url: "calendar-data.jsa",
		useRootURL: true
	},
	blogPosts: {
		url: "blog-data.jsa",
		useRootURL: true
	},
	messageBoard: {
		url: "view-message-board.jsa",
		useRootURL: true
	},
	thread: {
		url: "view-thread.jsa",
		useRootURL: true
	},
	profileData: {
		url: "session-profile.jsa",
		useRootURL: true,
		callBackDelay: 150
	},
	applicationData: {
		url: "application-data.jsa",
		useRootURL: true,
		callBackDelay: 150
	},
	eventLocations: {
		url: "eventLocation-data.jsa",
		useRootURL: true
	},
	userSpace: {
		url: "set-current-space.jsa",
		useRootURL: true
	},
	userSport: {
		url: "set-current-sport.jsa",
		useRootURL: true
	},
	logOut: {
		url: "logout.jsa",
		useRootURL: true
	},
	locateCMM: {
		url: "locate-cmm.jsa",
		useRootURL: true
	},
	publicPageCalendar: {
		url: "public-page-calendar-data.jsa",
		useRootURL: true
	},
	publicPageBlog: {
		url: "public-page-blog-data.jsa",
		useRootURL: true
	},
	kbFolderContents: {
		url: "folder-data.jsa",
		useRootURL: true
	},
	retreiveInvitation: {
		url: "retrieve-invitation.jsa",
		useRootURL:true
	},
	organizerLeagues: {
		url: "view-leagues-for-organizer.jsa",
		useRootURL:true
	},
	organizerTeams: {
		url: "view-league.jsa",
		useRootURL:true
	},
	viewLeagueSchedule: {
		url: "view-league-schedule.jsa",
		useRootURL:true
	},
	viewTeamSchedule: {
		url: "view-league-team-schedule.jsa",
		useRootURL:true
	},
	teamCreateContext: {
		url: "team-creation-context.jsa",
		useRootURL:true
	},
	viewTeam: {
		url: "view-team.jsa",
		useRootURL:true
	},
	acceptInvitation: {
		url: "accept-invitation.jsa",
		useRootURL:true
	},
	declineInvitation: {
		url: "reject-invitation.jsa",
		useRootURL:true
	},
	viewTeamScheduleCoach: {
		url: "view-team-schedule.jsa",
		useRootURL:true
	},
	viewTeamsForCoach: {
		url: "view-teams-for-coach.jsa",
		useRootURL:true
	},
	viewGame: {
		url: "view-game.jsa",
		useRootURL:true
	},
	viewOpponents: {
		url: "view-opponents.jsa",
		useRootURL:true
	},
	endSeason: {
		url: "end-season.jsa",
		useRootURL:true
	},
	extendSeason: {
		url: "extend-season.jsa",
		useRootURL:true
	},
	newSeasonAlert: {
		url: "send-archive-notification.jsa",
		useRootURL:true
	},
	playerMessages: {
		url: "view-event-announcements.jsa",
		useRootURL:true
	},
	extendedSeason: {
		url: "ack-season-extended.jsa",
		useRootURL:true
	},
	emailUpdates: {
		url: "http://www.dickssportinggoods.com/include/entry.html",
		useRootURL:false,
		useIFrame:true
	},
	salesReports: {
		url: "sales-lead-report.jsa",
		useRootURL:true
	}
};

/** URLs for Form Actions */
JiveDataExchange.formActions = {
	"emailUpdatesForm-form":
	{
		"emailUpdates": {
			url: "http://www.dickssportinggoods.com/emailHandler/index.jsp",
			useRootURL: false,
			useIFrame: true,
			external: true
		}
	},
	"createCMM-form":
	{
		"update": {
			url: "edit-cmm.jsa",
			useRootURL: true
		},
		"insert": {
			url: "edit-cmm.jsa",
			useRootURL: true
		}
	},

	"corporateAdmin-publicPageForm-form":
	{
		"edit": {
			url: "edit-corp-public-page.jsa",
			useRootURL: true
		},
		"setup": {
			url: "edit-corp-public-page.jsa",
			useRootURL: true
		}
	},
	"eventForm-form":
	{
		"insert": {
			url: "insert-event.jsa",
			useRootURL: true
		},
		"update": {
			url: "update-event.jsa",
			useRootURL: true
		},
		"delete": {
			url: "delete-event.jsa",
			useRootURL: true
		}
	},

	"sendAnInvitation-form":
	{
		"send": {
			url: "send-invitation.jsa",
			useRootURL: true
		}
	},

	"createProfile-form":
	{
		"invited": {
			url: "create-user-profile-from-invite.jsa",
			useRootURL: true
		},
		"insert": {
			url: "create-user-profile.jsa",
			useRootURL: true
		},
		"update": {
			url: "update-user-profile.jsa",
			useRootURL: true
		}
	},

	"create-league-form":
	{
		"send": {
			url: "create-league.jsa",
			useRootURL: true,
			useIFrame: true
		},
		"update": {
			url: "update-league.jsa",
			useRootURL:true
		},
		"copy": {
			url: "archive-league!copyOrganization.jsa",
			useRootURL:true
		},
		"new": {
			url: "archive-league!newOrganization.jsa",
			useRootURL:true
		}

	},
	"team-league-form":
	{
		"add":	{
			url: "add-team-to-league.jsa",
			useRootURL:true
		},
		"edit": {
			url: "update-team-within-league.jsa",
			useRootURL:true
		},
		"deleteCoach": {
			url: "delete-coach.jsa",
			useRootURL:true
		},
		"deactivate": {
			url: "deactivate-team.jsa",
			useRootURL:true
		}
	},

	"team-league-activate-form":
	{
		"activate": {
			url: "activate-team.jsa",
			useRootURL:true
		},
		"deactivate": {
			url: "deactivate-team.jsa",
			useRootURL:true
		}
	},

	"blogPostForm-form":
	{
		"insert": {
			url: "insert-blogPost.jsa",
			useRootURL: true,
			useIFrame: true
		},
		"update": {
			url: "update-blogPost.jsa",
			useRootURL: true,
			useIFrame: true
		},
		"delete": {
			url: "delete-blogPost.jsa",
			useRootURL: true
		},
		"deleteImage": {
			url: "delete-blogPost.jsa",
			useRootURL: true
		}
	},

	"signIn-form":
	{
		"login": {
			url: "index!default.jsa",
			useRootURL: true
		}
	},

	"publicPage-form":
	{
		"edit": {
			url: "update-cmm-profile.jsa",
			useRootURL: true,
			useIFrame: true
		},
		"setup": {
			url: "setup-cmm-profile.jsa",
			useRootURL: true,
			useIFrame: true
		}
	},

	"kbFolderForm-form":
	{
		"insert": {
			url: "create-folder.jsa",
			useRootURL: true
		},
		"update": {
			url: "update-folder.jsa",
			useRootURL: true
		},
		"delete": {
			url: "delete-folder.jsa",
			useRootURL: true
	}
	},

	"kbFileForm-form":
	{
		"insert": {
			url: "upload-document.jsa",
			useRootURL: true,
			useIFrame: true
		},
		"update": {
			url: "update-document.jsa",
			useRootURL: true,
			useIFrame: true
		},
		"delete": {
			url: "delete-document.jsa",
			useRootURL: true
		}
	},

	"forgotPassword-form":
	{
		"emailToken": {
			url: "email-password-token.jsa",
			useRootURL: true
}
	},

	"resetPassword-form":
	{
		"reset": {
			url: "reset-password.jsa",
			useRootURL: true
		}
	},

	"messageForm-form":
	{
		"insert": {
			url: "create-thread.jsa",
			useRootURL: true
		},
		"update": {
			url: "edit-thread.jsa",
			useRootURL: true
		},
		"delete": {
			url: "delete-thread.jsa",
			useRootURL: true
		}
	},

	"information-request-form":
	{
		"request":{
			url: "request-information.jsa",
			useRootURL: true
		}

	},

	"messageThreadForm-form":
	{
		"update": {
			url: "create-reply.jsa",
			useRootURL: true
		},

		"delete": {
			url: "delete-reply.jsa",
			useRootURL: true
		}
	},

	"gameForm-form":
	{
		"insert": {
			url: "create-league-game.jsa",
			useRootURL:true
		},
		"update": {
			url: "update-league-game.jsa",
			useRootURL:true
		},
		"delete": {
			url: "delete-league-game.jsa",
			useRootURL:true
		},
		"insertTeam":
		{
			url: "create-team-game.jsa",
			useRootURL:true
		},
		"updateTeam": {
			url: "update-team-game.jsa",
			useRootURL:true
		},
		"insertTeamOrphan":
		{
			url: "create-orphan-team-game.jsa",
			useRootURL:true
		},
		"updateTeamOrphan": {
			url: "update-orphan-team-game.jsa",
			useRootURL:true
		}

	},
	"players-form":
	{
		"insert": {
			url: "add-player.jsa",
			useRootURL:true
		},
		"update": {
			url: "update-player.jsa",
			useRootURL:true
		},
		"delete": {
			url: "delete-player.jsa",
			useRootURL:true
		}
	},
	"populate-team":
	{
		"send": {
			url: "populate-team.jsa",
			useRootURL:true,
			useIFrame:true
		},
		"createTeam": {
			url: "create-team.jsa",
			useRootURL:true,
			useIFrame:true
		},
		"updateNoLeague": {
			url: "update-team.jsa",
			useRootURL:true,
			useIFrame:true
		},
		"updateWithLeague": {
			url: "update-team.jsa",
			useRootURL:true,
			useIFrame:true
		},
		"copy": {
			url: "archive-team!copyOrganization.jsa",
			useRootURL:true
		},
		"archiveNew": {
			url: "archive-team!newOrganization.jsa",
			useRootURL:true
		}
	}
}
/** Data store */
JiveDataExchange.dataStore = {};

/**
 * Custom Class to create a data-form mapping
 * @param {Function} submitFunction		The function used to submit the form
 * @constructor
 */
JiveDataExchange.formMap = function( submitFunction )
{
	this.submitFunction = submitFunction || undefined;

/** An array to hold the mappings between data attributes and formItemIds @type Array */
	this.mappings = []

/**
 * Add a mapping
 * @param {String} label						Human-readable label
 * @param {String} attribute 				The data attribute to map
 * @param {String} formItemId 			The formItemId to map
 * @param {Function} [populateMethod]		Optional. A method to use for populating the data into its form element
 * @param {Function} [serializeMethod]	Optional. A method to use for serializing the data
 * @return the class instance
 */
	this.add = function( label, attribute, formItemId, populateMethod, serializeMethod )
	{
		var el = $(formItemId);
		if( el !== null  && this.submitFunction !== undefined && el.type && ( el.type == "text" || el.type == "password" ))
		{
			Element.observe( el, "keypress", function( evt ) {
				if( evt.keyCode == Event.KEY_RETURN )
				{
					this.submitFunction();
				}
			}.bindAsEventListener(this) );
		}
		var mapping = { label: label, attribute: attribute, formItemId: formItemId };
		if( typeof populateMethod == 'function' ) mapping.populateMethod = populateMethod;
		if( populateMethod && populateMethod == null ) mapping.populateMethod = function() {};
		if( typeof serializeMethod == 'function' ) mapping.serializeMethod = serializeMethod;
		if( serializeMethod && serializeMethod == null ) mapping.serializeMethod = function( data ){ return data };

		this.mappings.push( mapping );
		return this;
	}

/**
 * Find a form mapping
 * @param {String} attribute		The attribute to search for
 * @param {Object} value				The value to match
 * @return The matching form mapping or undefined
 * @type Object
 */
	this.lookupFormMap = function( attribute, value )
	{
		var map = this.mappings.find( function( attribute, value, map ) {
			return map[attribute] == value;
		}.bind(this, attribute, value ) );

		return map;
	}

/**
 * Populate the form values via mapped data
 * @param {Object}	data							The data object to use for population
 * @param {Boolean} skipMissingData		Skip items when data attribute is missing from the data object
 */
	this.populateForm = function( data, skipMissingData )
	{
		var i,len,map,val;
		for( i=0,len=this.mappings.length;i<len;i++ )
		{
			map = this.mappings[i];
			val = data[ map.attribute ];
			if( skipMissingData && val == undefined ) continue;

			if( map.populateMethod )
			{
				map.populateMethod( data, map.formItemId, map.attribute );
			}
			else
			{
				if( $( map.formItemId ) == null )
				{
					GSI.Debug.writeLine("Could not find element " + map.formItemId + " for population of form map");
				}
				else
				{
					$( map.formItemId ).value = ( val == undefined ? "" : val );
				}
			}
		}
	}

/**
 * Serialize the form values for data exchange
 * @return {Object} serialized object with the form values populated
 */
	this.serialize = function( )
	{
		var i,len,map;
		var data = {};

		for( i=0,len=this.mappings.length;i<len;i++ )
		{try {

			map = this.mappings[i];
			if( map.serializeMethod )
			{
				data = map.serializeMethod( data, map.formItemId, map.attribute );
			}
			else
			{
				data[ map.attribute ] = $( map.formItemId ).value;
			}
		} catch(e){
			if( CommandCenter.Debug == true )
			{
				GSI.Debug.writeLine("Error in form serialize method: " );
				GSI.Debug.writeLine(( e.message || e ) + "<br>formItem: " + (map.formItemId || "undefined") +"<br>attribute: " + (map.attribute || "undefined"));
			}
			else
			{
				throw( e );
			}
		}}

		return data;
	}
}

/**
 * Load data into the data store
 * @param {String} storeId		The data store id
 * @param {Object} params			The serialized parameters for the Ajax call
 * @param {Function} callback	The method to call upon success or failure
 */
JiveDataExchange.loadData = function( storeId, params, callback )
{
	GSI.Debug.writeLine("Loading data for store: [" +storeId +"]");
	var storeInfo = this.dataLoaders[ storeId ];

	var url = ( storeInfo.useRootURL ) ? this.proxyURL : "";
	url += storeInfo.url + "?refresh=" + GSI.uId();
	new Ajax.Request( url, {
		method: "get",
		parameters: params || {},
		onSuccess: this.loadData_success.bind(this, storeId, callback),
		onFailure: this.loadData_failure.bind(this, storeId, callback),
		onException: this.loadData_exception.bind(this, storeId, callback)
	} );
}

/**
 * Load Multiple data sources
 * @param {Array} sources				An array of string store ids or objects with storeId and params as values
 * @param {Function} callback		The method to call upon completion
 */
JiveDataExchange.loadDataStores = function( sources, callback )
{
	var chain = new GSI.MethodChain();
	var i,len,source;
	for( i=0,len=sources.length; i<len; i++ )
	{
		source = sources[i];
		if( typeof source == "string" ) source = { storeId: source, params: {} };
		chain.add( this.loadData.bind( this, source.storeId, source.params || {}, this.loadDataStores_nextMethod.bind(this,chain,callback) ) )
	}
	chain.add( callback );
	chain.callNext();
}

/**
 * Handler for loadDataStores chain call next method
 * @param {GSI.MethodChain} chain		The chain object
 */
JiveDataExchange.loadDataStores_nextMethod = function( chain )
{
	chain.callNext();
}

/** Success handler for loadData
 * @param {String} storeId		The data store id
 * @param {Function} callback	The GSI method to call
 * @param {Object} transport	XMLHttpRequest object
 * @param {Object} JSON				The result of evaluating the X-JSON response header
 */
JiveDataExchange.loadData_success = function( storeId, callback, transport, JSON )
{

	GSI.Debug.writeLine("Load OK for: " + storeId);
	eval( "JiveDataExchange.dataStore." + storeId + " = " + transport.responseText );
	//callback( true, storeId, this.dataStore[ storeId ] );
	setTimeout(
		function( storeId ,callback)
		{
			callback( true, storeId, this.dataStore[ storeId ] );
		}.bind(this,storeId,callback),
		JiveDataExchange.dataLoaders[ storeId ].callBackDelay || 0
		)
}

/** Failure handler for loadData
 * @param {String} storeId		The data store id
 * @param {Function} callback	The GSI method to call
 * @param {Object} transport	XMLHttpRequest object
 * @param {Object} JSON				The result of evaluating the X-JSON response header
 */
JiveDataExchange.loadData_failure = function( storeId, callback, transport, JSON )
{
	GSI.Debug.writeLine("Load failed for: " + storeId);
	this.dataStore[ storeId ] = {};
	callback( false, storeId );
}

/** Exception handler for loadData
 * @param {String} storeId		The data store id
 * @param {Function} callback	The GSI method to call
 * @param {Object} request		Ajax.request instance
 * @param {Object} exception	The exception returned by the Ajax call
 */
JiveDataExchange.loadData_exception = function( storeId, callback, request, exception )
{
	GSI.Debug.writeLine("Load exception for: " + storeId + "<br>" + (exception.message || exception) );
	this.dataStore[ storeId ] = {};
	callback( exception, storeId );
}

/**
 * Look up a value from the data store
 * @param {Object} storeObject		The store object to use for lookup
 * @param {String} attribute			The attribute to search for
 * @param {Object} value					The value to use for matching
 * @return The matching object
 * @type Object
 */
JiveDataExchange.lookupValue = function( storeObject, attribute, value )
{
	var key,val;
	for( key in storeObject )
	{
		val = storeObject[key];
		if( val[ attribute ] !== undefined  && val[ attribute ] == value ) return val;
	}
	return {};
}

/**
 * Look up a blog post
 * @param {String} attribute		Look up based on this attribute
 * @param {Object} value				Look for this value to match the attribute
 */
JiveDataExchange.lookupBlogPost = function( attribute, value )
{
	var posts = this.dataStore.blogPosts.blog ? this.dataStore.blogPosts.blog.blogPosts : this.dataStore.blogPosts.blogPosts;
	return this.lookupValue( posts, attribute, value );
}

/**
 * Look up a value from the eventTypes in profileData
 * @param {String} attribute		Look up based on this attribute
 * @param {Object} value				Look for this value to match the attribute
 */
JiveDataExchange.lookupEventType = function( attribute, value )
{
	return this.lookupValue( this.dataStore.profileData.eventTypes, attribute, value );
}

/**
 * Look up a value from the eventLocations in profileData
 * @param {String} attribute		Look up based on this attribute
 * @param {Object} value				Look for this value to match the attribute
 */
JiveDataExchange.lookupEventLocation = function( attribute, value )
{
	return this.lookupValue( this.dataStore.eventLocations.locations, attribute, value );
}

/**
 * Look up a value from the calendarTypes in profileData
 * @param {String} attribute		Look up based on this attribute
 * @param {Object} value				Look for this value to match the attribute
 */
JiveDataExchange.lookupCalendarType = function( attribute, value )
{
	return this.lookupValue( this.dataStore.profileData.calendarTypes, attribute, value );
}

/**
 * Submit a form. The browser event is stopped and the form is submitted via an asynchronous request.
 * @param {Event} e							The event which triggered this submission.
 * @param {Element} form				The form element
 * @param {Object} params				The serialized parameters for this form
 * @param {Function} callback		The method to call on completion
 * @return {Ajax.Request} the created request which sent the form.
 */
JiveDataExchange.submitForm = function( e, form, params, callback )
{

//	If they passed a string there isn't really a form
	if( typeof form == "string" )
	{
		var formId = form;
		form = {
			id: formId,
			method: "GET"
		}
	}

//	Get the information for the current action from the formActions object
	var actionInfo = this.formActions[ form.id ][ params.formAction ];
	var url = ( actionInfo.useRootURL ) ? this.proxyURL : "";
	url += actionInfo.url + "?refresh=" + GSI.uId();
	GSI.Debug.writeLine("Submit form to: " + url );
//	Are we using an IFrame or AJAX?
	if( actionInfo.useIFrame )
	{
	//	Remove the old frame from the DOM
		if( actionInfo.frameEl ) Element.remove( actionInfo.frameEl );

	//	Create an iframe for the form submission
		var frameId = GSI.uId();
		var el = actionInfo.frameEl = GSI.$e("iframe",frameId,false,false,document.body,false,{name: frameId});
		el.setStyle({width:0,height:0,alpha:0,opacity:0});

	// IMPORTANT: This is a BUG FIX for Internet Explorer
		if( self.frames[frameId].name != frameId )
		{
			self.frames[frameId].name = frameId;
		}

	// Add hidden form elements for parameters if they don't exist
		for( key in params )
		{
			if( typeof params[key] == "function" ) continue;

			if( $(key) == null || !$(key).descendantOf( form ) )
			{
				GSI.Debug.writeLine("Creating Hidden Element");
				var hiddenEl = GSI.$e("input", key, false, false, form, false, {type:"hidden",name: key, value: params[key] } );
			}
			else if( $(key) !== null && $(key).descendantOf( form ) )
			{
				GSI.Debug.writeLine("Populating Hidden Element");
				$(key).value = params[key];
			}
		}

	// Set the form properties to utilize the iframe
		form.action = url;
		form.target = frameId;
		form.encoding = "multipart/form-data";
		form.method = "POST";

	//	Submit the form and observe the load event of the iframe for callback
		setTimeout( function( form, callback, el ) {

			form.submit();
			if( actionInfo.external ) {
				Element.observe( el, "load", callback );
			} else {
				Element.observe( el, "load", JiveDataExchange.submitForm_iframeLoad.bind( JiveDataExchange, form, callback, el ) );
			}
		}.bind( this, form, callback, el ), 500 );
	}
//	Using AJAX
	else
	{
		var options =
		{
			method: form.method || "get",
			parameters : params || Form.serialize( form ),
			onSuccess: JiveDataExchange.submitForm_success.bind( JiveDataExchange, form, callback ),
			onFailure: JiveDataExchange.submitForm_failure.bind( JiveDataExchange, form, callback ),
			onException: JiveDataExchange.submitForm_failure.bind( JiveDataExchange, form, callback )
		}

		if( e ) Event.stop(e);
		return new Ajax.Request( url, options );
	}
}

/**
 * Load event for iframe call on submitForm
 * @param {Element} form			The original form element
 * @param {Function} callback	The requested callback method
 * @param {Element} frame			The frame element used for the submit
 */
JiveDataExchange.submitForm_iframeLoad = function( form, callback, frame )
{

	setTimeout( function( form, callback, frame ) {
		var doc = frame.contentDocument  ||  ( frame.contentWindow  ? frame.contentWindow.document : false ) || self.frames[ frame.id ].document;
		var body = doc.body;

		var data = undefined;
		try
		{
		data = new String( body.innerHTML ).evalJSON( false );
		}
		catch( e )
		{
			data = { parseError: e };
		}

		callback( true, form, data );
	}.bind( this, form, callback, frame ), 500 );
}

/**
 * Success event for ajax call on submitForm
 * @param {Element}	form			The original form element
 * @param {Function} callback	The requested callback method
 * @param {Object} transport	XMLHttpRequest object
 * @param {Object} JSON				The result of evaluating the X-JSON response header
 */
JiveDataExchange.submitForm_success = function( form, callback, transport, JSON )
{
	var data = undefined;
	try
	{
		data = new String( transport.responseText ).evalJSON( false );
	}
	catch( e )
	{
		GSI.Debug.writeLine("Parse Error: " + transport.responseText);

		data = { parseError: e };
	}
	callback( true, form, data  );
}

/**
 * Failure event for ajax call on submitForm
 * @param {Element}	form			The original form element
 * @param {Function} callback	The requested callback method
 * @param {Object} transport	XMLHttpRequest object
 * @param {Object} JSON				The result of evaluating the X-JSON response header
 */
JiveDataExchange.submitForm_failure = function( form, callback, transport, JSON )
{
	GSI.Debug.writeLine("Form Submission Failed");
	GSI.Debug.writeLine( transport.responseText );
	callback( false, form );
}

/**
 * Failure event for ajax call on submitForm
 * @param {Element}	form			The original form element
 * @param {Function} callback	The requested callback method
 * @param {Object} request		Ajax.request instance
 * @param {Object} exception	The exception returned by the Ajax call
 */
JiveDataExchange.submitForm_exception = function( form, callback, request, exception )
{
	GSI.Debug.writeLine("Form Threw an Exception");
	callback( exception, form );
}
