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.' ) }
        };

        // MLC: strFetch deprecated
        strFetch = strFetch || 'prodcat';
        method = strFetch;

        var id = 0;
        // JDD: use Perl Gem JSON-RPC format
        if (query) {
            jsonRpcWrapper.fetch({
                method: method,
                params: query,
                onSuccess: function(jsonRpcResponse) {
                    options.onSuccess(jsonRpcResponse.getValue());
                },
                onError: function (jsonRpcResponse) {
                    console.log(method + " fail");
                    console.log(jsonRpcResponse);
                }
            });                
        } else {
            id = 0;
        }
        return id;
    },

    // a callback for JSONRPC onSuccess
    processData: function(responseData){
        var data = $H(responseData);
        this._processData(data);
    },

    _processData: function(data){
        // post-processing of JSON independent of its source
        this.data = this.fillinData(data);
        
        if (this.query) {
            // type determination
            if (this.query[0].categories && data.get('categories')) {
                this.type = "mpp";
                this.category = this.getCategoryById(CATEGORY_ID);
                document.fire("categoryData:loaded", "category");
            } else if (this.query[0].products && data.get('products')) {
                this.type = "spp";
                var prodkey = (CATEGORY_ID ? CATEGORY_ID + '~' + PRODUCT_ID : null);
                this.product = prodkey ? this.getProductByKey(prodkey) : this.getProductById(PRODUCT_ID);
                document.fire("categoryData:loaded", "product");
            } else if (this.query[0].skus && data.get('skus')) {
                this.type = "cart";
                document.fire("categoryData:loaded", "sku");
            }
        }
    },

    fillinData: function(data){
        var self = this;
        data.set('category_by_id', $H());
        data.set('product_by_key', $H());
        data.set('product_by_id', $H());
        data.set('sku_by_id', $H());

        data.set('all_categories', []);
        data.set('all_products', []);
        data.set('all_skus', []);

        data.each(function(t){
            var key = t[0];
            var obj = t[1];

            if (!obj || (key != 'categories' && key != 'products' && key != 'skus'))
                return;
                
            if ( !obj.each ) {
            	obj = $A(obj);
            }
            
            if (key == 'skus') {
                obj.each(function(item){
                    self._processSku(data, item);
                });
            }

            if (key == 'products') {
                obj.each(function(item){
                    self._processProduct(data, item);
                });
            }

            if (key == 'categories') {
                obj.each(function(item){
                    self._processCategory(data, item);
                });
            }
        });

        return data;
    },

    // these functions are thought to be used only by fillinData
    _processSku: function(data, item){
        if (!data.get('sku_by_id').get(item.SKU_ID)) {
            data.get('all_skus').push(item);
            data.get('sku_by_id').set(item.SKU_ID, item);
        }
    },

    _processProduct: function(data, item){
        var self = this;
        var prodkey = item.PRODUCT_KEY;
        if (!prodkey) {
            prodkey = (item.PARENT_CAT_ID) ? item.PARENT_CAT_ID + '~' + item.PRODUCT_ID : item.DEFAULT_CAT_ID + '~' + item.PRODUCT_ID;
        }
        if (Object.isArray(item.skus)) {
            // iterate over each sku and add the sku to the sku lists
            item.skus.each(function(sku){
                self._processSku(data, sku);
            });
        } else {
            item.skus = null;
        }
        if (!data.get('product_by_key').get(prodkey)) {
            data.get('all_products').push(item);
            data.get('product_by_key').set(prodkey, item);
            // product_by_id: use default product if we have it
            // otherwise use the one we've got
            var seenProd = data.get('product_by_id').get(item.PRODUCT_ID);
            if (seenProd == null) {
                data.get('product_by_id').set(item.PRODUCT_ID, item);
            } else {
                // we've already added this product, replace it we the default if we now have that product
                if (item.PARENT_CAT_ID == item.DEFAULT_CAT_ID) {
                    data.get('product_by_id').unset(item.PRODUCT_ID);
                    data.get('product_by_id').set(item.PRODUCT_ID, item);
                }
            }
        }
    },

    _processCategory: function(data, item){
        var self = this;
        // recursive processing of children
        if (Object.isArray(item.children)) {
            item.children.each(function(childCat){
                self._processCategory(data, childCat);
            });
        } else {
            item.children = null;
        }
        if (Object.isArray(item.products)) {
            item.products.each(function(prod){
                self._processProduct(data, prod);
            });
        } else {
            item.products = null;
        }
        if (!data.get('category_by_id').get(item.CATEGORY_ID)) {
            data.get('all_categories').push(item);
            data.get('category_by_id').set(item.CATEGORY_ID, item);
        }
    },

    // accessors
    // returns all products
    getProducts: function(){
        return (this.data ? this.data.get('all_products') : null);
    },

    // returns all skus
    getSkus: function(){
        return (this.data ? this.data.get('all_skus') : null);
    },

    // returns all categories
    getCategories: function(){
        return (this.data ? this.data.get('all_categories') : null);
    },

    getProductBySku: function(skuid, prodid){
        var sku = this.data.get('sku_by_id').get(skuid);
        if (!sku) return null;
        var prod;
        if (!prodid) {
            prodid = sku.PRODUCT_ID;
        }
        if (sku.PARENT_CAT_ID) {
            var prodkey = sku.PARENT_CAT_ID + '~' + prodid;
            prod = this.data.get('product_by_key').get(prodkey);
        }
        if (!prod) {
            prod = this.data.get('product_by_id').get(prodid);
        }
        if (!prod) return null;
        // note: not setting up prod.sku, instead always using array object
        if (!prod.skus) {
           prod.skus = [];
           prod.skus[0] = sku;
        }
        return prod;
    },

    getProductById: function(prodid){
        var prod = this.data.get('product_by_id').get(prodid);
        return (!prod ? null : prod );
    },

    getProductByKey: function(prodkey){
        var prod = this.data.get('product_by_key').get(prodkey);
        return (!prod ? null : prod );
    },

    // reasoning: cannot expect product object to have cat id info?
    getCategoryByProduct: function(prodid){
        var prod = this.data.get('product_by_id').get(prodid);
        var cats = this.data.get('all_categories');
        var retcat = null;
        cats.each(function(c){
            if (c.products) {
                var prod = c.products.find(function(p){
                    return p.PRODUCT_ID == prodid;
                });
            }
            if (prod)
                retcat = c;
        });
        return retcat;
    },

    getCategoryBySku: function(skuid, prodid){
        var prod = this.getProductBySku(skuid, prodid);
        var cat = ( prod && prod.PRODUCT_ID ? this.getCategoryByProduct(prod.PRODUCT_ID) : null);
        return cat;
    },

    getCategoryById: function(catid){
        var cat = (this.data.get('category_by_id') ? this.data.get('category_by_id').get(catid) : null);
        return cat;
    },

    // merge two filled in data structures
    mergeData: function(newProductData) {
        if (!this.data || !this.data.keys().length) {
            this.query = newProductData.query;
            this.reverse = newProductData.reverse;
            this.callback = newProductData.callback;
            this.category = newProductData.category;
            this.product = newProductData.product;
            this.sku = newProductData.sku;
            this.type = newProductData.type;
            this.data = newProductData.data;

        } else {

            var clonedData = this.data;
            var self = this;
            if (newProductData.getSkus) {
                var obj = newProductData.getSkus();
                if ( obj ) {
	                obj.each(function(item){
	                    self._processSku(clonedData, item);
	                });
	            }
            }
            if (newProductData.getProducts) {
                var obj = newProductData.getProducts();
                if ( obj ) {
	                obj.each(function(item){
	                    self._processProduct(clonedData, item);
	                });
	            }
            }
            if (newProductData.getCategories) {
                var obj = newProductData.getCategories();
                if ( obj ) {
	                obj.each(function(item){
	                    self._processCategory(clonedData, item);
	                });
	            }
            }
            if (newProductData.getSkus) {
                var obj = newProductData.getSkus();
                if ( obj ) {
	                obj.each(function(item){
	                    if (!clonedData.get('all_skus')) {
	                        clonedData.set('all_skus', []);
	                    }
	                    clonedData.get('all_skus').push(item);
	                });
	            }
            }
            if (newProductData.getProducts) {
                var obj = newProductData.getProducts();
                if ( obj ) {
	                obj.each(function(item){
	                    if (!clonedData.get('all_products')) {
	                        clonedData.set('all_products', []);
	                    }
	                    clonedData.get('all_products').push(item);
	                });
	            }
            }
            if (newProductData.getCategories) {
                var obj = newProductData.getCategories();
                if ( obj ) {
	                obj.each(function(item){
	                    if (!clonedData.get('all_categories')) {
	                        clonedData.set('all_categories', []);
	                    }
	                    clonedData.get('all_categories').push(item);
	                });
	            }
            }
        }
    },

    linkSkusToProducts: function() {
        /*
         * FIXME: 
         * PENDING: not sure this is needed with new RPC API
         */
    }
});

var GlobalCatProdData = new CatProdPageData();

mergeIntoGlobalCatProdData = function(newCatProdData) {
    if (GlobalCatProdData) {
        GlobalCatProdData.mergeData(newCatProdData);
    } else {
        GlobalCatProdData = newCatProdData;
    }
    //console.dir( GlobalCatProdData );
}

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

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

GlobalCatProdData.lookupProduct = function(prodid) {
    var prodObj = null;
    if (typeof CatProdData == 'object')
        prodObj = this.tryLookupObject(CatProdData, 'product_by_id', prodid);
    if (!prodObj)
        prodObj = this.tryLookupObject(GlobalCatProdData, 'product_by_id', 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);

       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;
}

