/* turn off legacy dropcart */
NO_USER_NOTIFY = 1;

/* transaction.js */
var txn = {};
txn.TRANSACTION_QUERY = {};
txn.TRANSACTION_QUERY.TRANSACTION_FIELDS = {
    "trans_fields" : ["TRANS_ID", "payments"]
};
txn.TRANSACTION_QUERY.PAYMENT_FIELDS = {
    "payment_fields" : ["address", "PAYMENT_TYPE", "PAYMENT_AMOUNT", "TRANS_PAYMENT_ID"]
};
txn.TRANSACTION_QUERY.ORDER_FIELDS = {
    "order_fields" : ["items", "samples", "address", "TRANS_ORDER_ID"]
};

var Txn = Class.create({
    order: new Hash(),
    payments: new Array(),
    carts: new Hash(),
    history: new Hash(),
    count: 0,
    hasCartItems: false,
    
    // WDR: when we add/subtract an item, the result will be stored here for handy reference.
    // Index to the array will be the "id" of the request.
    cartResults: new Array(),

    options: {},

    emptyMessage: '<p>' + brand_resource('Your_cart_empty_txt') + '</p>',
    addMessage: '<p>' + brand_resource('The_following_added_to_cart_txt') + ':</p>',
    removeMessage: '<p>' + brand_resource('The_following_removed_from_cart_txt') + ':</p>',

    initialize: function(options){
        this.options = Object.extend({
            cart_box: 'cart-box',
            cart_items: 'cart-items',
            cart_link: 'cart-link',
            cart_qty_class: '.cart-qty',
            cart_message: 'cart-message'
        }, options || {});

        var self = this;
        var id = this._loadtxn({
            success: function(data) {
                self._load_data(data);
            },
            failure: function(){console.log('Transaction JSON failed to load')}
        });
        return id;
    },
    getItemQty : function(baseSkuId) {
        var lineItem = this.order.items.find( function (line) {
            return line['sku.SKU_BASE_ID'] ==  baseSkuId;
        });
        if (!lineItem) {
            return null; 
        }                
        return lineItem.ITEM_QUANTITY;
    },
    getSubtotal: function() {
        var lineItems = this.order.items;
        var subtotal = 0;
        for (var i=0, len = lineItems.length; i<len; i++) {
            var lineItem = lineItems[i];
            subtotal += (lineItem.UNIT_PRICE) * lineItem.ITEM_QUANTITY;
            //subtotal += (lineItem.UNIT_PRICE + lineItem.UNIT_TAX) * lineItem.ITEM_QUANTITY;
        }
        return subtotal;
    },
    getLineItemUnitPrice: function(baseSkuId) {
        var lineItem = this.order.items.find( function (line) {
            return line['sku.SKU_BASE_ID'] ==  baseSkuId;
        });
        if (!lineItem) {
            return null; 
        }                
        return lineItem.UNIT_PRICE;
    },
    getLineItemAppliedPrice: function(baseSkuId) {
        var lineItem = this.order.items.find( function (line) {
            return line['sku.SKU_BASE_ID'] ==  baseSkuId;
        });
        if (!lineItem) {
            return null; 
        }
        var subtotal = lineItem.UNIT_PRICE * lineItem.ITEM_QUANTITY;
        return subtotal;
    },
    getLineItemUnitTax: function(baseSkuId) {
        var lineItem = this.order.items.find( function (line) {
            return line['sku.SKU_BASE_ID'] ==  baseSkuId;
        });
        if (!lineItem) {
            return null; 
        }                
        return lineItem.UNIT_TAX;
    },
    getLineItemAppliedTax: function(baseSkuId) {
        var lineItem = this.order.items.find( function (line) {
            return line['sku.SKU_BASE_ID'] ==  baseSkuId;
        });
        if (!lineItem) {
            return null; 
        }
        return lineItem.UNIT_TAX * lineItem.ITEM_QUANTITY;
    },
    getBaseSkuIds: function() {
        var baseSkuIds = this.order.items.pluck( 'sku.SKU_BASE_ID' );
        return baseSkuIds; 
    },
    _loadtxn: function(options){
        var options = Object.extend({
            success: function(){},
            failure: function(){}
        }, options || {});
        var transParams = {};
        transParams = Object.extend ( transParams, txn.TRANSACTION_QUERY.TRANSACTION_FIELDS );
        transParams = Object.extend ( transParams, txn.TRANSACTION_QUERY.PAYMENT_FIELDS );
        transParams = Object.extend ( transParams, txn.TRANSACTION_QUERY.ORDER_FIELDS );
        transParams = [transParams];
        var id = jsonRpcWrapper.fetch({
            method : 'trans.get',
            params : transParams,
            onSuccess : function(jsonRpcResponse) {
                options.success(jsonRpcResponse.getValue());
            },
            onError : options.failure.bind(this)
        });
        return id;
    },

    // Assuming one order per transaction
    _load_data: function(data){
        this.data = data;
        this.count = data.items_count;
        this.defaultCartId = data.default_cart_id;
        this.payments = $A(data.trans.payments);
        this.order = data.order;
        this.fillinData();
        this.resetDropCart(0);
        document.fire('txn:loaded');  
    },

    // Assuming one order per transaction
    fillinData: function(){
        // contents and sample_contents mirror the sku by qty hashes
        this.order.contents = new Hash();
        this.order.sample_contents = new Hash();
        if (this.order.items != null) {
            this.order.items = this.order.items.reject(function(item){ // filter out nulls
                return item === null;
            });
        }
        var items = (this.order.items != null) ? this.order.items : null;
        if (items != null) {
            items.each(function(item){
                if (!item) { return; }
                // set up contents by cart hashes
                var cartID = item.CART_ID;
                var cart = this.carts.get(cartID);
                if (!cart) {
                    this.carts.set(cartID, new Hash());
                    cart = this.carts.get(cartID);
                    cart.set('contents', new Hash());
                }
                var id = item['sku.SKU_BASE_ID'] ? item['sku.SKU_BASE_ID'] : item.COLLECTION_ID; 
                cart.get('contents').set(id, item.ITEM_QUANTITY);
                
                // compute per-unit tax (replace this with field from JSONRPC result when available)
                var unitTax = item.APPLIED_TAX/item.ITEM_QUANTITY;
                item.UNIT_TAX = unitTax;

                // set up order contents hash (spans carts)
                if (item.itemType.toLowerCase() == 'skuitem') {
                    var key = item['sku.SKU_BASE_ID'];
                    var qty = item.ITEM_QUANTITY;
                    this.order.contents.set(key,qty);
                } else if (item.itemType.toLowerCase() == 'kititem') {
                    var key = item.COLLECTION_ID;
                    var qty = item.ITEM_QUANTITY;
                    this.order.contents.set(key,qty);
                } else {
                    console.log( "UNKNOWN CARTITEM!!! " + item.itemType.toLowerCase() );
                    // FUTURE: other cart item types (e.g. kits)
                }
            }, this);
        }

        var samples = this.order.samples;
        if (samples != null) {
            samples.each(function(item){
                // set up contents by cart hashes
                var cartID = item.CART_ID;
                var cart = this.carts.get(cartID);
                if (!cart) {
                    this.carts.set(cartID, new Hash());
                    cart = this.carts.get(cartID);
                    cart.set('contents', new Hash());
                }
                var id = item['sku.SKU_BASE_ID'] ? item['sku.SKU_BASE_ID'] : item.COLLECTION_ID; 
                cart.get('contents').set(id, item.ITEM_QUANTITY);

                // set up order contents hash (spans carts)
                if (item.itemType.toLowerCase() == 'sampleitem') {
                    var key = item['sku.SKU_BASE_ID'];
                    var qty = item.ITEM_QUANTITY;
                    this.order.sample_contents.set(key,qty);
                } else {
                    // other item types (are likely errors)
                }
            }, this);
        }
        // hasCartItems is a top-level flag to indicate a non-empty transaction
        this.hasCartItems = (this.count > 0) ? true : false;
    },

    // Provide option to exclude samples from the count?
    qty: function(){
        var includeSamples = true;
        var ttl = 0;
        var items = this.order.items;
        if (items != null) {
            items.each(function(item){
                if (item && item.ITEM_QUANTITY) {
                    ttl += item.ITEM_QUANTITY;
                }
            });
        }
        if (includeSamples) {
            var samples = this.order.samples;
            if (samples != null) {
                samples.each(function(item){
                    ttl += item.ITEM_QUANTITY;
                });
            }
        }        
        return ttl;
    },

    // interface change: perlgem multiple carts?
    // functions which update the contents and sample_contents hashes
    addSku: function(cartid,skubaseid,qtyToAdd){
        if (!cartid) {
            cartid = this.defaultCartId;
        }
        var qty = this.order.contents.get(skubaseid) || 0;
        qty += qtyToAdd;
        this.order.contents.set(skubaseid,qty);
        this.updateGlobalQty();
        $(this.options.cart_message).innerHTML = this.addMessage;
    },
    addSample: function(cartid,skubaseid,qtyToAdd){
        // by convention we do not add samples to the default cart
        if (cartid && (cartid != this.defaultCartId)) {
            var qty = this.order.sample_contents.get(skubaseid) || 0;
            qty += qtyToAdd;
            this.order.sample_contents.set(skubaseid,qty);
            this.updateGlobalQty();
            $(this.options.cart_message).innerHTML = this.addMessage;
        }
    },

    // change to use base ids?
    checkSkuCat: function(sku){
        if (sku.simple) return sku;
        if (sku && sku.sku_id) {
            var catid = GlobalCatProdData.getCategoryIdBySku(sku.skuid);
            if (catid)
                sku.category_id = catid;
        }
        return sku;
    },

    // CartItem Manipulation
    // targeting of the correct cart is still missing (and important to get right)
    add: function(){
        args = Array.from(arguments);
        var skus = [];
        var options = {};
        if (args.length == 1) {
            arg = args[0];
            if (typeof arg == 'object') {
                sku = Object.extend({
                    sku_base_id: '',
                    skucat_id: '',
                    qty: 1,
                    increment: 0,
                    cart_id: ''
                }, arg);
            } else {
                sku = {
                    sku_base_id: arg,
                    skucat_id: '',
                    qty: 1,
                    increment: 0,
                    cart_id: ''
                };
            }
            sku = this.checkSkuCat(sku);
            skus.push(sku);
        } else {
            args.each(function(arg){
                if (typeof arg == 'object') {
                    if (arg.success || arg.failure) {
                        options = arg;
                    } else {
                        sku = Object.extend({
                            sku_base_id: '',
                            skucat_id: '',
                            qty: 1,
                            increment: 0,
                            cart_id: ''
                        }, arg);
                        sku = this.checkSkuCat(sku);
                        skus.push(sku);
                    }
                } else {
                    sku = {
                        sku_base_id: arg,
                        skucat_id: '',
                        qty: 1,
                        increment: 0,
                        cart_id: ''
                    };
                    sku = this.checkSkuCat(sku);
                    skus.push(sku);
                }
            }, this);
        }

        var options = Object.extend({
            success: function(){},
            failure: function(){}
        }, options || {});

		// WDR 11/2/2010: updated to handle an array of skus, not just one
        var self = this;
        var params = {
            'SKU_BASE_ID': $A(skus).pluck('sku_base_id'),
            'QTY': $A(skus).pluck('qty'),
            '_SUBMIT':'cart'
        };
        if (skus[0].increment){
            params['INCREMENT']=1;
        }
        // cart id if we are adding to something other than the default cart
        if (skus[0].cart_id && (skus[0].cart_id != self.defaultCartId)) {
            params['CART_ID']=skus[0].cart_id;
        }

        var id = jsonRpcWrapper.fetch({
            method : 'generic',
            params: [params],
            onSuccess: function(jsonRpcResponse){
                // var data = jsonRpcResponse.getData();
                var data = jsonRpcResponse.getCartResults();
				document.fire('txn:altercart',data);
                self.modify(jsonRpcResponse);
                options.success(data);
            },
            onError: function(t){
				document.fire('txn:error',t);
                options.failure(t);
            }
        });

        var operations = [];
        skus.each(function(sku){
            operations.push({action:'add', type:'sku', status:'pending', sku_base_id:sku.sku_base_id, sku_type:'sku', cart_id:sku.cart_id});
        });
        this.history.set(id,operations);
        return id;
    },

    sub: function(skubaseid, options){
        var options = Object.extend({
            success: function(){},
            failure: function(){}
        }, options || {});

        // fixme: sample/items
        var qty = this.order.contents.get(skubaseid) || 0;
        if (--qty<0) return (-1);

        var params = {
            'SKU_BASE_ID':skubaseid,
            'QTY':qty,
            '_SUBMIT':'cart'
        };
        // cart id if we are adding to something other than the default cart
        if (options.cart_id && (options.cart_id != self.defaultCartId)) {
            params['CART_ID']=options.cart_id;
        }

        var self = this;
        var id = jsonRpcWrapper.fetch({
            method : 'generic',
            params: [params],
            onSuccess: function(jsonRpcResponse){
                var data = jsonRpcResponse.getData();
				document.fire('txn:altercart',data);
                self.modify(jsonRpcResponse);
                options.success(data);
            },
            onError: function(t){
				document.fire('txn:error',t);
                options.failure(t);
            }
        });

        var operations = [];
        operations.push({action:'sub', type:'sku', status:'pending', sku_base_id:skubaseid, sku_type:'sku', cart_id:options.cart_id});
        this.history.set(id,operations);
        return id;
    },

    remove: function(skubaseid, options){
        var self = this;
        var options = Object.extend({
            success: function(){},
            failure: function(){}
        }, options || {});

        var params = {
            'SKU_BASE_ID':skubaseid,
            'QTY':0,
            '_SUBMIT':'cart'
        };
        // cart id if we are adding to something other than the default cart
        if (options.cart_id && (options.cart_id != self.defaultCartId)) {
            params['CART_ID']=options.cart_id;
        }

        var id = jsonRpcWrapper.fetch({
            method : 'generic',
            params: [params],
            onSuccess: function(jsonRpcResponse){
                // var data = jsonRpcResponse.getData();
                var data = jsonRpcResponse.getCartResults();
                self.modify(jsonRpcResponse);
                options.success(data);
            },
            onError: function(t){
				document.fire('txn:error',t);
                options.failure(t);
            }
        });

        var operations = [];
        operations.push({action:'remove', type:'sku', status:'pending', sku_base_id:skubaseid, sku_type:'sku', cart_id:options.cart_id});
        this.history.set(id,operations);
        return id;
    },

    _getCartResults: function(jsonRpcResponse) {
        var data = jsonRpcResponse.getCartResults();
        return data;
    },

    modify: function(jsonRpcResponse){
        var id = jsonRpcResponse.getId();
        this.cartResults[id] = jsonRpcResponse.getCartResults();
        
        this.cartResults[id].each(function(cartResult){
        	
            var type = cartResult.type.toLowerCase();
            var action = cartResult.action.toLowerCase();
            if (action == 'remove' || action == 'delete') {
                // N.B. The cartResult will have a different format since the underlying CARTITEM was deleted from the server
                if (type == 'sku') {
                    var cartOperationResult = cartResult.result;
                    var self = this;
                    self.count -= cartOperationResult.PREVIOUS_ITEM_QUANTITY;
                    if (self.order.items) {
                        self.order.items = self.order.items.reject( function (line) {
                            return line['sku.SKU_BASE_ID'] ==  cartOperationResult.SKU_BASE_ID;
                        });                            
                    }
                    self.order.contents.set(cartOperationResult['SKU_BASE_ID'], 0);
                    self.carts.get(cartOperationResult['CART_ID']).get('contents').set(cartOperationResult['sku.SKU_BASE_ID'],0);
                    self.hasCartItems = (self.count > 0) ? true : false;
                }
            } else {
                // action was 'add' or 'sub', cartResult should contain a proper CARTITEM object
                if (type == 'sku') {
                    var cartOperationResult = cartResult.result;
                    var self = this;
                    self.count += (cartOperationResult.CARTITEM['ITEM_QUANTITY'] - cartOperationResult.PREVIOUS_ITEM_QUANTITY);
                    var contents_item;
                    if (self.order.items != null) {
                        contents_item = self.order.items.find(function(citem){
                            return cartOperationResult.CARTITEM['sku.SKU_ID'] == citem['sku.SKU_ID'];
                        });
                    }
                    if (contents_item) {
                        contents_item.ITEM_QUANTITY = cartOperationResult.CARTITEM['ITEM_QUANTITY'];
                        contents_item.UNIT_PRICE = cartOperationResult.CARTITEM['UNIT_PRICE'];
                        contents_item.APPLIED_TAX = cartOperationResult.CARTITEM['APPLIED_TAX'];
                    } else {
                        // we should add this to our local indexes
                        if (self.order.items == null) { self.order.items = new Array(); }
                        self.order.items.push({
                            ITEM_QUANTITY: cartOperationResult.CARTITEM['ITEM_QUANTITY'],
                            UNIT_PRICE: cartOperationResult.CARTITEM['UNIT_PRICE'],
                            'sku.SKU_ID' : cartOperationResult.CARTITEM['sku.SKU_ID'],
                            'sku.label' : null,
                            'prod.PRODUCT_ID' : cartOperationResult.CARTITEM['product.PRODUCT_ID'],
                            'prod.FAMILY_CODE' : null,
                            'prod.PROD_RGN_NAME' : cartOperationResult.CARTITEM['product.PROD_RGN_NAME']
                        });
                    }
                    self.order.contents.set(cartOperationResult.CARTITEM['sku.SKU_BASE_ID'],cartOperationResult.CARTITEM['ITEM_QUANTITY']);
                    if (!self.carts.get(cartOperationResult.CARTITEM['CART_ID'])) {
                        self.carts.set(cartOperationResult.CARTITEM['CART_ID'], new Hash());
                        self.carts.get(cartOperationResult.CARTITEM['CART_ID']).set('contents', new Hash());
                    }
                    self.carts.get(cartOperationResult.CARTITEM['CART_ID']).get('contents').set(cartOperationResult.CARTITEM['sku.SKU_BASE_ID'],cartOperationResult.CARTITEM['ITEM_QUANTITY']);
                    self.hasCartItems = (self.count > 0) ? true : false;
                } else if (type == 'kit') {
                    // PENDING
                } else if (type == 'sample') {
                    // PENDING
                }
            }
        }, this);
        
        this.updateGlobalQty();
        this.userNotify(id);
        document.fire("txn:modify");
    },

    // Notifications and Display
    userNotify: function(id){
        // set NO_USER_NOTIFY global to prevent drop cart on a page
        if (!NO_USER_NOTIFY) {
            if (id) {
                this.refreshDropCart(id);
            } else {
                // notify with 0 means tell them their cart is empty
                this.resetDropCart(id);
                this.showDropCart();
            }
        }
        this.updateGlobalQty();
    },
    
    updateGlobalQty: function(){
        var total = this.qty();
        var subtotal = total + ' ' + ((total == 1) ? brand_resource('Nav_Item') : brand_resource('Nav_Items'));
        $$(this.options.cart_qty_class).each(function(elem){
            elem.innerHTML = subtotal
        });
    },

    resetDropCart: function(id){
        if ($(this.options.cart_message) && $(this.options.cart_items)) {
            $(this.options.cart_message).innerHTML = this.emptyMessage;
            $(this.options.cart_items).fillin({ template: templatefactory.get('/templates/dropcart-items-empty.tmpl'), position: 'replace' });
        }
    },

    fillinDropCart: function(args){
        $(this.options.cart_items).fillin(args);
    },
    
    // Take a cart item (as received from a cart.add request)
    // and turn it into a hash/object with sku and prod fields.
    makeCartItemObject: function(cartItem) {
    	var rHash = {};
    	$H(cartItem).each(function(pair){
    		var arKeys = pair.key.split('.');
    		var subKey = ( arKeys[0] == 'sku' || arKeys[0] == 'prod' ? arKeys[1] : null );
    		if ( subKey ) {
    			if ( !rHash[arKeys[0]] ) rHash[arKeys[0]] = {};
    			rHash[arKeys[0]][subKey] = pair.value;
    		} else {
    			rHash[pair.key] = pair.value;
    		}
    	});
    	return rHash;
    },

    refreshDropCart: function(id){
    	
    	// If this doesn't exist, we don't need to bother
    	var cartWindow = $(this.options.cart_items);
    	if ( !cartWindow ) return;
        var hasAddAction = false;
    	
    	// Ideally we'll do this from the cartResults we received in the json callback.
    	// If not, we'll have to look up the operation from our history.
    	if ( this.cartResults[id] ) {
    		// Loop thru the result items and update the dropcart with each item
    		this.cartResults[id].each( function(cartResult,index) {
    			
	            var skubaseid = cartResult.result.CARTITEM["sku.SKU_BASE_ID"];;
	            var skuid = 'SKU' + skubaseid;
            	var skuObj = GlobalCatProdData.lookupSku(skuid);
            	if (!skuObj) return;
            	var prodObj = GlobalCatProdData.lookupProduct(skuObj.PRODUCT_ID);
            	if (!prodObj) return;
    			if ( cartResult.action == 'add' ) {
    				hasAddAction = true;
    			}

            	this.fillinDropCartItem({
            		index: index,
            		sku: skuObj,
            		prod: prodObj,
            		qty: cartResult.result.CARTITEM["ITEM_QUANTITY"],
            		price: cartResult.result.CARTITEM["sku.PRICE"],
            		cartWindow: cartWindow
            	});
    		}, this);
    	} else {
    		// Look up the sku(s) from the history.
	        var operations = this.history.get(id);
	        operations.each(function(op, index){
	            if (op.type == 'sku') {

		            var skuid = 'SKU' + op.sku_base_id;
	            	var skuObj = GlobalCatProdData.lookupSku(skuid);
	            	if (!skuObj) return;
	            	var prodObj = GlobalCatProdData.lookupProduct(skuObj.PRODUCT_ID);
	            	if (!prodObj) return;
	                if ( op.action == 'add' ) {
	                	hasAddAction = true;
	                }
	            	
	            	this.fillinDropCartItem({
	            		sku: skuObj,
	            		prod: prodObj,
	            		qty: 1,
	            		price: skuObj.PRICE,
	            		index: index,
	            		cartWindow: cartWindow
	            	});
	            }
	        }, this);
        }

        if ($(this.options.cart_message)) {
            $(this.options.cart_message).innerHTML = (
                hasAddAction ? this.addMessage : this.removeMessage
            );
        }

		// We're ready to show this thing...
		this.showDropCart();
    },
    
    fillinDropCartItem: function(args) {
    	var cartWindow = args.cartWindow;
    	var cartItem = args.cartItem;
    	var sendObj = {};
    	if ( cartItem ) {
    		// Mild hack for backward compatabililty
    		var calcObj = {
    			QTY: cartItem.ITEM_QUANTITY,
    			total: Number(cartItem.APPLIED_PRICE).toCurrency(),
    			formattedPrice: Number(cartItem.APPLIED_PRICE).toCurrency()
    		};
        	sendObj = Object.extend(sendObj, { CALC: calcObj, sku: cartItem.sku, prod: cartItem.prod });
    	} else {
    		var calcObj = {
    			QTY: args.qty,
    			total: Number(args.qty*args.price).toCurrency(),
    			formattedPrice: Number(args.qty*args.price).toCurrency()
    		};
        	sendObj = Object.extend(sendObj, { CALC: calcObj, sku: args.sku, prod: args.prod });
    	}
            	
        cartWindow.fillin({
            template: templatefactory.get('/templates/dropcart-items.tmpl'),
			position: ( args.index ? 'bottom' : 'replace' ),
            object: sendObj
		});
    },

    showDropCart: function(){
        $(this.options.cart_link).addClassName('active').scrollTo();
        $(this.options.cart_box).show();

        var reset = function(){
            $(this.options.cart_link).removeClassName('active');
            $(this.options.cart_box).hide();
        };

        if (this.timeout){
            clearTimeout(this.timeout);
        }
        this.timeout = setTimeout(reset.bind(this),20000);
    }

});

