var decimalPointDelimiters = '.';

function _isDecSepa(c) {
  return c == '.' || c == ',';
}

function _decCharIdxOf(s, c) {
  var i = s.indexOf(c);
  if (i == -1) {
    if (c == ',') i = s.indexOf('.');
    else if (c == '.') i = s.indexOf(',');
  }
  return i;
}


//
// Formats the number according to the following examples:
//
// 123434        ->    123 434
// 12123123434   ->    12 123 123 434
// 123           ->    123
// 123.123       ->    123,12
// 1123.123      ->    1 123,12
//
// @param n             The number to format
// @param decimals      (optional) The number of decimals to keep
// @param decimapChar   (optional) The character to use as separator
// @param formatString  (optional) A String to format using the formated number as first arg.
//                      May be a loaded UI-text key.
// @param prefixPositiveValueWithPlusChar  (optional) When you want value a positive value to be prefixed with a '+' char like negative values have a '-' char.
// Examples:
//
//  fNum(1234.123)                           : '1 234.12'
//  fNum(1234.123,1)                         : '1 234.1'
//  fNum(1234.123,1,',')                     : '1 234,1'
//  fNum(1234.123,1,',', '€ {0}')            : '€ 1 234,1'
//  fNum(1234.123,0,',', '€ {0}')            : '€ 1 234'
//  fNum(1234.123,0,',', '€ {0}', true)      : '€ +1 234'
//
//
function fNum(n) {
  var d = 2;
  var decimalChar = decimalPointDelimiters;
  var format = undefined;
  var prefixPositiveValueWithPlusChar = undefined;
  var a = arguments;
  if (a.length > 1) d = a[1];
  if (a.length > 2) decimalChar = a[2];
  if (a.length > 3) format = a[3];
  if (a.length > 4) prefixPositiveValueWithPlusChar = a[4];
  if (d > 0) d += 1;
  if (n == undefined) return '';
  if (d == 0) n = Math.round(n);
  var vs = '' + n;
  var i = _decCharIdxOf(vs, decimalChar);
  if (i >= 0 && vs.length > (i + d)) {
    n = new Number(vs.substring(0, (i + d))).valueOf();
    vs = '' + n;
  } else if (d > 0) {
    var zerosMissing;
    if (i < 0) {
      vs = vs + decimalChar;
      zerosMissing = d - 1;
    } else {
      zerosMissing = (i + d) - vs.length;
    }
    for (var z = 0; z < zerosMissing; z++) {
      vs = vs + '0';
    }
  }
  if (vs.length - d > 3) {
    i = _decCharIdxOf(vs, decimalChar);
    var b = 0;
    var tmp = (i > 0 ? vs.substring(i, vs.length) : '');
    for (var y = (vs.length - tmp.length - 1); y >= 0; y--) {
      b++;
      tmp = vs.substring(y, y + 1) + tmp;
      if (b == 3) {
        tmp = ' ' + tmp;
        b = 0;
      }
    }
    vs = tmp;
  }

  if (prefixPositiveValueWithPlusChar && n > 0) {
    vs = "+" + vs;
  }

  if (format && format.length > 3) {
    vs = UiText.get(format, vs);
  }

  return vs;
}

function fEnc(s) {
  return parseInt(Math.round(new Number(s).valueOf() * 1000).toString()).toString(16);
}
function fDec(s) {
  return (new Number(parseInt(s, 16) / 1000).valueOf());
}
function iEnc(s) {
  return parseInt(s).toString(16);
}
function iDec(s) {
  return parseInt(s, 16);
}
var EFloat = function(s) {
  this.s = s;
  this.val = typeof s == 'string' ? fDec(s) : s;
}
var EInt = function(s) {
  this.s = s;
  this.val = typeof s == 'string' ? iDec(s) : s;
}


function isTrue(s) {
  return (s && ('' + s) == 'true')
}

/**
 * Cost - Splits a cost in net, tax and vat.
 */
var Cost = function(net, tax, vat) {
  this.net = new EFloat(net).val;
  this.tax = new EFloat(tax).val;
  this.vat = new EFloat(vat).val;
  this.debug = ''; // Debug Calculation
  this.d = function(s) {
    this.debug += (s + '\n');
  };

  /**
   * Adds the cost object to this instance (this instance will change). Also returns a new Cost object.
   * @param c a Cost object
   * @param boolean if true this function will return a new Cost instance as well as doing its regular duties.
   * @return object undefined or a new Cost object with the performed addition.
   */
  this.add = function(c, returnNewObject) {
    this.net += c.net;
    this.tax += c.tax;
    this.vat += c.vat;
    if (returnNewObject) {return new Cost(this.net, this.tax, this.vat);}
  };

  this.getTotal = function() {
    return this.net + this.tax + this.vat;
  };

  this.negatedTotal = function() {
    return (-1) * this.getTotal();
  };
  /**
   * Clones the current instance and negates all values.
   */
  this.negate = function() {
    var retVal = new Cost(0, 0, 0);
    retVal.net = (-1) * this.net;
    retVal.tax = (-1) * this.tax;
    retVal.vat = (-1) * this.vat;
    return retVal;
  };

  // returns a new object, does not affect instance
  this.plus = function(cost) {
    var net = this.net,tax = this.tax,vat = this.vat;
    return new Cost(net + cost.net, tax + cost.tax, vat + cost.vat);
  };

  // returns a new object, does not affect instance
  this.minus = function(cost) {
    var net = this.net,tax = this.tax,vat = this.vat;
    //console.log([net - cost.net, tax - cost.tax, vat - cost.vat])
    return new Cost(net - cost.net, tax - cost.tax, vat - cost.vat);
  };

  // returns a new object, does not affect instance
  this.copy = function() {
    return new Cost(this.net, this.tax, this.vat);
  }
};

/**
 *
 * @param id discount item id. can be a negative value which indicates that it is only used for display purposes.
 * @param selected is this discount selected
 * @param name a string which describes all selected discounts as one item (generic name for a set of selected discounts)
 * @param discountCost a Cost object - value/worth of this discount
 * @param prodCartId the id of the row where we will display the total for all the selected bonuses
 */
var DiscountItem = function(id, selected, name, discountCost, prodCartId, associatedCartItemId, associatedCartItemCost) {
  this.id = id;
  this.selected = selected;
  this.name = name;
  this.discountCost = discountCost;
  this.prodCartId = prodCartId;
  this.associatedCartItemId = associatedCartItemId;
  this.associatedCartItemCost = associatedCartItemCost;
  this.overflowing = null;

  this.isSelected = function() {
    return isTrue(this.selected);
  };

  this.getDiscountCost = function() {
    return this.discountCost;
  };

  this.getCheckBoxElement = function() {
    return document.getElementById('discountItem_' + this.id + "");
  };

  this.select = function(selected) {
    this.selected = selected;
    var cb = this.getCheckBoxElement();
    if (cb) cb.checked = this.isSelected();
    // alert(cb.checked + ':' + selected);
  };

  this.getAssociatedCartItemCost = function() {
    return this.associatedCartItemCost;
  };

  /**
   * Is this item on item which has enough bonuses to zero the price.
   */
  this.isOverflowing = function() {
    return this.overflowing;
  };

  this.setOverflowing = function(overflow) {
    this.overflowing = overflow;
  }
};

/**
 *
 * cart.add(new CartItem(32,false,undefined,3,'Internetbank (${costTotal})',new Cost('0','0','0')));
 *
 * Represents a Cart Item for a selectable Product.
 */
var CartItem = function(id, selection, validationErrorSelection, groupId, name, cost) {
  this.id = id;
  this.selection = selection;
  this.validationErrorSelection = validationErrorSelection;
  this.groupId = groupId;
  this.name = name;
  this.cost = cost;

  this.getValidationErrorSelection = function() {
    var sel = this.validationErrorSelection;
    return sel == undefined ? sel : isTrue(sel);
  };

  this.isSelected = function() {
    return isTrue(this.selection);
  };

  this.hasSelection = function() {
    return this.selection != undefined;
  };

  this.getCost = function() {
    return this.cost;
  };

  this.getYesElement = function() {
    return document.getElementById('cartitem_' + this.id + "_true");
  };

  this.getNoElement = function() {
    return document.getElementById('cartitem_' + this.id + "_false");
  };

  this.select = function(selected) {
    this.selection = selected;
    var yElem = this.getYesElement();
    var nElem = this.getNoElement();
    showHide('prodRowInfo_' + this.id, this.isSelected(), true);
    showHide('prodAdditionalInfo_' + this.id, this.isSelected(), true);
    if (yElem) yElem.checked = this.isSelected();
    if (nElem) nElem.checked = !this.isSelected();
  };

};

/**
 * var cart = new ShoppingCart(new Cost('36310c', '3eb52', '0'), new Cost('0', '0', '0'), 0, ',');
 * cart.add(new CartItem('VI', false, undefined, 3, 'VI', new Cost('75648', '0', '0')));
 * cart.add(new CartItem('CA', false, undefined, 3, 'CA', new Cost('5f6b8', '0', '0')));
 * cart.add(new CartItem('EC', false, undefined, 3, 'EC', new Cost('75648', '0', '0')));
 * cart.add(new CartItem(30, true, undefined, 3, 'Kontokort/kreditkort', new Cost('0', '0', '0')));
 * cart.add(new CartItem(32, false, undefined, 3, 'Internetbank (${costTotal})', new Cost('0', '0', '0')));
 *
 * This mama is mutable.
 */
var ShoppingCart = function(_baseCost, _additionalCost, _decimals, _decimalSepa) {
  this.baseCost = _baseCost;
  this.additionalCost = _additionalCost;
  this.decimals = _decimals;
  this.decimalSepa = _decimalSepa;
  this.items = new Array();
  this.itemMap = {};
  /**
   * What card is currently selected.
   */
  this.selectedCardType = undefined;
  this.paymentTypeCardId = undefined;

  this.discountItems = new Array();
  this.discountItemMap = {};
  this.discountItemAssociatedMap = {};
  /**
   * Executed on page load.
   * returns {baseCost; additionalCost; discountCosts; discountMap; sumCost}
   */
  this.updatePrices = function() {

    var costs = this.getTotalCost();
    var baseCost = costs.baseCost;
    var baseCostTotal = baseCost.getTotal();
    replaceHtml('dynSum', fNum(baseCostTotal, this.decimals, this.decimalSepa, 'General.Currency.Format'));
    replaceHtml('dynVat', fNum(baseCost.vat, this.decimals, this.decimalSepa, 'General.Currency.Format'));

    var toPay = costs.sumCost.getTotal();
    if (toPay < 0) {
      this.handleAmountBelowZero(costs);
    } else {
      replaceHtml('dynSumTot', fNum(toPay, this.decimals, this.decimalSepa, 'General.Currency.Format'));
    }
    return costs;
  };

  /**
   * If user has selected enough discounts the price to pay on the page will be below zero.
   * We set amount to pay to zero in this case.
   * @param costs {baseCost; additionalCost; discountCosts; discountMap; sumCost}
   */
  this.handleAmountBelowZero = function(costs) {
    replaceHtml('dynSumTot', fNum(0, this.decimals, this.decimalSepa, 'General.Currency.Format'));
  };

  this.updateSelected = function() {
    for (var i = 0; i < this.items.length; i++) {
      var item = this.items[i];
      item.select(item.isSelected());
    }
  };

  this.addCardType = function() {

  };

  this.add = function(cartItem) {
    this.items[this.items.length] = cartItem;
    this.itemMap['' + cartItem.id] = cartItem;
  };

  this.addDiscountItem = function(discItem) {
    this.discountItems[this.discountItems.length] = discItem;
    this.discountItemMap['' + discItem.id] = discItem;
    this.discountItemAssociatedMap['' + discItem.associatedCartItemId] = discItem;
  };
  /**
   *
   * @param id discountItemId
   */
  this.getDiscountItem = function(id) {
    return this.discountItemMap['' + id];
  };
  /**
   *
   * @param cartItemId associatedCartItemId
   */
  this.getDiscountItemFromCartItem = function(cartItemId) {
    return this.discountItemAssociatedMap['' + cartItemId];
  };

  this.selectDiscountItem = function(id, selected) {
    var item = this.getDiscountItem(id);
    if (item) item.select(selected);
    var costs = this.updatePrices();
    this.displayDiscountInfoAndCost(costs, item.prodCartId, item.name);
  };

  this.get = function(id) {
    return this.itemMap['' + id];
  };

  this.hasProduct = function(id) {
    return this.itemMap['' + id];
  };

  this.hasProductGroup = function(groupId) {
    return this.itemsInGrp(groupId).length > 0;
  };

  this.getForGroup = function(groupId) {
    var itemsInGrp = new Array();
    for (var i = 0; i < this.items.length; i++) {
      var item = this.items[i];
      if (item.groupId == groupId) {
        itemsInGrp[itemsInGrp.length] = item;
      }
    }
    return itemsInGrp;
  };

  this.getBaseCost = function() {
    var cost = new Cost(this.baseCost.net,
      this.baseCost.tax,
      this.baseCost.vat);
    for (var i = 0; i < this.items.length; i++) {
      var item = this.items[i];
      cost.d(item.name + '/' + item.cost.getTotal() + ' - ' + item.isSelected() + ' - ' + cost.getTotal());
      if (item.isSelected()) {
        cost.add(item.cost);
        cost.d('   - ADDED   ' + item.cost.getTotal() + ' => ' + cost.getTotal());
      }
    }
    return cost;
  };
  /**
   * @return object-literal object-literal with named properties as: {baseCost; additionalCost; discountCosts; discountMap; sumCost}
   * where sumCost is the final price when all of the previous costs have been added together - can be negative.
   */
  this.getTotalCost = function() {
    var sumCost = this.getBaseCost();
    sumCost.add(this.additionalCost);

    var discountMap = this._getCalculatedDiscountMap();

    var discountCosts = new Cost(0, 0, 0);
    for (var k in discountMap) {
      if (discountMap.hasOwnProperty(k)) {
        discountCosts.add(discountMap[k]);
        sumCost.add(discountMap[k]);
      }
    }

    sumCost.d('   - ADDED ADDITIONAL COST  ' + this.additionalCost.getTotal() + '\n SUM COST ' + sumCost.getTotal() + '\n DISCOUNT ' + discountCosts.getTotal());
    return {
      'baseCost':this.getBaseCost(),
      'additionalCost':this.additionalCost,
      'discountCosts':discountCosts,
      'discountMap':discountMap,
      'sumCost':sumCost
    };
  };
  /**
   * "Private method".
   * Return structure which associates reservationCartItems to calculated applicable discount values.
   * Checks which discount items are selected and adds discounts up to max value (the specific resCartItem's value).
   */
  this._getCalculatedDiscountMap = function() {
    var discountMap = {};
    var u;
    for (u = 0; u < this.discountItems.length; u++) {
      // init here so we dont have to do checks later on.
      discountMap['' + this.discountItems[u].associatedCartItemId] = new Cost(0, 0, 0);
    }

    var i;
    for (i = 0; i < this.discountItems.length; i++) {
      var item = this.discountItems[i];
      if (item.isSelected()) {
        var index = item.associatedCartItemId;
        var resItemAccumulatedDiscount = discountMap[index];
        var discountCost = item.getDiscountCost();
        resItemAccumulatedDiscount.add(discountCost);

        if (resItemAccumulatedDiscount.negatedTotal() > item.associatedCartItemCost.getTotal()) {
          discountMap[index] = item.associatedCartItemCost.negate();
          this._handleDiscountOverflow(item, true);
        } else {
          this._handleDiscountOverflow(item, false);
          discountMap[index] = resItemAccumulatedDiscount;
        }
        //console.log([discountCost.net, resItemAccumulatedDiscount.net, item.associatedCartItemCost.net, discountMap[index].net])
        //cost.d(item.name + '/' + item.discountCost.getTotal() + ' - ' + item.isSelected() + ' - ' + cost.getTotal());
        //cost.d('   - ADDED DISCOUNT  ' + item.discountCost.getTotal() + ' => ' + cost.getTotal());
      }
    }
    return discountMap;
  };
  /**
   * Change what is selectable for a specific discountItemGroup so that users cannot (in theory) "throw away" discounts.
   * @param discountItem item which causes zero value for product
   * @param overflowing enable or disable the input element(s), also value set for "overflowing" on associated items
   */
  this._handleDiscountOverflow = function(discountItem, overflowing) {
    //console.log([discountItem.id, discountItem.discountCost.getTotal(), overflowing, discountItem.associatedCartItemId, discountItem.overflowing])
    var cartItemId = discountItem.associatedCartItemId;
    var i, prefix = "discountItem_", inputRowPrefix = "discRow_", discountItems = this.discountItems;
    for (i = 0; i < discountItems.length; i++) {
      var item = discountItems[i];
      if (item.associatedCartItemId == cartItemId) {
        var input = document.getElementById(prefix + item.id);
        if (input) { // when payemtent page
          if (!input.checked) {
            input.disabled = overflowing;
          }
          var DM = YAHOO.util.Dom;
          input.disabled ?
          DM.removeClass(inputRowPrefix + item.id, "pointer") :
          DM.addClass(inputRowPrefix + item.id, "pointer");
          input.value = input.checked ? "true" : "false";
          item.setOverflowing(overflowing);
        }
      }
    }
  };

  /**
   * Should be run on page reload to fix possible browser "quirks" remembering the state of check-boxes.
   */
  this._fixInitOverflowSimple = function() {
    var i, prefix = "discountItem_", discountItems = this.discountItems;
    for (i = 0; i < discountItems.length; i++) {
      var item = discountItems[i];
      var input = document.getElementById(prefix + item.id);
      input.disabled = false;
    }
  };
  /**
   * Should be run on page reload to fix possible browser "quirks" remembering the state of check-boxes.
   * This version should be chosen over _fixInitOverflowSimple if a discount has been selected or updatePrices has been run,
   * as it makes checks to not make errors. (if _fixInitOverflowSimple works in all scenarios we can remove this function.)
   */
  this._fixInitOverflow = function() {

    var i, prefix = "discountItem_", groups = {}, discountItems = this.discountItems;
    for (i = 0; i < discountItems.length; i++) {
      var item = discountItems[i];
      var input = document.getElementById(prefix + item.id);
      if (input.disabled) {
        groups["" + item.associatedCartItemId] = 'x';
      }
    }
    var k;
    for (i in groups) {// for each product which has discounts.
      if (groups.hasOwnProperty(i)) {
        var enable = true;
        var groupItems = [];
        for (k = 0; k < discountItems.length; k++) {
          var item = discountItems[k];
          groupItems.push(item);
          if (item.isOverflowing()) {
            enable = false;
            break;
          }
        }
        if (enable) {
          for (k = 0; k < groupItems.length; k++) {
            var item = groupItems[k];
            document.getElementById(prefix + item.id).disabled = false;
          }
        }
      }
    }
  };

  this.select = function(id, selected) {
    this.selectProductUpSell(id, selected);
    this.selectCheckTarget(id, selected, null, false);
  };

  this.selectProductUpSell = function(id, selected) {
    updateUpSellBookSetUi(id, selected);
  };

  this.selectCheckTarget = function(id, selected, eventTarget, paymentTypeIsCard) {
    var item = this.get(id);
    selected = isTrue(selected);
    if (selected) {
      var itemsInGrp = this.getForGroup(item.groupId);
      for (var i = 0; i < itemsInGrp.length; i++) {
        var tmpItem = itemsInGrp[i];
        tmpItem.select(false);
      }
    }

    item.select(selected);

    this.checkPaymentType(paymentTypeIsCard, id);

    this.updatePrices();

    if (eventTarget) {
      eventTarget.checked = true;
    }

  };

  /**
   * @param paymentTypeIsCard
   * @param id
   */
  this.initCardPayment = function(paymentTypeIsCard, id) {
    if (paymentTypeIsCard) {
      this.checkPaymentType(paymentTypeIsCard, id);
      showHide('prodRowInfo_' + id, false, 'none'); // Initially hide credit card information row.
    }
  };

  /**
   * @param id e.g. String code of the card type.
   */
  this.getCardTypeItem = function(id) {
    for (var i = 0; i < this.items.length; i++) {
      var item = this.items[i];
      if (item.id == id) {
        return this.items[i];
      }
    }
  };

  /**
   * Include the card type in the cart item list, to be included in the total sum.
   *
   * @param id String, code of the card type.
   * @param selected boolean, set it as selected.
   */
  this.selectCardType = function(id, selected) {
    var item = this.getCardTypeItem(id);
    if (item) {
      if (this.selectedCardType == undefined) {
        this.selectedCardType = item;
      } else {
        this.selectedCardType.select(false);
      }
      item.select(selected);
      this.selectedCardType = item;
      this.updatePrices();
      this.displayCardPaymentInfoAndCost(item);
    }
  };

  /**
   * When card payement is selected, and a card type was previously selected, then include the price in the total sum.
   */
  this.cardTypeIsSelected = function() {
    if (this.selectedCardType != undefined) {
      this.selectedCardType.select(true);
    } else if (this.paymentTypeCardId != undefined) {
      // Hide credit card information row, since no card type is selected.
      showHide('prodRowInfo_' + this.paymentTypeCardId, false, 'none');
    }
  };

  this.checkPaymentType = function(paymentTypeIsCard, id) {
    if (paymentTypeIsCard) {
      this.paymentTypeCardId = id;
      this.cardTypeIsSelected();
    } else {
      this.paymentTypeCardId = undefined;
    }
  };

  /**
   * @param item CreditCard Item
   */
  this.displayCardPaymentInfoAndCost = function(item) {
    var e = this.get(this.paymentTypeCardId);
    if (e) e.select(true);
    // update price in the summary component
    replaceHtml('prodRowAmountInfo_' + this.paymentTypeCardId, fNum(item.cost.getTotal(), this.decimals, this.decimalSepa, 'General.Currency.Format'));
    replaceHtml('prodRowDescriptionInfo_' + this.paymentTypeCardId, item.name);
  };
  /**
   * Discount Item
   * Finds out how we should display selected discounts in its own summary as well as the general cart summary.
   * @param costs {baseCost; additionalCost; discountCosts; discountMap; sumCost}
   * @param prodCartId the id of the row where we will display the total for all the selected bonuses
   * @param name the 'heading" for the sum of the selected discounts.
   */
  this.displayDiscountInfoAndCost = function(costs, prodCartId, name) {

    var cost = new Cost(0, 0, 0);
    var displayRow = false;
    var i;
    for (i = 0; i < this.discountItems.length; i++) {
      var item = this.discountItems[i];
      cost.d(item.name + '/' + item.discountCost.getTotal() + ' - ' + item.isSelected() + ' - ' + cost.getTotal());
      if (item.isSelected()) {
        cost.add(item.discountCost);
        cost.d('   - ADDED DISCOUNT  ' + item.discountCost.getTotal() + ' => ' + cost.getTotal());
        displayRow = true;
      }
    }
    // display sum of all discounts in summary component
    if (displayRow) {
      showHide('prodRowInfo_' + prodCartId, true, 'none');
      replaceHtml('prodRowAmountInfo_' + prodCartId, fNum(costs.discountCosts.getTotal(), this.decimals, this.decimalSepa, 'General.Currency.Format'));
      replaceHtml('prodRowDescriptionInfo_' + prodCartId, name);
    } else {
      showHide('prodRowInfo_' + prodCartId, false, 'none');
    }

    // update discount selection component prices
    this.updateDisplayedDiscounts(costs.discountMap);

  };

  this.updateDisplayedDiscounts = function(discountMap) {
    for (var cartItemId in discountMap) {
      if (discountMap.hasOwnProperty(cartItemId)) {
        // "calculate" beforeDiscountPrice, discountPrice, discountedTotalPrice.
        var cartItemCost = this.getDiscountItemFromCartItem(cartItemId).getAssociatedCartItemCost();

        var discountCost = discountMap[cartItemId];
        var tmp = new Cost(0, 0, 0);
        var discountedTotal = tmp.add(cartItemCost, true).add(discountCost, true);
        //console.log([cartItemId, cartItemCost, discountCost, discountedTotal])
        // display the prices
        replaceHtml("discountBefore_" + cartItemId, fNum(cartItemCost.getTotal(), this.decimals, this.decimalSepa, 'General.Currency.Format'));
        replaceHtml("dizcount_" + cartItemId, "&ndash;" + fNum(discountCost.negate().getTotal(), this.decimals, this.decimalSepa, 'General.Currency.Format'));
        replaceHtml("discountedTotal_" + cartItemId, fNum(discountedTotal.getTotal(), this.decimals, this.decimalSepa, 'General.Currency.Format'));
      }
    }
  };

  this.ensureDiscountSelection = function() {
    this._fixInitOverflowSimple();
    var item;
    for (var i = 0; i < this.discountItems.length; i++) {
      item = this.discountItems[i];
      item.select(item.isSelected());
    }
    var costs = this.updatePrices();
    //this._fixInitOverflow();
    // item has two values which are the same for all items: prodcartid and name.
    this.displayDiscountInfoAndCost(costs, item.prodCartId, item.name);
  };
};

function updateUpSellBookSetUi(itemTypeId, selected) {
  var bookId = 'upsell_book_' + itemTypeId;
  var unBookId = 'upsell_already_booked_' + itemTypeId;
  if ((typeof selected == 'string' && selected == 'true') || selected === true) { // IT is a string for some reason
    setVisible(unBookId, true);
    setHidden(bookId, true);
  } else {
    setVisible(bookId, true);
    setHidden(unBookId, true);
  }
}

function upSellClicked(itemTypeId, selected, noSelectionComponentUrl) {
  if (getExtraProductSelectionField(itemTypeId)) {
    cart.select(itemTypeId, selected);
  } else {
    setCookie('selectExtraProduct', itemTypeId);
    window.location = noSelectionComponentUrl;
  }

}

function getExtraProductSelectionField(itemTypeId) {
  var e = getObj("cartitem_" + itemTypeId + "_true");
  return e;
}

function upSellIsInPaymentStep(itemTypeId) {
  if (getExtraProductSelectionField(itemTypeId)) return true;
  else return false;
}

