/* 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,

    items: new Array(),
    samples: new Array(),

    options: {},

    emptyMessage: '<p>' + prodrb.get('Your_cart_empty_txt') + '</p>',
    addMessage: '<p>' + prodrb.get('The_following_added_to_cart_txt') + ':</p>',
    removeMessage: '<p>' + prodrb.get('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.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') {
                    console.log( "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 || {});

        var self = this;
        var params = {
            'SKU_BASE_ID':skus[0].sku_base_id,
            'QTY':skus[0].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();
                self.modify(jsonRpcResponse);
                options.success(data);
            },
            onError: function(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();
                self.modify(jsonRpcResponse);
                options.success(data);
            },
            onError: function(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){
                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();
        var cartResults = jsonRpcResponse.getCartResults();
        var thisHistory = this.history.get(id);
        thisHistory.each(function(item){
            var type = item.type;
            var action = item.action;
            if (action == 'remove') {
                // N.B. The cartResult will have a different format since the underlying CARTITEM was deleted from the server
                if (type == 'sku') {
                    var cartResult = cartResults.find(function(res){
                        return res.result['SKU_BASE_ID'] == item.sku_base_id;
                    });
                    if (cartResult) {
                        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 cartResult = cartResults.find( function(res) {
                        return res.result.CARTITEM['sku.SKU_BASE_ID'] == item.sku_base_id;
                    });
                    if (cartResult) {
                        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 == 1) ? total + navrb.get('Nav_Item') : total + navrb.get('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('dropcart-items-empty'), position: 'replace' });
        }
    },

    fillinDropCart: function(args){
        $(this.options.cart_items).fillin(args);
    },

    refreshDropCart: function(id){
        var operations = this.history.get(id);
        var skus = [];
        var types = [];
        var actions = [];
        operations.each(function(op){
            if (op.type == 'sku') {
                var item = $H();
                item.set( op.sku_base_id, op );
                skus.push(item);
                types.push(op.type);
                actions.push(op.action);
            }
        });

        var self = this;

        var hasAddAction = false;
        hasAddAction = (actions.find(function(a){
            return a == 'add';
        }) ? true : false);

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

        skus.each(function(item){
            var opKeys = item.keys();
            var skubaseid = opKeys[0];
            var operation = item.get(skubaseid);
            if (operation.type != 'sku') return;

            // FIXME: until we can lookupSku by skubaseid...
            var skuid = 'SKU' + skubaseid;

            // FIXME: var qty = item.value;
            var qty = 1;        
            var skuObj = GlobalCatProdData.lookupSku(skuid);
            if (!skuObj) return;
            var prodObj = GlobalCatProdData.lookupProduct(skuObj.PRODUCT_ID);
            if (!prodObj) return;
            var total = Number(qty*skuObj.PRICE).toCurrency('$');
            var calObj = {
                QTY: qty,
                TTL: total,
                formattedTaxedPrice: skuObj.formattedTaxedPrice
            };
            var sendObj = {
                PRODUCT: prodObj,
                SKU: skuObj,
                CALC: calObj
            };
            if ($(self.options.cart_items)) {
                $(self.options.cart_items).fillin({
                    template: templatefactory.get('dropcart-items'),
                    position: 'replace',
                    object: sendObj
                });
                self.showDropCart();
            }
        });
    },

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

});
