

var CatProdPageData = Class.create({
	
	initialize: function ( query, reverse, callback, strFetch ) {
		
		this.query = query;
		this.reverse = reverse || false;
		this.callback = callback || function () {};
		
		this.category = null;
		this.product = null;
		this.sku = null;
		this.type = '';
		this.data = $H();
		
		var self = this;
		var options = {
			onSuccess: function (t) { 
				self.processData(t);
				self.callback();
			},
			onFailure: function () { console.log ( 'CatProd JSON failed to load.' ) }
		};
		
		strFetch = strFetch || 'prodcat.byid';
		method = this.reverse ? 'tacdorp.byid' : strFetch;
		
		// WDR: skip the fetch if no query given.
		// This allows us to create empty objects that just hold other data.
		var id = ( query ? jsonrpc.fetch( method, query, options ) : 0 );
		
		return id;
		
	}, 
	processData: function (t) {
		var response = t.responseText.evalJSON()[0];
		var id = response.id;
		var error = response.error;
		var data = $H(response.result);
		
		if (error == null) {
			
			this.data = this.fillinData ( data );
			
			if (this.query[0].category && data.get('category')) {
				this.type = "mpp";
				this.category = data.get('category').all[0];
				document.fire("categoryData:loaded", "category");
				
			} else if (this.query[0].product && data.get('product')) {
				this.type = "spp";
				this.product = data.get('product').all[0];
				document.fire("categoryData:loaded", "product");
				
			} else if (this.query[0].sku && data.get('sku')) {
				this.type = "cart";
				this.sku = data.get('sku').all[0];
				document.fire("categoryData:loaded", "sku");
				
			} else if (this.query[0].search && data.get('search')) {
				this.type = "search";
				this.product = data.get('product').all[0];
				document.fire("categoryData:loaded", "search");
				
			}
		}
	},
	
	// Pulled this into a method so i can call it separate from above.
	fillinData: function(data) {
		// add .all, and pointers to the layout
		data.each( function (t) {
			var key = t[0];
			var obj = t[1];
				
			if ( !obj || (key != 'product' && key != 'category' && key != 'sku') )
				return;
					
			obj.all = [];
			Object.keys(obj).each( function (id) {
				var item = obj[id];
				if (Object.isArray(item) && id=='all'){
					// ignore this one.
				} else {
					Object.keys(item).each( function (prop) {
						var link = data.keys().findAll(
							function (s) {
								return s==prop
							});
						if ( link.length && item[prop] ){
							for(c=0;c<item[prop].length;c++){
								item[prop][c]=data.get(prop)[item[prop][c]];
							}
							// convienience method
							item[prop+'s']=item[prop];
						}
						
					});
					obj.all.push(item);
					obj.get = function (id) {
						return obj.all.find( 
							function (o) { 
								return o[key.toUpperCase()+'_ID']==id; 
							} 
						); 
					}												
				}
			});
		});
		
		this.data = data;
		return data;
	},
	
	getProducts: function() {
		var prodobj = ( this.data && this.data.get ? this.data.get('product') : null );
		return ( prodobj ? prodobj.all : null );
	},
	
	getSkus: function() {
		var skuobj = ( this.data && this.data.get ? this.data.get('sku') : null );
		return ( skuobj ? skuobj.all : null );
	},
	
	// Pass in a skuid and get a complete product object for that sku.
	getProductBySku: function(skuid, prodid) {
		var skuGetter = ( this.data && this.data.get ? this.data.get('sku') : null );
		var sku = ( skuGetter ? skuGetter.get(skuid) : null );
		//var sku = this.data.get('sku').get(skuid);
		if ( !sku ) return null;
		if ( !prodid ) {
			prodid = sku.PRODUCT_ID;
		}
		var prod = this.data.get('product').get(prodid);
		if ( !prod ) return null;
		if ( !prod.sku ) {
			prod.sku = sku;
		}
		if ( !prod.skus ) {
			prod.skus = [];
			prod.skus[0] = sku;
		}
		return prod;
	},
	
	// Pass in a product id and get the product object.
	getProductById: function(prodid) {
		var prod = this.data.get('product').get(prodid);
		if ( !prod ) return null;
		return prod;
	},
	
	// Given a sku, lookup what category it belongs to.
	getCategoryBySku: function(skuid, prodid) {
		var prod = this.getProductBySku(skuid,prodid);
		var cat = ( prod && prod.PRODUCT_ID ? this.getCategoryByProduct(prod.PRODUCT_ID) : null );
		return cat;
	},
	
	// Given a product, lookup what category it belongs to.
	getCategoryByProduct: function(prodid) {
		var cat = this.data.get('category');
		var retCat = null;
		if ( cat ) {
			cat.all.each(function(c){
				var plist = ( c.product ? c.product : c.products );
				if ( plist ) {
					var prod = plist.find(function(p){
						return p.PRODUCT_ID == prodid;
					});
				}
				if ( prod )
					// The product is in this category, so this is the category we want.
					retCat = c;
			}, this);
		}
		return retCat;
	},
	
	// This is basically the "middle" of the fillinData() method.
	// Used in the mergeData stuff below.
    addDataObject: function(dataKey,item,key) {
    	var dataObj = this.data.get(dataKey);
    	if ( !dataObj ) {
    		//this.data[dataKey] = $H();
    		this.data.set(dataKey,$H());
    		this.data.get(dataKey)['all'] = [];
    		dataObj = this.data.get(dataKey);
    	}
    	if ( dataObj ) {
    		dataObj.all.push(item);
    		dataObj.get = function (id) {
				return dataObj.all.find( 
					function (o) { 
						return o[key.toUpperCase()+'_ID']==id; 
					}
				); 
			}												
    	}
    },
    
    // Merge another catproddata into this one
	mergeData: function(newProductData) {
		this.mergeSkus ( newProductData.data.get('sku') );
		this.mergeProducts ( newProductData.data.get('product') );
    },	
    
    addObjectList: function(arObjs,strType) {
    	if ( arObjs ) {
    		arObjs.each( function(o) {
    			this.addDataObject(strType,o,strType);
    		}, this);
    	}
    },
    
    mergeSkus: function(arSkus) {
    	if ( arSkus ) {
    		if ( arSkus.all && typeof arSkus.all != 'function' ) {
    			this.addObjectList(arSkus.all,'sku');
    		} else {
    			this.addObjectList(arSkus,'sku');
    		}
    	}
    },
	
    mergeProducts: function(arProducts) {
    	if ( arProducts ) {
    		if ( arProducts.all && typeof arProducts.all != 'function' ) {
    			this.addObjectList(arProducts.all,'product');
    		} else {
    			this.addObjectList(arProducts,'product');
    		}
    	}
    },
	
	linkSkusToProducts: function() {
		// This function links skus to their parent products.
		// This will, of course, create a closure, but needed on pages
		// that build products from a list of skus rather than the
		// other way around.
		var skus = this.data.get('sku').all;
		skus.each ( function(s){
			if ( s.products ) {
				s.products.each(function(p){
					if ( !p.skus ) {
						p.skus = [];
					}
					p.skus.push(s);
				});
			}
		});
	}
	
});

// Global CatProdData manager.
// Based on CPD class, but we'll add some stuff
var GlobalCatProdData = new CatProdPageData();

// These function vars allow external modules to set an additional
// set of lookup functions to find cats/prods/skus.
// (Done originally to support the Endeca catalog data.)
var g_externCatLookup = function(catid) { 
	return null; 
}
var g_externProdLookup = function(prodid) { 
	return null; 
}
var g_externSkuLookup = function(skuid) { 
	return null; 
}

// Global function to add to (or create) the main CatProdData object.
// The Cart object needs this info when adding/removing items.
// This object is fed by multiple places, including userpurchases
// and CMS product server modules.
var mergeIntoGlobalCatProdData = function ( newCatProdData ) {
	// See if global one exists.
	// If not, set it to this one
	if ( GlobalCatProdData ) {
		GlobalCatProdData.mergeData ( newCatProdData );
	} else {
		GlobalCatProdData = newCatProdData;
	}
}

// Merge raw object data into global cat prod object.
// Added for flash apps.  We create a tmp catprod object and call above merge function.
var mergeRawIntoGlobalCatProdData = function ( respData ) {
    var cpobj = new CatProdPageData();
    var responseDataHash = $H(respData[0].result);
    cpobj.fillinData(responseDataHash);
    mergeIntoGlobalCatProdData(cpobj);
}

GlobalCatProdData.tryLookupObject = function(obj,key,index) {
	var retObj = null;
	if ( typeof obj == 'object' ) {
		var keyObj = obj.data.get(key);
		if ( keyObj )
			retObj = keyObj.get(index);
	}
	return retObj;
}

GlobalCatProdData.lookupCategory = function(catid) {
	var catObj = null;
	if ( typeof CatProdData == 'object' )
		catObj = this.tryLookupObject ( CatProdData, 'category', catid );
	if ( !catObj )
		catObj = this.tryLookupObject ( GlobalCatProdData, 'category', catid );
	if ( !catObj )
		catObj = g_externCatLookup(catid);
	return catObj;
}

GlobalCatProdData.lookupSku = function(skuid) {
	var skuObj = null;
	if ( typeof CatProdData == 'object' )
		skuObj = this.tryLookupObject ( CatProdData, 'sku', skuid );
	if ( !skuObj )
		skuObj = this.tryLookupObject ( GlobalCatProdData, 'sku', skuid );
	if ( !skuObj )
		skuObj = g_externSkuLookup(skuid);
	return skuObj;
}

GlobalCatProdData.lookupProduct = function(prodid) {
	var prodObj = null;
	if ( typeof CatProdData == 'object' )
		prodObj = this.tryLookupObject ( CatProdData, 'product', prodid );
	if ( !prodObj )
		prodObj = this.tryLookupObject ( GlobalCatProdData, 'product', prodid );
	if ( !prodObj )
		prodObj = g_externProdLookup(prodid);
	return prodObj;
}

GlobalCatProdData.lookupProductBySku = function(skuid) {
	var prodObj = null;
	if ( typeof CatProdData == 'object' )
		prodObj = CatProdData.getProductBySku(skuid);
	if ( !prodObj && GlobalCatProdData )
		prodObj = GlobalCatProdData.getProductBySku(skuid);
	return prodObj;
}

GlobalCatProdData.lookupCategoryBySku = function(skuid) {
	var catObj = null;
	if ( typeof CatProdData == 'object' )
		catObj = CatProdData.getCategoryBySku(skuid);
	if ( !catObj && GlobalCatProdData )
		catObj = GlobalCatProdData.getCategoryBySku(skuid);
	return catObj;
}

GlobalCatProdData.getCategoryIdBySku = function(skuid) {
	var catId = 0;
	if ( skuid ) {
		var prodObj = this.lookupProductBySku(skuid);
		var catObj  = this.lookupCategoryBySku(skuid);
		
		// If we found a catObj, assume that's the one we want.
		// Else see if the product has a cat id, and if so use that.
		// Else see if there's a default.
		// Else punt.
		catId = ( catObj && catObj.CATEGORY_ID ? catObj.CATEGORY_ID :
				  prodObj && prodObj.PARENT_CAT_ID ? prodObj.PARENT_CAT_ID :
				  prodObj && prodObj.DEFAULT_CAT_ID ? prodObj.DEFAULT_CAT_ID :
				  0 );
	}
	return catId;
}
