var gg;
if (!gg) {
  gg = {};
}
(function() { // So we can have private functions
  if (!gg.Cart) {
    gg.Cart = {
      current: null,
      ejs: null,
      guid: null,
      MAX_SIZE: 5,
      subsite_id: 0
    };
  }
  /**
  * If the user is a member of a meaningful user group, returns that
  * group ID. Meaningful here means it alters the cart response in some way
  **/
  gg.Cart.userGroupId = function() {
    var ca = fl.Util.readCookie('ca');
    if (ca == null || ca == "") {
      return "";
    }
    if (ca.indexOf(".705.") != -1 || ca.indexOf(".700.") != -1) {
        return "700";
    }
    return "";
  };
  gg.Cart.addSku = function(sale_id, product_id, sku_id, callback, exchange_mode, opts) {
    if (!exchange_mode) {
      gg.Cart.numberSkus(function(count) {
        gg.Cart.getCartDialog()
          .html(Locale.please_wait_loading_spin)
          .dialog("option", { height:  221 + 111 * (count + 1) }) // Guesstimate height of modal
          .dialog("open");
      });
    }

    $.getJSON("/inventory_service/reserve_units", addStandardParams({
        product_id: product_id,
        sku_id: sku_id,
        quantity: 1
      }),
      HandleCartResponseFactory(function(cart, msg, data) {
        if (data.data && 0 < data.data.reservations[0].unit_id) {
          // unit_id is valid, send it to cart_service
          sendNewRsvToCartService(sale_id, product_id, sku_id, data.data.reservations[0], callback, exchange_mode, opts);
        } else {
          if (!exchange_mode) {
            showWaitlistFor(sku_id, data);
            if(!fl.Omniture.attributes['events'] || !fl.Omniture.attributes['events'].join().match(/event6/)) {
              fl.Omniture.addAttribute('events', 'event6');
            }
            fl.Omniture.doTracking();
          } else {
            if (callback) {
              callback(true);
            }
          }
        }
      })
    );
  };

  gg.Cart.minExpiration = function() {
    var cart = gg.Cart.current;

    if (!cart.hasOwnProperty("minExpiration")) {
      gg.Cart.reservationsBySku();
    }

    return cart.minExpiration;
  };

  gg.Cart.removeSku = function(sku_id, callback) {
    gg.Cart.updateSkuQuantity(sku_id, 0, null);

    // We want to cart dialog to update instantly, instead of waiting.
    // Fake out removing the reservations and trigger the callback.
    removeReservationsWithSku(sku_id);

    if (callback) {
      callback(gg.Cart.current);
    }
  };

  gg.Cart.reservationsBySku = function() {
    var cart = gg.Cart.current;

    if (!cart.reservations.length) {
      return {};
    }

    if (cart.skus[cart.reservations[0].sku_id].hasOwnProperty("quantity")) {
      return cart.skus;
    }

    var i = -1;
    var max = cart.reservations.length;
    while (++i < max) {
      var reservation = cart.reservations[i];
      var sku         = cart.skus[reservation.sku_id];
      sku.quantity    = (sku.quantity || 0) + 1;
      if (reservation.optional_data && reservation.optional_data.hasOwnProperty("subsite_id")) {
        sku.subsite_id  = reservation.optional_data.subsite_id; // Assuming no skus are common across subsites, or that we would display the most recent one
      }

      if (!sku.expiration_ms || sku.expiration_ms > reservation.expiration_ms) {
        sku.expiration    = reservation.expiration;
        sku.expiration_ms = reservation.expiration_ms;
      }
    }

    cart.quantity      = 0;
    cart.minExpiration = Number.MAX_VALUE;

    for (sku in cart.skus) {
      if (cart.skus.hasOwnProperty(sku)) {
        cart.quantity++;

        if (cart.skus[sku].expiration_ms < cart.minExpiration) {
          cart.minExpiration = cart.skus[sku].expiration_ms;
        }
      }
    }

    return cart.skus;
  };

  gg.Cart.retrieve = function(callback) { // TODO: all usages must have callbacks
    if (gg.Cart.current) {
      callback(gg.Cart.current);
    } else {
      gg.Cart.current = newCart();
      $.getJSON('/cart_service/get', addStandardParams({
        group_id: groupIdForCart(),
        group_id_hash: groupIdHashForCart()
      }), HandleCartResponseFactory(callback));
    }
  };

  gg.Cart.secondsUntilCartExpires = function() {
    return Math.floor((gg.Cart.minExpiration() - (new Date()).getTime() - gg.Cart.current.serverClockDelta) / 1000);
  };

  gg.Cart.updateSkuQuantity = function(sku_id, quantity, callback, sale_id, product_id) { // TODO: signature changed
    var cart = gg.Cart.current;
    var num_reservations = cart.reservations.length;
    cart.user_message = "";

    if (!sale_id || !product_id) {
      var info   = getProductInfoForSku(sku_id);
      sale_id    = info.sale_id;
      product_id = info.product_id;
    }

    var notification = $("div[data-skuid=" + sku_id + "]");
    if (notification.length) {
      Gilt.Notifications.remove(notification);
    }

    var block = function(ev) {
      ev.preventDefault();
    };
    $("a.checkout_button").click(block);
    setTimeout(function() {
      $("a.checkout_button").unbind("click", block);
    }, 5000);
    $.post('/cart_service/change_sku_quantity',
      addStandardParams({
        sale_id: sale_id,
        product_id: product_id,
        sku_id: sku_id,
        quantity: quantity,
        group_id: groupIdForCart(),
        group_id_hash: groupIdHashForCart()
      }),
      HandleCartResponseFactory(function(cart, msg, data) {
        $("a.checkout_button").unbind("click", block);
        evaluateCartModification(sku_id, data, num_reservations);
        if (quantity) {
          addNotification(cart.skus[sku_id]);
          Gilt.Discount.drawAvailable(gg.Cart.subtotal());
        }
        cart.user_message = msg;

        if (callback) {
          callback(cart, data.msg);
        }
      }), "json"
    );
  };

  /*******************************************
  * PRIVATE FUNCTIONS:                       *
  *******************************************/

  var addNotification = function(sku) {
    if (!sku) {
      return;
    }
    var sku_id = sku.sku_data.sku_id;
    var notification = $("div[data-skuid=" + sku_id + "]");
    if (notification.length) {
      Gilt.Notifications.remove(notification);
    }

    Gilt.Notifications.add({
      k:"sku",
      v: [sku_id, sku.sku_data.label_data.product_name, Gilt.Subsite[sku.subsite_id].full_url + sku.sku_data.details_url, "is reserved for @@time@@", "is no longer reserved", "Check Out Now", "gg.Cart.display",
          sku.expiration_ms - gg.Cart.current.serverClockDelta],
      r: sku.expiration_ms - gg.Cart.current.serverClockDelta + 30000
    });
  };

  var addStandardParams = function(params, opts) {
    if (opts) {
      var origOpts = opts;
      opts = {};
      $.each(origOpts, function(key, value) {
        opts["unitopt_" + key] = value;
      });
    }
    return $.extend({}, params, {
      cart_id: getCartGuid(),
      jskey: gg.random_string(20),
      user_guid: fl.Util.readHashedCookie('guid'),
      unitopt_subsite_id: gg.Cart.subsite_id
    }, opts);
  };


  var evaluateCartModification = function(sku_id, data, num_reservations, showWaitlistDialog) {
    fl.Omniture.initialize("cart", "cart: update");

    var result           = getResultFromJson(data) || {};
    var user_msg         = "";

    // Find out what result cart_service returned
    switch(result.code) {
      case 0:
        // Ok
        break;

      case 2:
        // Cart is full, no items added
        user_msg = Locale.max_cart_size(gg.Cart.MAX_SIZE);
        fl.Omniture.addAttribute('events', 'event7');
        break;

      case 3:
        // Cart is full, some items added
        user_msg = Locale.max_cart_size(gg.Cart.MAX_SIZE);
        fl.Omniture.addAttribute('events', 'event7');
        break;

      case 4:
        // Not enough inventory
        if (inventoryIsOutOfStock(getInvResFromJson(data))) {
          user_msg = Locale.is_out_of_stock;
        } else {
          user_msg = Locale.is_not_available;
        }

        if (showWaitlistDialog) {
          showWaitlistFor(data);
        }

        fl.Omniture.addAttribute('events', 'event6');
        break;

      default:
        // Unknown error
        user_msg = result.msg;
    }

    gg.Cart.current.user_message = user_msg;

    // Finish up omniture tracking
    var delta = gg.Cart.current.reservations.length - num_reservations;
    var type  = (0 > delta) ? 'scRemove' : 'scAdd';

    fl.Omniture.addAttribute('products', ';' + sku_id + ';' + delta);
    fl.Omniture.addAttribute('events', type);

    if (num_reservations == 0) {
      fl.Omniture.addAttribute('events', 'scOpen');
    }

    fl.Omniture.doTracking();
  };

  // Gets a unique identifier for the cart. Currently based on guid and subsite id (or a random string if not logged in)
  var getCartGuid = function() {
    if (gg.Cart.guid == null) {
      gg.Cart.guid = fl.Util.readHashedCookie('guid');
      if (gg.Cart.guid == null || gg.Cart.guid == "") {
          // Can't look like a GUID as we want to ensure that we never
          // share this cart with anybody else. We use a 60 char hex
          // to distinguish from a GUID and be long enough to avoid
          // collissions Can't look like a GUID as we want to ensure
          // that we never share this cart with anybody else. We use a
          // 60 char hex to distinguish from a GUID and be long enough
          // to avoid collissions. Start with 0- as we don't have a "0"
          // subsite and thus won't collide with valid carts.
          gg.Cart.guid = '0-' + gg.random_string(60, true);
      } else {
        // Strip out junk in the cookie
        gg.Cart.guid = gg.Cart.guid.substring(gg.Cart.guid.indexOf('_')+1, gg.Cart.guid.length);
      }
    }
    return gg.Cart.guid;
  };

  var HandleCartResponseFactory = function(callback) {
    return function(data) {
      if (data.data && data.data.cart) {
        gg.Cart.current = newCart();
        updateCartFromService(data);
      }
      if (data.data && data.data.success && data.data.result.code == 0) {
        callback(gg.Cart.current, null, data);
      } else {
        callback(gg.Cart.current, data.data.result ? data.data.result.msg : data.msg, data);
      }
    };
  };

  var newCart = function() {
    return {
      loaded: false,
      reservations: [],
      serverClockDelta: 0,
      skus: {},
      user_message: ""
    };
  };

  var getCartFromJson = function(json) {
    if (json.status == 0 && json.data && json.data.cart) {
      return json.data.cart;
    }
    return null;
  };

  var getResultFromJson = function(json) {
    if (json.status == 0 && json.data && json.data.result) {
      return json.data.result;
    }
    return null;
  };

  var getInvResFromJson = function(json) {
    if (json.status == 0 && json.data && json.data.invsvc_response) {
      return json.data.invsvc_response;
    }
    return null;
  };

  var getProductInfoForSku = function(sku_id) {
    var cart = gg.Cart.current;
    var i    = cart.reservations.length;
    var info = {};

    while (i--) {
      if (gg.Cart.current.reservations[i].sku_id == sku_id) {
        info.sale_id = gg.Cart.current.reservations[i].sale_id;
        info.product_id = gg.Cart.current.reservations[i].product_id;
        break;
      }
    }
    return info;
  };

  var groupIdForCart = function() {
    var ca = fl.Util.readHashedCookie('ca');
    if (ca && ca != "") {
        if (ca.indexOf(".700.") != -1 || ca.indexOf(".705.") != -1) {
            return 700;
        }
    }
    return null;
  };

  var groupIdHashForCart = function() {
    if (gg.Cart.current.useEmployeePrices) {
      return '6a3d2919d503d11b7a39220593bc1131588da1068d994c37184cbb4364ea496b';
    }
  };

  var initializeWaitList = function(msg, sku_id, type) {
    if (fl.Product.Inventory.waitListEnabled) {
      gg.WaitList.initializeForm(msg, sku_id, type, '', true);
      return true;
    } else {
      var d = gg.Cart.getCartDialog();
      d.dialog("option", { height: "auto", title: Locale.add_to_cart_now_sold_out })
       .css({ height: "auto" });
      d.html('');
      return true;
    }
  };

  var inventoryIsOutOfStock = function(inventory_responses) {
    if (!inventory_responses) return false;

    for (var i in inventory_responses) {
      var reservations = inventory_responses[i].data.reservations;
      for (var j in reservations) {
        if (reservations[j].stat == "R") {
          return false;
        }
      }
    }
    return true;
  };

  var removeReservationsWithSku = function(sku_id) {
    var reservations = gg.Cart.current.reservations;

    for(var i = reservations.length-1; i >= 0; i--) {
      if (reservations[i].sku_id == sku_id) {
        reservations.splice(i, 1);
      }
    }
    delete gg.Cart.current.skus[sku_id];
  };

  var sendNewRsvToCartService = function(sale_id, product_id, sku_id, reservation, callback, exchange_mode, opts) {
    var num_reservations = gg.Cart.current ? gg.Cart.current.reservations.length : 0;

    $.post("/cart_service/add_unit", addStandardParams({
      sku_id: sku_id,
      product_id: product_id,
      sale_id: sale_id,
      unit_id: reservation.unit_id,
      expiration: reservation.expiration,
      status: reservation.stat,
      group_id: gg.Cart.userGroupId()
    }, opts),
    HandleCartResponseFactory(function(cart, msg, data) {
      evaluateCartModification(sku_id, data, num_reservations);
      addNotification(cart.skus[sku_id]);

      if (!exchange_mode) {
        gg.Cart.showCartDialog();
      }

      if (callback) {
        callback(cart, data.msg);
      }
    }), "json");
  };

  var showWaitlistFor = function(sku_id, data) {
    if (!data.data || inventoryIsOutOfStock([data])) {
      initializeWaitList(Locale.out_of_stock, sku_id, "out_of_stock");
    } else {
      initializeWaitList(Locale.is_not_available, sku_id, "not_available");
    }
  };

  var updateCartFromService = function(json) {
    var cart_data = getCartFromJson(json);
    if (cart_data) {
      $.extend(gg.Cart.current, {
        skus: cart_data.sku_info || {},
        reservations: cart_data.reservations || [],
        user_discounts: cart_data.user_discounts || [],
        loaded: true
      });

      delete gg.Cart.current.minExpiration;
      gg.Cart.reservationsBySku(); // to populate quantity
      gg.Cart.updatePageCartCount(gg.Cart.current.quantity, gg.Cart.current.reservations.length);
      gg.Cart.current.serverClockDelta = (new Date()).getTime() - (new Date(json.timestamp)).getTime();

      // Poll for missing cart notifications, and add them as needed
      for(var sku_id in gg.Cart.current.skus) {
        var sku = gg.Cart.current.skus[sku_id];
        if (sku.expiration_ms - gg.Cart.current.serverClockDelta > (new Date()).getTime()) {
          var notification = $("div[data-skuid=" + sku_id + "]");
          if (!notification.length) {
            addNotification(sku);
          }
        }
      }
    }
  };
})();




//////////////////////////////////////////////////////////
////  REMOVE THIS ONCE GILT IS ON BLACKBIRD CHECKOUT  ////
//////////////////////////////////////////////////////////
gg.Cart._checkout = function() {
    var cart = gg.Cart.retrieve();

    var n_reservations = cart.reservations.length;
    var numberResponses = 0;

    var i = -1;
    var f = function(existing_reservation) {
        return function(new_reservation) {
            numberResponses++;

            if (new_reservation) {
                existing_reservation.unit_id = new_reservation.unit_id;
                if (0 < new_reservation.unit_id) {
                    existing_reservation.expiration = new_reservation.expiration;
                }
            } else {
                // Inventory service did not have any information about
                // this unit. This occurs if the unit has been depleted
                // and inventory service started after. In this case, use
                // -2 to indicate that the unit is no longer available
                existing_reservation.unit_id = -2;
            }

            if (numberResponses == n_reservations) {
                gg.Cart.persist(cart);
                window.location = '/checkout';
                return false;
            }
        };
    };
    while (++i < n_reservations) {
        var reservation = cart.reservations[i];
        var f2 = f(reservation);
        gg.Inventory.extend_reservation(reservation, f2, f2);
    }
};

gg.Cart.checkout = gg.throttleFunction('cart_checkout', gg.Cart._checkout, 5000);

/* Same functionality as cart.js#gg.Cart.subtotal() */
gg.Cart.subtotal = function() {
  var reservations = this.current.reservations;
  var skus = this.current.skus;
  var subtotal = 0.0;
  for (var i = 0; i < reservations.length; ++i) {
    subtotal += skus[ reservations[i].sku_id ].sku_data.sale_price;
  }
  return subtotal;
};

gg.Cart.hasReturnableItems = function() {
  var returnable = false;
  $.each(this.current.skus, function() {
    if (this.sku_data.returnable) {
      returnable = true;
    }
  });
  return returnable;
};
