﻿// This shopping cart uses a cookie to store its contents so that it survives page changes during a session
// An object datastructure representing the cart contents is generated on every operation.
//
// This may seem like a lot of work, but it is really quite quick, and it's much easier to
// understand the code...


// --------------------------------------------------------------------------
// Language dependent string constants
// --------------------------------------------------------------------------
var g_lang = { no:0, en:1 };

var g_ILabel   = [ "Kode",                    "Code" ];
var g_DLabel   = [ "Produkt",                 "Product" ];
var g_QLabel   = [ "Antall",                  "Number" ];
var g_PLabel   = [ "Pris pr. stk.",           "Price Each" ];
var g_RLabel   = [ "&nbsp;",                  "&nbsp;" ];
var g_RButton  = [ "Fjern",                   "Remove" ];
var g_SUB      = [ "Sum",                     "Sum" ];
var g_SHIP     = [ "Frakt ",                  "Postage and Packing " ];
var g_NORWAY   = [ "Til Norge",               "To Norway" ];
var g_EUROPE   = [ "Til Europa",              "To Europe" ];
var g_WORLD    = [ "Til resten av verden",    "To the rest of the world" ];
var g_TAX      = [ "MVA",                     "VAT" ];
var g_TOT      = [ "Totalsum",                "Total Sum" ];
var g_ErrQty   = [ "Ugyldig antall",          "Invalid number" ];
var g_NewQty   = [ "Vennligst angi antall:",  "Please enter number of copies" ];
var g_Empty    = [ "tom",                     "empty" ];
var g_Handling = [ " (pluss frakt)",          " (plus P&P)" ];
var g_Pcs      = [ " stk ",                   " " ];
var g_Explain  = [ "Vis fraktberegning ",     "Show postage details" ]

var MonetarySymbol = "kr. ";

var strILabel;
var strDLabel;
var strQLabel;
var strPLabel;
var strRLabel;
var strRButton;
var strSUB;
var strSHIP;
var strNORWAY;
var strEUROPE;
var strWORLD;
var strTAX;
var strTOT;
var strErrQty;
var strNewQty;
var strEmpty;
var strPlusHandling;
var strPcs;
var strExplainPostage;

// --------------------------------------------------------------------------
// Utility functions
// --------------------------------------------------------------------------

// Formats Amount to #.## format
// 55.999 => 5599.9 ==> 5600 ==> 56.00
function moneyFormat(amount)
{
  var fval = Math.round(amount * 100.0);
  var cents = fval % 100;
  var dollars = Math.floor(fval / 100.0);
  var sc = "" + cents;
  if (sc.length < 2)
    sc += "0";

  return dollars + "," + sc;
} // end moneyFormat()



function getQuantityFromAddToCartButton(button)
{
  // Assumes that the quantity-field resides in the tablecell preceding the table cell containing the button
  //       IMG      TD           TR        TD      "Antall:"     INPUT
  var td = button.parentNode.parentNode.firstChild;
  while (td && td.nodeType == 3) // On FireFox, the first child of the table row could be text!!!!
    td = td.nextSibling;
  return ensureNumeric(td.lastChild.value);
} // end getQuantityFromAddToCartButton()



function ensureNumeric(checkString)
{
  var strNewNumber = "";

  for (var i = 0; i < checkString.length; i++)
  {
    ch = checkString.charAt(i); // checkString[i] does not work everywhere...!!!???
    if (ch >= "0" && ch <= "9")
      strNewNumber += ch;
  }

  if (strNewNumber.length < 1)
    strNewNumber = "1";

  return strNewNumber;
} // end ensureNumeric()



function gtDistributor(name, product_ids, price_calculator)
{
  // Initialized one and for all
  this.m_name             = name;
  this.m_family_ids       = product_ids;
  this.m_price_calculator = price_calculator;

  // Updated whenever neccessary to reflect items in shoppingcart
  this.m_count            = 0;
  this.m_price            = 0.0;
  this.m_shipping         = 0.0;
} // end gtDistributor()


GTDISTRIBUTOR = gtDistributor.prototype;


GTDISTRIBUTOR.clear = function gtDistributor_clear()
{
  this.m_count    = 0;
  this.m_price    = 0.0;
  this.m_weight   = 0.0;
  this.m_shipping = 0.0;
}; // end clear()



GTDISTRIBUTOR.addItem = function gtDistributor_addItem(item)
{
  this.m_count    += item.m_quantity;
  this.m_price    += item.m_quantity * item.m_price;
  this.m_weight   += item.m_quantity * item.m_weight;
  this.m_shipping += item.m_quantity * item.m_shipping;
}; // end addItem()



GTDISTRIBUTOR.calcPriceFromWeightInG = function gtDistributor_calcPriceFromWeightInG(region)
{
  return this.m_price_calculator.calcPriceFromWeightInG(this.m_weight, region);
} // end calcPriceFromWeightInG()



GTDISTRIBUTOR.renderExplanation = function gtDistributor_renderExplanation(region)
{
  return this.m_price_calculator.renderExplanation(this.m_weight, region);
}; // end renderExplanation()



// --------------------------------------------------------------------------
// Class representing one item in the shopping cart
// --------------------------------------------------------------------------

function gtShoppingItem(id, family, quantity, name, price, shipping, weight, info, discount_percent, add_vat)
{
  if (arguments.length == 1)
  {
    // Only one parameter: parse cookie value
    var fields = id.split("|");
    this.m_id               = fields[0];
    this.m_family           = fields[1];
    this.m_quantity         = parseInt(fields[2]);
    this.m_name             = fields[3];
    this.m_price            = parseFloat(fields[4]);
    this.m_shipping         = parseFloat(fields[5]);
    this.m_weight           = parseFloat(fields[6]);
    this.m_info             = fields[7];
    this.m_discount_percent = parseFloat(fields[8]);
    this.m_add_vat          = fields[9];
  }
  else
  {
    this.m_id               = id               ? id   : "";
    this.m_family           = family           ? family : 0;
    this.m_name             = name             ? name : "";
    this.m_info             = info             ? info : "";
    this.m_quantity         = quantity         ? parseInt  (quantity)         : 0;
    this.m_price            = price            ? parseFloat(price)            : 0.0;
    this.m_shipping         = shipping         ? parseFloat(shipping)         : 0.0;
    this.m_weight           = weight           ? parseFloat(weight)           : 0.0;
    this.m_discount_percent = discount_percent ? parseFloat(discount_percent) : 0.0;
    this.m_add_vat          = add_vat          ? add_vat                      : false;
  }
//alert("new gtShoppingItem: " + this.toString());
} // end gtShoppingItem::Constructor



gtShoppingItem.prototype.toString = function gtShoppingItem_toString()
{
  return this.m_id + "|" + this.m_family + "|" + this.m_quantity + "|" + this.m_name + "|" + this.m_price + "|" + this.m_shipping + "|" + this.m_weight + "|" + this.m_info + "|" + this.m_discount_percent + "|" + this.m_add_vat;
} // end toString()


gtShoppingItem.prototype.getTooltip = function gtShoppingItem_getTooltip()
{
  var words = this.m_name.split(":");
  return this.m_quantity + strPcs + words[0] + ": " + MonetarySymbol + this.m_price * this.m_quantity + strPlusHandling;
}; // end getTooltip()



// --------------------------------------------------------------------------
// Class representing the shopping cart
// --------------------------------------------------------------------------

function gtShoppingCart(name_of_variable)
{
  this.m_cookie            = new gtCookie(document);
  this.m_cookie.m_path     = "/";
  this.m_name              = "gtShoppingCart";
  this.m_region            = gtShoppingCart.NORWAY;
  this.m_name_of_variable  = name_of_variable;
  this.m_items             = [];
  this.m_loaded            = false;
  this.m_evt_loaded        = new gtEventHandler();
  this.m_evt_add           = new gtEventHandler();
  this.m_evt_del           = new gtEventHandler();
  this.m_evt_change_qty    = new gtEventHandler();
  this.m_evt_changed       = new gtEventHandler();
  this.fromCookie();

  this.m_distributors = [
    new gtDistributor("Sentraldistribusjon", [1, 2, 3, 4, 6], new gtPriceCalculator(this, gtPriceCalculator.SENTRALDITRIBUSJON)),
    new gtDistributor("Kartagena",           [5],             new gtPriceCalculator(this, gtPriceCalculator.KARTAGENA))
  ];
} // end gtShoppingCart::Constructor()

GTSHOPPINGCART = gtShoppingCart.prototype;



// Statics
gtShoppingCart.NORWAY = 0;
gtShoppingCart.EUROPE = 1;
gtShoppingCart.WORLD  = 2;



GTSHOPPINGCART.getShippingCost = function gtShoppingCart_getShippingCost(distributor)
{
  // Compute a total shipping cost by adding the price of shipping "total_weight" grammes to total_shiping
  var order_lines = this.m_items.length;
  var cost = 0.0;
  cost += order_lines * 0.0;
  cost += distributor.m_shipping;
  cost += distributor.calcPriceFromWeightInG(this.m_region);

  return cost;
}; // end getShippingCost()



GTSHOPPINGCART.initLanguageStrings = function gtShoppingCart_initLanguageStrings(lang_code)
{
  var c = g_lang[lang_code];
  strILabel         = g_ILabel  [c];
  strDLabel         = g_DLabel  [c];
  strQLabel         = g_QLabel  [c];
  strPLabel         = g_PLabel  [c];
  strRLabel         = g_RLabel  [c];
  strRButton        = g_RButton [c];
  strSUB            = g_SUB     [c];
  strSHIP           = g_SHIP    [c];
  strNORWAY         = g_NORWAY  [c];
  strEUROPE         = g_EUROPE  [c];
  strWORLD          = g_WORLD   [c];
  strTAX            = g_TAX     [c];
  strTOT            = g_TOT     [c];
  strErrQty         = g_ErrQty  [c];
  strNewQty         = g_NewQty  [c];
  strEmpty          = g_Empty   [c];
  strPlusHandling   = g_Handling[c];
  strPcs            = g_Pcs     [c];
  strExplainPostage = g_Explain [c];
}; // end initLanguageStrings()



// Format of shoppingcart cookie:
//   item1$item2$...$itemN
// Where itemN has the format:
//   id|quantity|name|price|shipping|info
GTSHOPPINGCART.fromCookie = function gtShoppingCart_fromCookie()
{
  var val = this.m_cookie.getCrumb(this.m_name);
  if (!val)
    return;
  var items = val.split("$");
  for (var i = 0; i < items.length; i++)
  {
    var item  = new gtShoppingItem(items[i]);
    var found = this.find(item);
    if (!found)
      this.m_items.push(item);
  }
  val = this.m_cookie.getCrumb(this.m_name + "_region");
  if (val)
    this.m_region = parseInt(val);
  this.m_evt_changed.raise(this);
} // end fromCookie()



GTSHOPPINGCART.toCookie = function gtShoppingCart_toCookie()
{
  var val = "";
  for (var i = 0; i < this.m_items.length; i++)
  {
    if (i > 0)
      val += "$";
    val += this.m_items[i].toString();
  }
  this.m_cookie.setCrumb(this.m_name, val);
  this.m_cookie.setCrumb(this.m_name + "_region", this.m_region);
} // end toCookie()



GTSHOPPINGCART.empty = function gtShoppingCart_empty()
{
  this.m_items.length = 0;
  this.m_cookie.setCrumb(this.m_name, "");
  this.m_evt_changed.raise(this);
} // end empty()



GTSHOPPINGCART.find = function gtShoppingCart_find(item)
{
  for (var n = 0; n < this.m_items.length; n++)
  {
    var found = this.m_items[n];
    if (found.m_id == item.m_id)
      return found;
  }
  return null;
} // end find()



GTSHOPPINGCART.add = function gtShoppingCart_add(id, family, quantity, name, price, shipping, weight, info, discount_percent, add_vat)
{
//alert("id:" + id + ", qty:" + quantity + ", name:" + name + ", price:" + price + ", shp: " + shipping + ", wgt: " + weight + ", inf:" + info + ", discount:" + discount_percent + ",add_vat:" + add_vat);
  var item = new gtShoppingItem(
    id,
    family,
    quantity,
    name,
    price            ? price            : 0.0,
    shipping         ? shipping         : 0.0,
    weight           ? weight           : 0.0,
    info             ? info             : "",
    discount_percent ? discount_percent : 0.0,
    add_vat          ? add_vat          : false);
//alert("add: " + item.toString());
    
  var found = this.find(item);
  if (found)
  {
    found.m_quantity += item.m_quantity;
    this.m_evt_change_qty.raise(found);
  }
  else
  {
    this.m_items.push(item);
    this.m_evt_add.raise(item);
  }
  this.m_evt_changed.raise(this);
  this.toCookie();  // Save it!
} // end add()



GTSHOPPINGCART.del = function gtShoppingCart_del(i)
{
  this.m_items.splice(i, 1);
  this.m_evt_del.raise(i);
  this.m_evt_changed.raise(this);
  this.toCookie();  // Save it!
} // end del()



GTSHOPPINGCART.changeQuantity = function gtShoppingCart_changeQuantity(i, quantity)
{
  var item = this.m_items[i];
  item.m_quantity = quantity;
  this.m_evt_change_qty.raise(item);
  this.m_evt_changed.raise(this);
  this.toCookie();  // Save it!
} // end changeQuantity()



function getShippingString(distributor, region)
{
  var strReg;
  switch (region)
  {
    case gtShoppingCart.NORWAY: strReg = strNORWAY; break;
    case gtShoppingCart.EUROPE: strReg = strEUROPE; break;
    case gtShoppingCart.WORLD:  strReg = strWORLD;  break;
  }

  return strSHIP + strReg + " (" + distributor.m_name + ")";
} // end getShippingString()



GTSHOPPINGCART.changeRegion = function gtShoppingCart_changeRegion(region)
{
  this.m_region = region;
  this.displayTotals();
  for (var distr_idx in this.m_distributors)
  {
    var distributor = this.m_distributors[distr_idx];
    if (distributor.m_count > 0)
    {
      var el = gtGetElementById("tdPaPText" + distr_idx);
      el.innerHTML = getShippingString(distributor, region);
    }
  }
  this.m_evt_change_qty.raise(null);  // Update sums (no item passed since nothing has changed, really)
  this.toCookie();  // Save it!
}; // end changeRegion()



GTSHOPPINGCART.render = function gtShoppingCart_render(editable)
{
  var s =
    "<table class='gtShoppingCart' cellspacing='0'><tr>" +
    "<td width='60' class='gtShoppingCartHader'><b>"  + strILabel + "</b></td>" +
    "<td class='gtShoppingCartHader'><b>" + strDLabel + "</b></td>" +
    "<td width='50' class='gtShoppingCartHader'><b>"  + strQLabel + "</b></td>" +
    "<td width='80' class='gtShoppingCartHader' align='right'><b>"+strPLabel+"</b></td>" +
    "<td width='50' class='gtShoppingCartHader'><b>" + strRLabel + "</b></td></tr>";
    
  if (this.m_items.length == 0)
    s += "<tr><td colspan='6' class='gtShoppingCartEntry'><center><b>Handlekurven din er tom</b><br></center></td></tr>";

  for (i = 0; i < this.m_items.length; i++ )
  {
    var item  = this.m_items[i];
    s += "<tr>";
    s += "<td class='gtShoppingCartEntry'>" + item.m_id + "</td>";
    s += "<td class='gtShoppingCartEntry'>" + item.m_name + "</td>";
    s += "<td class='gtShoppingCartEntry'>";
    if (editable)
      s += "<input class='gtShoppingCartEntry' type='text' name='Q' size='2' value='" + item.m_quantity + "' onChange='" + this.m_name_of_variable + ".guiChangeQuantity(this);'>";
    else
      s += item.m_quantity;
    s += "</td>";
    s += "<td class='gtShoppingCartEntry' align='right'>" + MonetarySymbol + moneyFormat(item.m_price) + "</td>";
    s += "<td class='gtShoppingCartEntry' align='right'>";
    if (editable)
      s += "<a href='javascript:' onClick='" + this.m_name_of_variable + ".removeFromCart(this.parentNode.parentNode)' class='gtShoppingCartEntry'>" + strRButton + "</a>";
    s += "</td>";
    s += "</tr>";
  }

  this.computeTotals();
  for (var d in this.m_distributors)
    s += this.renderShipping(d);

  s += "<tr>";
  s += "<td class='gtShoppingCartTotal' colspan='2'><b>" + strTOT + "</b></td>";
  s += "<td id='gtShoppingCartCount' class='gtShoppingCartTotal'>" + this.m_total_count + "</td>";
  s += "<td id='gtShoppingCartTotal' class='gtShoppingCartTotal' align='right'><b>" + MonetarySymbol + moneyFormat(this.m_total_cost + this.m_total_shipping_cost) + "</b></td>";
  s += "<td class='gtShoppingCartTotal'>&nbsp;</td>";
  s += "</tr>";
  
  s += "</table>";
  return s;
} // end render()



GTSHOPPINGCART.renderShipping = function gtShoppingCart_renderShipping(distr_idx)
{
  var distributor = this.m_distributors[distr_idx];
  if (distributor.m_count == 0)
    return "";

  var s = "<tr>";
  s += "<td id='tdPaPText" + distr_idx + "' class='gtShoppingCartEntry' colspan='3'>";
  s += "<a title='" + strExplainPostage + "' onClick='" + this.m_name_of_variable + ".explainPostage(this.parentNode.parentNode.parentNode, " + distr_idx + ");' href='javascript:;'>";
  s += getShippingString(distributor, this.m_region) + "</a></td>";
  s += "<td id='gtShoppingCartShipping" + distr_idx + "' class='gtShoppingCartEntry' align='right'>";
  s += MonetarySymbol + moneyFormat(this.getShippingCost(distributor)) + "</td>";
  s += "<td class='gtShoppingCartEntry" + distr_idx + "' align='center'><a title='" + strExplainPostage + "' onClick='" + this.m_name_of_variable + ".explainPostage(this.parentNode.parentNode.parentNode, " + distr_idx + ");' href='javascript:;'>?</a></td>";
  s += "</tr>";
  return s;
}; // end renderShipping()



GTSHOPPINGCART.explainPostage = function gtShoppingCart_explainPostage(table, distr_idx)
{
  var div = gtGetElementById("divExplanation");
  if (!div)
  {
    div = document.createElement("div");
    div.id = "divExplanation";
    document.body.appendChild(div);
    div.style.position = "absolute";
    div.style.top    = gtGetTop(table) + gtGetHeight(table) + 10 + "px";
    div.style.left   = "200px";
    div.style.width  = "550px";
    div.style.textAlign = "right"; // So the button ends up to the right...
    div.style.border = "solid 1px #888888";
    div.style.backgroundColor = "#eeeeee";
  }
  this.computeTotals();
  div.innerHTML = this.m_distributors[distr_idx].renderExplanation(this.m_region);
} // end explainPostage()



GTSHOPPINGCART.closeExplanation = function gtShoppingCart_closeExplanation(div)
{
  div.parentNode.removeChild(div);
}; // end closeExplanation()



GTSHOPPINGCART.guiChangeQuantity = function gtShoppingCart_guiChangeQuantity(txtQuantity)
{
  var tr = txtQuantity.parentNode.parentNode;
  var item_number = tr.rowIndex - 1; // Don't count header row...
  var new_count = parseInt(txtQuantity.value);
  if (new_count == 0)
  {
    this.removeFromCart(tr);
    return;
  }
  
  this.changeQuantity(item_number, new_count);
//  // This really displayed a sub-total, but the column title is "price for each"
//  var item = this.m_items[item_number];
//  txtQuantity.parentNode.nextSibling.innerHTML = MonetarySymbol + moneyFormat(item.m_quantity * item.m_price);
  this.displayTotals();
} // end guiChangeQuantity()



GTSHOPPINGCART.displayTotals = function gtShoppingCart_displayTotals()
{
  this.computeTotals();
  for (var d in this.m_distributors)
  {
    var distributor = this.m_distributors[d];
    if (distributor.m_count > 0)
      gtGetElementById("gtShoppingCartShipping" + d).innerHTML = MonetarySymbol + moneyFormat(distributor.m_shipping + this.getShippingCost(distributor));
  }

  gtGetElementById("gtShoppingCartCount").innerHTML = "<b>" + this.m_total_count + "</b>";
  gtGetElementById("gtShoppingCartTotal").innerHTML = "<b>" + MonetarySymbol + moneyFormat(this.m_total_cost + this.m_total_shipping_cost) + "</b>";
} // end displayTotals()



GTSHOPPINGCART.removeFromCart = function gtShoppingCart_removeFromCart(tr)
{
  var item_number = tr.rowIndex - 1; // Don't count header row...
  this.del(item_number);

  gtGetElementById("tdShoppingCart").innerHTML = this.render(true);
} // end removeFromCart()



GTSHOPPINGCART.findDistributor = function gtShoppingCart_findDistributor(family_id)
{
  for (var d in this.m_distributors)
  {
    var distributor = this.m_distributors[d];
    for (var i in distributor.m_family_ids)
    {
      if (distributor.m_family_ids[i] == family_id)
        return distributor;
    }
  }
  return null;
}; // end findDistributor()



GTSHOPPINGCART.computeTotals = function gtShoppingCart_computeTotals()
{
  // Reset all counts for each distributor
  for (var d in this.m_distributors)
    this.m_distributors[d].clear();

  // Accumulate info for all items into relevant distributors
  for (var i = 0; i < this.m_items.length; i++)
  {
    var item = this.m_items[i];

    var distributor = this.findDistributor(item.m_family)
    if (!distributor)
      alert("gtShoppingCart_computeTotals: Couldn't find distributor for product family " + item.m_family);

    distributor.addItem(item);
  }

  this.m_total_count         = 0;
  this.m_total_cost          = 0;
  this.m_total_shipping_cost = 0;

  for (var d in this.m_distributors)
  {
    var distributor = this.m_distributors[d];
    this.m_total_count         += distributor.m_count;
    this.m_total_cost          += distributor.m_price;
    this.m_total_shipping_cost += this.getShippingCost(distributor)
  }
} // end computeTotals()
