function cartClass(){
  this.ship = new shipClass();
  this.tax = new Array();
  this.item = new Array();
  this.total = 0;
  this.subTotal = 0;
  this.addrShip = new addrClass();
  this.addrBill = new addrClass();
  this.tax = new Array();
  this.coupon = ""; // a space delimited list of specific coupons to apply
}

function addrClass(){
  // From this object, pretty much everything is stored in the cookie.
  // Only in the billing address you'll find an email and subsNews and AASP.
  // Only in the shippping address you'll find the note.
  // So far, we don't use street2 at all.
  this.fName = "";
  this.lName = "";
  this.cName = "";
  this.street1 = "";
  this.street2 = "";
  this.city = "";     // eg Calgary
  this.province = ""; // eg AB
  this.postCode = ""; // eg t2y2x7
  this.country = "ca";// eg us
  this.phone = "";    // eg 4032502525
  this.fax = "";      // eg 4032574382
  this.note = "";     // eg deliver to back door
  this.email = "";
  this.subsNews = 0;  // newsletter subscription option
  this.membership = ""; // could belong to aasp, etc. in this a space-delimited list
}

function cartItemClass(){
  // From this object, only sku and qty are stored in the cookie.
  this.sku = "";
  this.qty = 0;
  this.unitCost = 0;
  this.discCost = 0;
  this.extCost = 0;
}

function shipClass(){
  // From this object, only the meth value is stored in the cookie.

  this.cost = -1; // -1 means that shipping cost is $0.00 and that
  // it should not be displayed in the html of the
  // cart or sent to Moneris
  this.meth = 0; // 0: no ship, 1: Makeda Courier, 2: CP ground,
  // 3: CP express, 4: greyhound et. al.
}

function cartTaxClass(){
  // From this object, nothing is stored in the cookie.
  this.name = "";
  this.rate = 0.0;
  this.cost = 0;
}

var cart = new cartClass();

function cart_addItem( itemSku ){
  var i;
  var found =  0;

  // TODO: Check for sanity: is this an actual item?

  // Determine if an item with this sku is alredy in the cart
  for( i=0; i < cart.item.length; i++ ){
    if( cart.item[i].sku == itemSku ){
      found = 1;
      break;
    }
  }

  // Either increment the quantity or add as a new item
  if( found ){
    cart.item[i].qty++;
  }
  else{
    cart.item[i] = new cartItemClass();
    cart.item[i].sku = itemSku;
    cart.item[i].qty = 1;
  }
}

function cart_removeItem( itemSku ){
  var i;
  var found =  0;

  // Determine if an item with this sku is alredy in the cart
  for( i=0; i < cart.item.length; i++ ){
    if( cart.item[i].sku == itemSku ){
      found = 1;
      break;
    }
  }

  if( found ){
    // remove array element by splicing in nothing into its place
    cart.item.splice(i,1);
  }
  else{
    return 1;
  }
}

function cart_getQty( itemSku ){
  var i;
  var found =  0;

  // Determine if an item with this sku is alredy in the cart
  for( i=0; i < cart.item.length; i++ ){
    if( cart.item[i].sku == itemSku ){
      found = 1;
      break;
    }
  }

  // Return the quantity, or error 1 if it's not in the cart
  if( found ){
    return cart.item[i].qty;
  }
  else{
    return 1;
  }
}

function cart_changeQty( itemSku, newQty ){
  var i;
  var found = 0;

  // Determine if an item with this sku is alredy in the cart
  for( i=0; i < cart.item.length; i++ ){
    if( cart.item[i].sku == itemSku ){
      found = 1;
      break;
    }
  }

  if( found ){
    cart.item[i].qty = newQty;
    if( cart.item[i].qty <= 0 ){
      cart_removeItem( itemSku );
    }
  }
  else{
    return 1;
  }
}

function cart_updateTotals( ){
  var i, j, k;
  var weight;

  // For each item in the cart, retreive its unit cost from the
  // catalog.  This is the right place to apply coupon discounts.
  for( i in cart.item ){
    for( j in catalog ){
      if( catalog[j].sku == cart.item[i].sku ){
	// we found the item in the catalog, now find the
	// right price break loop through the price breaks
	// array with k, starting with the largest break
	k = catalog[j].prcBreak.length;
	while( k > 0 ){
	  if( catalog[j].prcBreak[--k].qty <= cart.item[i].qty ){
	    cart.item[i].unitCost = catalog[j].prcBreak[k].cost;
	    if( cart.coupon == "aasp" ){
	      cart.item[i].unitDisc = catalog[j].prcBreak[k].cost * catalog[j].discount1;
	    }
	    else{
	      cart.item[i].unitDisc = 0;
	    }
	    cart.item[i].discCost = cart.item[i].unitCost - cart.item[i].unitDisc;
	    break;
	  }
	}
	break; // don't finish iterating through catalog --
	// just go to next cart item
      }
    }
  }

  // For each item in the cart, calculate its extended cost and sum
  // the sub total cost.  We get the extended cost from the .discCost, even if
  // there is no discount (in which case discCost and unitCost will be the same).
  cart.subTotal = 0;
  for( i in cart.item ){
    cart.item[i].extCost = cart.item[i].qty * cart.item[i].discCost;
    cart.subTotal += cart.item[i].extCost;
  }

  // We might as well do the shipping now that we can figure out the
  // weight, and since we know the subTotal
  cart.ship.cost = cart_getShipCost();

  // Now that we have a sub-total, do the tax
  // Tax will simply be 5% for any order, anywhere.
  cart.tax[0] = new cartTaxClass();

  cart.tax[0].name = "GST";
  cart.tax[0].rate = 0.05;
  cart.tax[0].cost = (cart.subTotal + cart.ship.cost) * cart.tax[0].rate;

  // Onto the total, add the gst and shipping and subTotal
  cart.total = cart.subTotal;
  for( i in cart.tax ){
    cart.total += cart.tax[i].cost;
  }

  // If the shipping is not available, it will be stored as -1 in
  // the cart so... don't be subtracting a dollar for shipping.
  if( cart.ship.cost > 0 ){
    cart.total += cart.ship.cost;
  }
}

function cart_getShipCost( ){
  var weight = 0;
  var cost = 0;

  // the rate_m is in units of $/kg, and it is different depending
  // on destination.

  // rate_b is the base cost, in $. It is also different depending
  // on destination.

  // Both rate values are different depending on shipping method, of
  // course.  But, we are only going to approximate the CP expedited
  // cost as a fraction of the CP Express Post cost.
  var rate_m, rate_b;

  for( i in cart.item ){
    weight += cart_getItemMass_kg( cart.item[i].sku ) * cart.item[i].qty;
  }

  // Get cost for Canada post Express post
  switch( cart.addrShip.province ){
  case "BC" :
    rate_m = 2.19; // Vancouver
    rate_b = 13.24;
    break;
  case "AB" :
    switch( cart.addrShip.city ){
    case "Calgary":
      rate_m = 0.623;
      rate_b = 7.76;
      break;
    case "Edmonton":
      rate_m = 0.723;
      rate_b = 8.01;
      break;
    case "Grande Prairie":
      rate_m = 0.966;
      rate_b = 10.87;
      break;
    default:
      rate_m = 0.8;
      rate_b = 10;
      break;
    }
    break;
  case "SK" :
    rate_m = 0.723; // Saskatoon
    rate_b = 8.01;
    break;
  case "MB" :
    rate_m = 2.193; // Winnipeg
    rate_b = 13.23;
    break;
  case "ON" :
    rate_m = 3.956; // Toronto
    rate_b = 12.25;
    break;
  case "QC" :
    rate_m = 3.956; // Montreal
    rate_b = 12.25;
    break;
  case "NB" :
    rate_m = 3.956; // Fredericton
    rate_b = 12.25;
    break;
  case "NS" :
    rate_m = 3.956; // Halifax
    rate_b = 12.25;
    break;
  case "PE" :
    rate_m = 3.956; // Charlottetown
    rate_b = 12.25;
    break;
  case "NL" :
    rate_m = 3.956; // St. John's
    rate_b = 12.25;
    break;
  case "YT" :
    rate_m = 3.956; // Whitehorse
    rate_b = 12.25;
    break;
  case "NT" :
    rate_m = 3.956; // Yellowknife
    rate_b = 12.25;
    break;
  case "NU" :
    rate_m = 8.95; // Iqualuit
    rate_b = 18.74;
    break;
  }

  // First of all, if the shipping method is Makeda courier, we
  // don't need to calculate much.
  if( cart.ship.meth == 1 ){
    return 0;
  }

  // If the subTotal is over $300, we don't have to calculate much either
  // because shipping is free over $300.00
  // Note that you have to have found the sub total before you run
  // this function.
  if( cart.subTotal >= 300 ){
    return 0;
  }

  // If they've chose "other" for shipping, then we don't even bother
  // displaying a shipping cost, $0 or otherwise.  A shipping cost of
  // -1 indicates this condition.
  if( cart.ship.meth == 4 ){
    return -1;
  }

  // Ok, they are shipping with either CP Expedited or CP Express
  // method number 2 is CP Expedited
  if( cart.ship.meth == 2 ){
    // convert the CP Epxress into CP Expedited cost, approximately.
    rate_m *= 0.6;
    rate_b *= 0.75;

    cost = rate_b;
    cost += rate_m * weight;
    return cost;
  }
  else{
    cost = rate_b;
    cost += rate_m * weight;
    return cost;
  }
}

function cart_getItemMass_kg( itemSku ){
  var j;

  // For the given sku, retreive its unit weight from the catalog.
  for( j in catalog ){
    if( catalog[j].sku == itemSku ){
      // we found the item in the catalog
      return catalog[j].mass_kg;
    }
  }
  //TODO: return what here? nothing?
}

function cart_setAddrCookie( ){
  var i;
  var s;

  // Cookie-encode the address values, and then put them in a cookie

  // We save the following objects here:
  // cart.addrShip
  // cart.addrBill

  s = "addr01=A:";

  s += cart.addrBill.fName + ":";
  s += cart.addrBill.lName + ":";
  s += cart.addrBill.cName + ":";
  s += cart.addrBill.street1 + ":";
  s += cart.addrBill.city + ":";
  s += cart.addrBill.province + ":";
  s += cart.addrBill.postCode + ":";
  s += cart.addrBill.country + ":";
  s += cart.addrBill.phone + ":";
  s += cart.addrBill.fax + ":";
  s += cart.addrBill.email + ":";
  s += cart.addrBill.subsNews + ":";

  s += cart.addrShip.fName + ":";
  s += cart.addrShip.lName + ":";
  s += cart.addrShip.cName + ":";
  s += cart.addrShip.street1 + ":";
  s += cart.addrShip.city + ":";
  s += cart.addrShip.province + ":";
  s += cart.addrShip.postCode + ":";
  s += cart.addrShip.country + ":";
  s += cart.addrShip.phone + ":";
  s += cart.addrShip.fax + ":";
  s += cart.addrShip.note + ":";

  document.cookie = s;
}

function cart_setOrderCookie( ){
  var i;
  var s;

  // Create a cookie with the order data that is in the cart object
  // right now.  By order data, I mean anything that affects the sub
  // total.  The address is separate from this cookie, mostly
  // because we want to keep the address for a longer duration than
  // the order info.  Don't do any updating or anything, just take
  // it like it is.

  // In particular, we are going to save:
  // each cart.item[].sku
  // each cart.item[].qty
  // cart.ship.meth
  // cart.coupon

  // it will be saved as a colon delimited list of values,
  // starting with a letter, "A", for the version

  s = "order01=A:";
  s += cart.ship.meth + ":";
  s += cart.coupon + ":";
  for( i in cart.item ){
    s += cart.item[i].sku + ":";
    s += cart.item[i].qty + ":";
  }

  document.cookie = s;
}

function cart_parseAddrCookie( s ){
  var i;
  var j;
  var subs; // if s is the whole browser cookie, then this is an
  // array of individual cookies
  var cookie; // the cookie contents, without the name
  var chip; // each of my colon delimited values
  var regexp;

  // Here we take a cookie string and update the cart object with
  // the saved data

  subs = s.split(";");

  cookie = "";
  for( i in subs ){
    if( subs[i].indexOf( "addr01=" ) >= 0 ){
      cookie = subs[i];
      // TODO: this will find an occurence of "addr01=" anywhere
      // in the cookie string.
      break;
    }
  }

  if( cookie.length > 0 ){
    // remove the cookie name from the string
    regexp = /^\s*addr01=/;
    cookie = cookie.replace( regexp, "");

    // remove the trailing colon from the string
    regexp = /:\s*$/;
    cookie = cookie.replace( regexp, "");

    if( cookie.indexOf( "A" ) != 0 ){
      return 1; // not the correct version of cookie
    }

    chip = cookie.split(":");

    // Populate the address variables with this still
    // cookie-encoded string
    i = 1;
    cart.addrBill.fName    = chip[i++];
    cart.addrBill.lName    = chip[i++];
    cart.addrBill.cName    = chip[i++];
    cart.addrBill.street1  = chip[i++];
    cart.addrBill.city     = chip[i++];
    cart.addrBill.province = chip[i++];
    cart.addrBill.postCode = chip[i++];
    cart.addrBill.country  = chip[i++];
    cart.addrBill.phone    = chip[i++];
    cart.addrBill.fax      = chip[i++];
    cart.addrBill.email    = chip[i++];
    cart.addrBill.subsNews = chip[i++];

    cart.addrShip.fName    = chip[i++];
    cart.addrShip.lName    = chip[i++];
    cart.addrShip.cName    = chip[i++];
    cart.addrShip.street1  = chip[i++];
    cart.addrShip.city     = chip[i++];
    cart.addrShip.province = chip[i++];
    cart.addrShip.postCode = chip[i++];
    cart.addrShip.country  = chip[i++];
    cart.addrShip.phone    = chip[i++];
    cart.addrShip.fax      = chip[i++];
    cart.addrShip.note     = chip[i++];
  }
}

function cart_parseOrderCookie( s ){
  var i;
  var j;
  var subs; // if s is the whole browser cookie, then this is an
  // array of individual cookies
  var cookie; // the cookie contents, without the name
  var chip; // each of my colon delimited values
  var regexp;

  // Here we take a cookie string and update the cart object with
  // the saved data

  subs = s.split(";");

  cookie = "";
  for( i in subs ){
    if( subs[i].indexOf( "order01=" ) >= 0 ){
      cookie = subs[i];
      // TODO: this will find an occurence of "order01="
      // anywhere in the cookie string.
      break;
    }
  }

  if( cookie.length > 0 ){
    // remove the cookie name from the string
    regexp = /^\s*order01=/;
    cookie = cookie.replace( regexp, "");

    // remove the trailing colon from the string
    regexp = /:\s*$/;
    cookie = cookie.replace( regexp, "");

    if( cookie.indexOf( "A" ) != 0 ){
      return 1; // not the correct version of cookie
    }

    chip = cookie.split(":");

    cart.ship.meth = chip[1];
    cart.coupon = chip[2];
    for( i=4,j=0; i < chip.length; i+=2,j++ ){
      cart.item[j] = new cartItemClass();
      cart.item[j].sku = chip[i-1];
      cart.item[j].qty = chip[i];
      // TODO: check for sanity of the cookie chips. ie, is it a
      // valid sku and quantity?
    }
  }
  return 0; // all good
}

function cart_parseQueryString( query ){
  var regexp;

  // Check if the query string (if any) is something the cart object
  // needs to pay attention to.  Possible queries are: add: to add
  // an item to the cart complete: the payment at Moneris went
  // through ok.

  regexp = /^\?add=/;
  if( regexp.test( query ) ){
    regexp = /.*=([a-z]+)/;
    query = query.replace( regexp, "$1" );
    cart_addItem( query );
  }
}

function cart_copyBillToShip( ){
  // Copy the relavent strings from the billing address to the
  // shipping address

  cart.addrShip.fName = cart.addrBill.fName;
  cart.addrShip.lName = cart.addrBill.lName;
  cart.addrShip.cName = cart.addrBill.cName;
  cart.addrShip.street1 = cart.addrBill.street1;
  cart.addrShip.city = cart.addrBill.city;
  cart.addrShip.province = cart.addrBill.province;
  cart.addrShip.postCode = cart.addrBill.postCode;
  cart.addrShip.phone = cart.addrBill.phone;
  cart.addrShip.fax = cart.addrBill.fax;
}

function cart_verifyAddrBill( ){
  var wasError = 0;
  var sIn;
  var regexpName, regexpPostCode, regexpPhone, regexpEmail;

  // negative match
  regexpName =     /[$*]/;
  // negative match
  regexpPostCode = /[$*]/;
  // negative match
  regexpPhone =    /[$*]/;
  // positive match
  regexpEmail =    /^[^@]+@[a-zA-Z0-9.-]+$/;


  // Do sanity checks on the information in the cart.  We do this
  // test just after populating the cart object from the form We
  // also encode the string to be suitable for a cookie

  sIn = cart.addrBill.fName;
  if( !sIn ){
    sIn = "";
  }
  sIn = sIn.toString();
  sIn = sIn.replace( /\s+$/, "" ); // chomp spaces from end
  sIn = sIn.replace( /^\s+/, "" ); // chomp spaces from beginning
  if( regexpName.test( sIn ) ){
    cart.addrBill.fName = "?" + sIn;
    wasError = 1;
  }
  else{
    cart.addrBill.fName = sIn;
  }

  sIn = cart.addrBill.lName;
  if( !sIn ){
    sIn = "";
  }
  sIn = sIn.toString();
  sIn = sIn.replace( /\s+$/, "" ); // chomp spaces from end
  sIn = sIn.replace( /^\s+/, "" ); // chomp spaces from beginning
  if( regexpName.test( sIn ) ){
    cart.addrBill.lName = "?" + sIn;
    wasError = 1;
  }
  else{
    cart.addrBill.lName = sIn;
  }

  sIn = cart.addrBill.cName;
  if( !sIn ){
    sIn = "";
  }
  sIn = sIn.toString();
  sIn = sIn.replace( /\s+$/, "" ); // chomp spaces from end
  sIn = sIn.replace( /^\s+/, "" ); // chomp spaces from beginning
  if( regexpName.test( sIn ) ){
    cart.addrBill.cName = "?" + sIn;
    wasError = 1;
  }
  else{
    cart.addrBill.cName = sIn;
  }

  sIn = cart.addrBill.street1;
  if( !sIn ){
    sIn = "";
  }
  sIn = sIn.toString();
  sIn = sIn.replace( /\s+$/, "" ); // chomp spaces from end
  sIn = sIn.replace( /^\s+/, "" ); // chomp spaces from beginning
  if( regexpName.test( sIn ) ){
    cart.addrBill.street1 = "?" + sIn;
    wasError = 1;
  }
  else{
    cart.addrBill.street1 = sIn;
  }

  sIn = cart.addrBill.city;
  if( !sIn ){
    sIn = "";
  }
  sIn = sIn.toString();
  sIn = sIn.replace( /\s+$/, "" ); // chomp spaces from end
  sIn = sIn.replace( /^\s+/, "" ); // chomp spaces from beginning
  if( regexpName.test( sIn ) ){
    cart.addrBill.city = "?" + sIn;
    wasError = 1;
  }
  else{
    cart.addrBill.city = sIn;
  }

  sIn = cart.addrBill.postCode;
  if( !sIn ){
    sIn = "";
  }
  sIn = sIn.toString();
  sIn = sIn.replace( /\s+$/, "" ); // chomp spaces from end
  sIn = sIn.replace( /^\s+/, "" ); // chomp spaces from beginning
  if( regexpPostCode.test( sIn ) ){
    cart.addrBill.postCode = "?" + sIn;
    wasError = 1;
  }
  else{
    cart.addrBill.postCode = sIn;
  }

  sIn = cart.addrBill.phone;
  if( !sIn ){
    sIn = "";
  }
  sIn = sIn.toString();
  sIn = sIn.replace( /\s+$/, "" ); // chomp spaces from end
  sIn = sIn.replace( /^\s+/, "" ); // chomp spaces from beginning
  if( regexpPhone.test( sIn ) ){
    cart.addrBill.phone = "?" + sIn;
    wasError = 1;
  }
  else{
    cart.addrBill.phone = sIn;
  }

  sIn = cart.addrBill.fax;
  if( !sIn ){
    sIn = "";
  }
  sIn = sIn.toString();
  sIn = sIn.replace( /\s+$/, "" ); // chomp spaces from end
  sIn = sIn.replace( /^\s+/, "" ); // chomp spaces from beginning
  if( regexpPhone.test( sIn ) ){
    cart.addrBill.fax = "?" + sIn;
    wasError = 1;
  }
  else{
    cart.addrBill.fax = sIn;
  }

  sIn = cart.addrBill.email;
  if( !sIn ){
    sIn = "";
  }
  sIn = sIn.toString();
  sIn = sIn.replace( /\s+$/, "" ); // chomp spaces from end
  sIn = sIn.replace( /^\s+/, "" ); // chomp spaces from beginning
  if( !regexpEmail.test( sIn ) ){
    cart.addrBill.email = "?" + sIn;
    wasError = 1;
  }
  else{
    cart.addrBill.email = sIn;
  }

  return wasError;
}

function cart_verifyAddrShip( ){
  var wasError = 0;
  var sIn;
  var regexpName, regexpPostCode, regexpPhone;

  // negative match
  regexpName =     /[$*]/;
  // negative match
  regexpPostCode = /[$*]/;
  // negative match
  regexpPhone =    /[$*]/;
  // positive match
  regexpEmail =    /^[^@]+@[a-zA-Z0-9.-]+$/;


  // Do sanity checks on the information in the cart.  We do this
  // test just after populating the cart object from the form We
  // also encode the string to be suitable for a cookie

  sIn = cart.addrShip.fName;
  if( !sIn ){
    sIn = "";
  }
  sIn = sIn.toString();
  sIn = sIn.replace( /\s+$/, "" ); // chomp spaces from end
  sIn = sIn.replace( /^\s+/, "" ); // chomp spaces from beginning
  if( regexpName.test( sIn ) ){
    cart.addrShip.fName = "?" + sIn;
    wasError = 1;
  }
  else{
    cart.addrShip.fName = sIn;
  }

  sIn = cart.addrShip.lName;
  if( !sIn ){
    sIn = "";
  }
  sIn = sIn.toString();
  sIn = sIn.replace( /\s+$/, "" ); // chomp spaces from end
  sIn = sIn.replace( /^\s+/, "" ); // chomp spaces from beginning
  if( regexpName.test( sIn ) ){
    cart.addrShip.lName = "?" + sIn;
    wasError = 1;
  }
  else{
    cart.addrShip.lName = sIn;
  }

  sIn = cart.addrShip.cName;
  if( !sIn ){
    sIn = "";
  }
  sIn = sIn.toString();
  sIn = sIn.replace( /\s+$/, "" ); // chomp spaces from end
  sIn = sIn.replace( /^\s+/, "" ); // chomp spaces from beginning
  if( regexpName.test( sIn ) ){
    cart.addrShip.cName = "?" + sIn;
    wasError = 1;
  }
  else{
    cart.addrShip.cName = sIn;
  }

  sIn = cart.addrShip.street1;
  if( !sIn ){
    sIn = "";
  }
  sIn = sIn.toString();
  sIn = sIn.replace( /\s+$/, "" ); // chomp spaces from end
  sIn = sIn.replace( /^\s+/, "" ); // chomp spaces from beginning
  if( regexpName.test( sIn ) ){
    cart.addrShip.street1 = "?" + sIn;
    wasError = 1;
  }
  else{
    cart.addrShip.street1 = sIn;
  }

  sIn = cart.addrShip.city;
  if( !sIn ){
    sIn = "";
  }
  sIn = sIn.toString();
  sIn = sIn.replace( /\s+$/, "" ); // chomp spaces from end
  sIn = sIn.replace( /^\s+/, "" ); // chomp spaces from beginning
  if( regexpName.test( sIn ) ){
    cart.addrShip.city = "?" + sIn;
    wasError = 1;
  }
  else{
    cart.addrShip.city = sIn;
  }

  sIn = cart.addrShip.postCode;
  if( !sIn ){
    sIn = "";
  }
  sIn = sIn.toString();
  sIn = sIn.replace( /\s+$/, "" ); // chomp spaces from end
  sIn = sIn.replace( /^\s+/, "" ); // chomp spaces from beginning
  if( regexpPostCode.test( sIn ) ){
    cart.addrShip.postCode = "?" + sIn;
    wasError = 1;
  }
  else{
    cart.addrShip.postCode = sIn;
  }

  sIn = cart.addrShip.phone;
  if( !sIn ){
    sIn = "";
  }
  sIn = sIn.toString();
  sIn = sIn.replace( /\s+$/, "" ); // chomp spaces from end
  sIn = sIn.replace( /^\s+/, "" ); // chomp spaces from beginning
  if( regexpPhone.test( sIn ) ){
    cart.addrShip.phone = "?" + sIn;
    wasError = 1;
  }
  else{
    cart.addrShip.phone = sIn;
  }

  sIn = cart.addrShip.fax;
  if( !sIn ){
    sIn = "";
  }
  sIn = sIn.toString();
  sIn = sIn.replace( /\s+$/, "" ); // chomp spaces from end
  sIn = sIn.replace( /^\s+/, "" ); // chomp spaces from beginning
  if( regexpPhone.test( sIn ) ){
    cart.addrShip.fax = "?" + sIn;
    wasError = 1;
  }
  else{
    cart.addrShip.fax = sIn;
  }

  return wasError;
}

function cart_encodeCookie( ){
  cart.addrBill.fName    = cookieEncode( cart.addrBill.fName );
  cart.addrBill.lName    = cookieEncode( cart.addrBill.lName );
  cart.addrBill.cName    = cookieEncode( cart.addrBill.cName );
  cart.addrBill.street1  = cookieEncode( cart.addrBill.street1 );
  cart.addrBill.city     = cookieEncode( cart.addrBill.city );
  cart.addrBill.postCode = cookieEncode( cart.addrBill.postCode );
  cart.addrBill.phone    = cookieEncode( cart.addrBill.phone );
  cart.addrBill.fax      = cookieEncode( cart.addrBill.fax );
  cart.addrBill.email    = cookieEncode( cart.addrBill.email );

  cart.addrShip.fName    = cookieEncode( cart.addrShip.fName );
  cart.addrShip.lName    = cookieEncode( cart.addrShip.lName );
  cart.addrShip.cName    = cookieEncode( cart.addrShip.cName );
  cart.addrShip.street1  = cookieEncode( cart.addrShip.street1 );
  cart.addrShip.city     = cookieEncode( cart.addrShip.city );
  cart.addrShip.postCode = cookieEncode( cart.addrShip.postCode );
  cart.addrShip.phone    = cookieEncode( cart.addrShip.phone );
  cart.addrShip.fax      = cookieEncode( cart.addrShip.fax );
  cart.addrShip.note     = cookieEncode( cart.addrShip.note );
}

function cart_decodeCookie( ){
  cart.addrBill.fName    = cookieDecode( cart.addrBill.fName );
  cart.addrBill.lName    = cookieDecode( cart.addrBill.lName );
  cart.addrBill.cName    = cookieDecode( cart.addrBill.cName );
  cart.addrBill.street1  = cookieDecode( cart.addrBill.street1 );
  cart.addrBill.city     = cookieDecode( cart.addrBill.city );
  cart.addrBill.postCode = cookieDecode( cart.addrBill.postCode );
  cart.addrBill.phone    = cookieDecode( cart.addrBill.phone );
  cart.addrBill.fax      = cookieDecode( cart.addrBill.fax );
  cart.addrBill.email    = cookieDecode( cart.addrBill.email );

  cart.addrShip.fName    = cookieDecode( cart.addrShip.fName );
  cart.addrShip.lName    = cookieDecode( cart.addrShip.lName );
  cart.addrShip.cName    = cookieDecode( cart.addrShip.cName );
  cart.addrShip.street1  = cookieDecode( cart.addrShip.street1 );
  cart.addrShip.city     = cookieDecode( cart.addrShip.city );
  cart.addrShip.postCode = cookieDecode( cart.addrShip.postCode );
  cart.addrShip.phone    = cookieDecode( cart.addrShip.phone );
  cart.addrShip.fax      = cookieDecode( cart.addrShip.fax );
  cart.addrShip.note     = cookieDecode( cart.addrShip.note );
}
