
/**
	ExecutionContext class
**/
function ExecutionContext() {
	var self = this;
	
	self.productFilter = new ProductFilter();
	self.hasProductFilterChanged = true;
	self.userType = Constants.NewUserType;
}


/**
	ProductFilter class
**/
function ProductFilter() {
	var self = this;
	//	var productsXML = $("Product:has(IndustryRef[industryID=AT]):has(Year:contains('2007')):has(PlatformRef[platformID=WD])", xml);
	self._elementExprTemplate = ":has(ELEMENT_NAME:contains('ELEMENT_VALUE'))";
	self._attributeExprTemplate = ":has(ELEMENT_NAME[ATTRIBUTE_NAME=ATTRIBUTE_VALUE])";
	
	self.activeProductExpr = self._makeElementExpr("IsActive", "true");
	self.platformExpr = "";
	self.numberOfBusinessLocationsExpr = "";
	self.productNameExpr = "";
	self.yearExpr = "";
	self.industryExpr = "";
	self.numberOfUserExpr = "";
	self.hasSalesAndExpenseTrackingExpr = "";
	self.hasAccoutingAndBusinessMgmtToolsExpr = "";
}


// *** Private methods **//
ProductFilter.prototype._makeAttributeExpr = function(elementName, attributeName, attributeValue) {
	var self = this;
	var attributeExpr = "";
	
	if (!DataUtil.HasValue(attributeValue)) {
		return attributeExpr;
	}

	attributeExpr = self._attributeExprTemplate;
	attributeExpr = attributeExpr.replace("ELEMENT_NAME", elementName);
	attributeExpr = attributeExpr.replace("ATTRIBUTE_NAME", attributeName);
	attributeExpr = attributeExpr.replace("ATTRIBUTE_VALUE", attributeValue);
	
	return attributeExpr;
}


ProductFilter.prototype._makeElementExpr = function(elementName, elementValue) {
	var self = this;
	var elementExpr = "";
	
	if (!DataUtil.HasValue(elementValue)) {
		return elementExpr;
	}

	elementExpr = self._elementExprTemplate;
	elementExpr = elementExpr.replace("ELEMENT_NAME", elementName);
	elementExpr = elementExpr.replace("ELEMENT_VALUE", elementValue);
	
	return elementExpr;
}


// ** Public methods **//
ProductFilter.prototype.getFilterExpr = function() {
	var self = this;

	return self.activeProductExpr +
		self.platformExpr + 
		self.numberOfBusinessLocationsExpr + 
		self.productNameExpr +
		self.yearExpr +
		self.industryExpr + 
		self.numberOfUserExpr + 
		self.hasSalesAndExpenseTrackingExpr + 
		self.hasAccoutingAndBusinessMgmtToolsExpr;
}


ProductFilter.prototype.setPlatformFilter = function(filterValue) {
	var self = this;
	
	self.platformExpr = self._makeAttributeExpr("PlatformRef", "platformID", filterValue);
}


ProductFilter.prototype.setNumberOfBusinessLocationsFilter = function(filterValue) {
	var self = this;
	
	self.numberOfBusinessLocationsExpr = self._makeElementExpr("NumberOfBusinessLocations", filterValue);
}


ProductFilter.prototype.setProductNameFilter = function(filterValue) {
	var self = this;
	
	self.productNameExpr = self._makeElementExpr("ProductName", filterValue);
}


ProductFilter.prototype.setYearFilter = function(filterValue) {
	var self = this;
	
	self.yearExpr = self._makeElementExpr("Year", filterValue);
}


ProductFilter.prototype.setIndustryFilter = function(filterValue) {
	var self = this;
	
	self.industryExpr = self._makeAttributeExpr("IndustryRef", "industryID", filterValue);
}


ProductFilter.prototype.setNumberOfUsersFilter = function(filterValue) {
	var self = this;
	
	self.numberOfUserExpr = self._makeElementExpr("NumberOfUsers", filterValue);
}


ProductFilter.prototype.setHasSalesAndExpenseTrackingFilter = function(filterValue) {
	var self = this;
	
	self.hasSalesAndExpenseTrackingExpr = self._makeElementExpr("HasSalesAndExpenseTracking", filterValue);
}


ProductFilter.prototype.setHasAccoutingAndBusinessMgmtToolsFilter = function(filterValue) {
	var self = this;
	
	self.hasAccoutingAndBusinessMgmtToolsExpr = self._makeElementExpr("HasAccoutingAndBusinessMgmtTools", filterValue);
}


/**
	Product class
**/
function Product() {
	this.productID = "";
	this.productName = "";
	this.productNameShort = "";
	this.productNameAndYear = "";
	this.productDescription = "";
	this.mktgCopy_1 = "";
	this.mktgCopy_2 = "";
	this.featureListStatic = "";
	this.features = new Array();
	this.platformRef = "";
	this.numberOfBusinessLocations = "";
	this.numberOfUsers = "";
	this.industryRefXML = "";
	this.hasSalesAndExpenseTracking = "";
	this.hasAccoutingAndBusinessMgmtTools = "";
	this.year = "";
	this.screenShotSmallURL = "";
	this.screenShotLargeURL = "";
	this.productPageURL = "";
	this.price = "dynamic price";
	this.productIDToCompare_1 = "";
	this.productIDToCompare_2 = "";
	this.productIDToCompare_3 = "";
	this.productIDToCompare_4 = "";
	this.isActive = "";
	this.productRanking = "";
	this.skuID = "";
}

// Public methods
Product.prototype.hasFeature = function(feature) {
	var self = this;
	
	for (var i = 0; i < self.features.length; i++) {
		if (feature.featureID == self.features[i].featureID)
			return true;
	}
	return false;
}


Product.prototype.showFeatureOnInProductPage = function(feature) {
	var self = this;
	var productFeature = self.getFeature(feature);

	if ( productFeature == null )
		return false;
	
	return productFeature.showOnProductPage.toLowerCase() == "true";
}


Product.prototype.showFeatureDot = function(feature) {
	var self = this;
	var productFeature = self.getFeature(feature);

	return productFeature.featureGridDisplayValue.toLowerCase() == Constants.CheckMarkChar;
}


// This method get a feature from the Feature collection fo the Product object
// The particular Product/Feature context may alter properties on the Feature object e.g. Feature.featureGridDisplayValue
Product.prototype.getFeature = function(feature) {
	var self = this;
	
	for (var i = 0; i < self.features.length; i++) {
		if (feature.featureID == self.features[i].featureID)
			return self.features[i];
	}
	return null;
}


Product.prototype.hasFeatureGroup = function(featureGroup) {
	var self = this;
	
	for (var i = 0; i < self.features.length; i++) {
		if (featureGroup.featureGroupID == self.features[i].featureGroupID)
			return true;
	}
	return false;
}


Product.prototype.getFeatureGroups = function() {
	var self = this;

	var featureGroupHash = new Array();
	var featureGroups = new Array();
	
	for (var i = 0; i < self.features.length; i++) {
		featureGroupHash[self.features[i].featureGroupID] = self.features[i].featureGroup;
	}
	
	for (featureGroupID in featureGroupHash) {
		featureGroups.push(featureGroupHash[featureGroupID]);
	}
	
	return featureGroups;
	
}


/**
	Feature class
**/
function Feature() {
	this.featureID = "";
	this.featureGroupID = "";
	this.featureGroup = "";
	this.featureName = "";
	this.featureDescriptionShort = "";
	this.featureDescriptionLong = "";
	this.featureGridDisplayValue = "";
	/*
	this.screenShotURL_1 = "";
	this.screenShotURL_2 = "";
	this.screenShotURL_3 = "";
	*/
	this.showOnProductPage = "";
	this.screenShotURL = "";
	this.footNoteID = "";
}


/**
	FeatureGroup class
**/
function FeatureGroup() {}


/**
	Platform class
**/
function Platform() {}


/**
	Platform class
**/
function Industry() {}


/**
	DataMapper class
**/
function DataMapper(xml) {
	var self = this;

	self.xml = xml;	// copy of the entire xml file
	self.allProducts = null; // cache for products (all products)
}


/**	Product related methods **/

// Private methods
DataMapper.prototype._makeProduct = function(productXML) {
	var self = this;
	var product = new Product();
	
	product.productID = DataUtil.HasValue($(productXML).attr('productID')) ?  $(productXML).attr('productID') : "";
	product.productName = $('ProductName', productXML).text();
	product.productNameShort = $('ProductNameShort', productXML).text();
	product.productNameAndYear = $('ProductName', productXML).text() + " " + $('Year', productXML).text();
	product.productDescription = $('ProductDescription', productXML).text();
	product.productDescriptionLong = $('ProductDescriptionLong', productXML).text();
	product.mktgCopy_1 = $('MktgCopy_1', productXML).text();
	product.mktgCopy_2 = $('MktgCopy_2', productXML).text();
	product.featureListStatic = $('FeatureListStatic', productXML).text();
	
	product.features = self.getFeaturesByProductAssociation($('FeatureRef', productXML));
	product.platformRef = $('PlatformRef', productXML);
	product.numberOfBusinessLocations = $('NumberOfBusinessLocations', productXML).text();
	product.numberOfUsers = $('NumberOfUsers', productXML).text();
	product.industryRefXML = $('IndustryRef', productXML).text();
	product.hasSalesAndExpenseTracking = $('HasSalesAndExpenseTracking', productXML).text();
	product.hasAccoutingAndBusinessMgmtTools = $('HasAccoutingAndBusinessMgmtTools', productXML).text();
	product.year = $('Year', productXML).text();
	product.screenShotSmallURL = $('ScreenShotSmallURL', productXML).text();
	product.screenShotLargeURL = $('ScreenShotLargeURL', productXML).text();
	product.productPageURL = $('ProductPageURL', productXML).text();
	product.productIDToCompare_1 = $('ProductIDToCompare_1', productXML).text();
	product.productIDToCompare_2 = $('ProductIDToCompare_2', productXML).text();
	product.productIDToCompare_3 = $('ProductIDToCompare_3', productXML).text();
	product.productIDToCompare_4 = $('ProductIDToCompare_4', productXML).text();
	product.isActive = $('IsActive', productXML).text();
	product.productRanking = $('ProductRanking', productXML).text();
	product.skuID = $('SkuID', productXML).text();
	
	return product;
}


DataMapper.prototype._getProductsByProductFilter = function(productFilter) {
	var self = this;
	
	/*
	Check for PlatformID WDO	- Windows Desktop or Online.
	This platform really means no mac, so we need to translate.
	*/
	if (productFilter.platformExpr == ":has(PlatformRef[platformID=WDO])") {
		// Remove WDO since it is not a real platform
		productFilter.platformExpr = "";
		
		var productsXML = $("Product" + productFilter.getFilterExpr(), self.xml);
		
		return productsXML.not(":has(PlatformRef[platformID=MC])");
	
	}
	else {
		return $("Product" + productFilter.getFilterExpr(), self.xml);			
	}
}


// If the product filter is in its default state and we have already cached all active products
// we return the products from the cache
DataMapper.prototype._shouldGetAllProductsFromCache = function(productFilter) {
	var self = this;

	return self.allProducts != null && productFilter.getFilterExpr() == new ProductFilter().getFilterExpr();
}


// Public methods
DataMapper.prototype.getProducts = function(productFilter) {
	var self = this;

	// If we need to return all products and all products are cached, return the cached products
	if (self._shouldGetAllProductsFromCache(productFilter)) {
		return self.allProducts;
	}

	var productsXML = self._getProductsByProductFilter(productFilter);
	var products = new Array();
	
	$(productsXML).each(function() {
		var product = self._makeProduct(this);
		products.push(product);
	});


	// If we pulled all products, cache them
	if (productFilter.getFilterExpr() == new ProductFilter().getFilterExpr()) {
		self.allProducts = products.slice();
	}

	return products;
}


DataMapper.prototype.getProductByProductID = function(productID) {
	var self = this;

	if (! DataUtil.HasValue(productID)) {
		throw new Error("productID not provided.")
	}

	var productXML = $("Product[productID=" + productID + "]", self.xml);

	if (productXML.length < 1) {
		throw new Error("No product could not be found for productID: " + productID);
	}

	if (productXML.length > 1) {
		throw new Error("More than one product was found for productID: " + productID);
	}
	
	return self._makeProduct(productXML);
}


DataMapper.prototype.getProductByProductID_IntuitAndIndustryID = function(productID_Intuit, industryID) {
	var self = this;
	var filterExpr = "";

	if (! DataUtil.HasValue(productID_Intuit)) {
		throw new Error("productID_Intuit not provided.")
	}

	filterExpr = "Product:has( ProductID_Intuit:contains('" + productID_Intuit + "') )";

	if (DataUtil.HasValue(industryID)) {
		filterExpr += ":has( IndustryRef[industryID=" + industryID + "] )";
	}

	var productXML = $(filterExpr, self.xml);
	
	if (productXML.length < 1) {
		throw new Error("No product could not be found for productID: " + productID_Intuit + " and industryID:  " + industryID);
	}

	if (productXML.length > 1) {
		throw new Error("More than one product was found for productID: " + productID_Intuit + " and industryID:  " + industryID);
	}
	
	return self._makeProduct(productXML);

	
	
}


/** Feature related methods **/

// Private methods
DataMapper.prototype._makeFeature = function(featureXML) {
	var self = this;
	var feature = new Feature();
	
	feature.featureID = DataUtil.HasValue($(featureXML).attr('featureID')) ? $(featureXML).attr('featureID') : "";
	feature.featureGroupID = $('FeatureGroupID', featureXML).text();
	feature.featureGroup = self.getFeatureGroupByFeatureGroupID($('FeatureGroupID', featureXML).text());
	feature.featureName = $('FeatureName', featureXML).text();
	feature.featureDescriptionShort = $('FeatureDescriptionShort', featureXML).text();
	feature.featureDescriptionLong = $('FeatureDescriptionLong', featureXML).text();
	feature.featureGridDisplayValue = $('FeatureGridDisplayValue', featureXML).text();
	/*
	feature.screenShotURL_1 = $('ScreenShotURL_1', featureXML).text();
	feature.screenShotURL_2 = $('ScreenShotURL_2', featureXML).text();
	feature.screenShotURL_3 = $('ScreenShotURL_3', featureXML).text();
	*/
	feature.showOnProductPage = "";
	feature.screenShotURL = $('ScreenShotURL_1', featureXML).text();
	feature.footNoteID = $('FootNoteID', featureXML).text();

	return feature;
}


// Public methods
DataMapper.prototype.getFeatures = function() {
	var self = this;
	var features = new Array();
	var featureXML = $("Feature", self.xml);			
	
	$(featureXML).each(function() {
		var feature = self._makeFeature(this);
		features.push(feature);
	});
	
	return 	features;
}


DataMapper.prototype.getFeatureByFeatureID = function(featureID) {
	var self = this;

	if (! DataUtil.HasValue(featureID)) {
		throw new Error("featureID not provided.")
	}

	var featureXML = $("Feature[featureID=" + featureID + "]", self.xml);

	if (featureXML.length < 1) {
		throw new Error("No product could not be found for featureID: " + featureID);
	}

	if (featureXML.length > 1) {
		throw new Error("More than one feature was found for featureID: " + featureID);
	}
	
	return self._makeFeature(featureXML);
}


DataMapper.prototype.getFeaturesByProductAssociation = function(xml) {
	var self = this;
	var features = new Array();
	
	$(xml).each(function() {
		var feature = self.getFeatureByFeatureID($(this).attr("featureID"));

		// Make sure we have a valid feature record for this association
		if (! DataUtil.HasValue(feature.featureID)) {
			throw new Error("No feature record found for FeatureID: " + $(this).attr("featureID"));
		}

		feature.showOnProductPage = $(this).attr("showOnProductPage");
	
		// Set the product/feature specific display value.
		if ( DataUtil.HasValue($(this).attr("featureGridDisplayValue")) ) {
			feature.featureGridDisplayValue = $(this).attr("featureGridDisplayValue");
		}

		// Set the product/feature specific feature screen shot.
		if ( DataUtil.HasValue($(this).attr("screenShotURL")) ) {
			feature.screenShotURL = $(this).attr("screenShotURL");
		}
		
		// Set the product/feature specific foot notes.
		if ( DataUtil.HasValue($(this).attr("footNoteID")) ) {
			feature.footNoteID = $(this).attr("footNoteID");
		}	

		features.push(feature);
	});
	
	return features;
}


/** Feature group related methods **/

// Private methods
DataMapper.prototype._makeFeatureGroup = function(featureGroupXML) {
	var self = this;
	var featureGroup = new FeatureGroup();
	
	featureGroup.featureGroupID = $(featureGroupXML).attr('featureGroupID');
	featureGroup.featureGroupName = $('FeatureGroupName', featureGroupXML).text();

	return featureGroup;
}


// Public methods
DataMapper.prototype.getFeatureGroupByFeatureGroupID = function(featureGroupID) {
	var self = this;
	var featureGroupXML = $("FeatureGroup[featureGroupID=" + featureGroupID + "]", self.xml);
	
	return self._makeFeatureGroup(featureGroupXML);
}


/** Platform related methods **/

// Private methods
DataMapper.prototype._makePlatform = function(platformXML) {
	var self = this;
	var platform = new Platform();
	
	platform.platformID = $(platformXML).attr('platformID');
	platform.platformName = $('PlatformName', platformXML).text();

	return platform;
}


// Public methods
DataMapper.prototype.getPlatforms = function() {
	var self = this;
	var platforms = new Array();
	var platformXML = $("Platform", self.xml);			
	
	$(platformXML).each(function() {
		var platform = self._makePlatform(this);
		platforms.push(platform);
	});
	
	return 	platforms;
}


/** Industry related methods **/

// Private methods
DataMapper.prototype._makeIndustry = function(industryXML) {
	var self = this;
	var industry = new Industry();
	
	industry.industryID = $(industryXML).attr('industryID');
	industry.industryName = $('IndustryName', industryXML).text();

	return industry;
}


// Public methods
DataMapper.prototype.getIndustries = function() {
	var self = this;
	var industries = new Array();
	var industryXML = $("Industry", self.xml);			
	
	$(industryXML).each(function() {
		var industry = self._makeIndustry(this);
		industries.push(industry);
	});
	
	return 	industries;
}