// customizer.js
//
// by Steav

var cmz = new Object();
cmz.priceWnd = new Object();

////////////////////////////////////////////////////////////////////////////////
// CONFIGURATION DATA

// the parameters below define customizer behavior

cmz.priceWnd.formID   = "configForm";
cmz.formAction        = "configuration_save.php";
cmz.formMethod        = "post";
cmz.fetchXML          = "/customizer/fetch_data.php";

cmz.loadingMsg = "<b>loading configuration...</b>"

cmz.priceView = "rel";   // "rel" (relative) or "abs" (abdominals. er-- absolute)

cmz.priceWnd.idText       = "system_id";
cmz.sumTableClass         = "summary_table";
cmz.priceWnd.continueText = "Continue";
cmz.moreInfoText          = "More Info";
cmz.saveText              = "Save for Later";
cmz.addText               = "Add to Cart";
cmz.sendText              = "Send to Sales";
cmz.continueText          = "Continue";
cmz.reconfigureText       = "Reconfigure this System";

cmz.priceWnd.corner = "bottom_right";   // <bottom/top>_<left/right>

cmz.priceWnd.width  = 300;
cmz.priceWnd.height = 100;
cmz.infoWndWidth    = 612;
cmz.infoWndHeight   = 600;

cmz.priceWnd.paddingTop    = 20;
cmz.priceWnd.paddingRight  = 40;
cmz.priceWnd.paddingBottom = 20;
cmz.priceWnd.paddingLeft   = 20;

// END CONFIGURATION DATA
////////////////////////////////////////////////////////////////////////////////

// classes and members
////////////////////////////////////////////////////////////////////////////////

// product class
cmz.prod = function( pid, plabel, pdef, pname, pprice, pimg )
{
  this.pid = pid;
  this.plabel = plabel;
  this.pdef = pdef;
  this.pname = pname;
  this.pprice = pprice;
  this.pimg = pimg;
  this.psel = false;
}

// category class
cmz.cat = function( cid, clabel, cname, cimg, cavail, cfrcid )
{
  this.cid = cid;
  this.clabel = clabel;
  this.cname = cname;
  this.cimg = cimg;
  this.cavail = cavail;
  this.cfrcid = cfrcid;
  this.prods = new Array();
}

// section class
cmz.sect = function( sid, sname, savail )
{
  this.sid = sid;
  this.sname = sname;
  this.cats = new Array();
}

// position class
cmz.pos = function( sidx, cidx, pidx )
{
  this.sidx = sidx;
  this.cidx = cidx;
  this.pidx = pidx;
}

// customizer members
cmz.sysid = 0;
cmz.savid = 0;
cmz.sysname = "";
cmz.sysdesc = "";
cmz.sysspecs = "";
cmz.price_type = "C";     // F, C, or N
cmz.flat_price = 0;
cmz.total_price = 0;
cmz.submit_action = "continue";

cmz.sects = new Array();

cmz.req = null;
cmz.out = null;
cmz.formDiv = null;
cmz.cfrmDiv = null;
cmz.priceEl = null;

// customizer functions
////////////////////////////////////////////////////////////////////////////////

// initialize customizer
cmz.init = function( sysid, savid )
{
  cmz.sysid = sysid;
  cmz.savid = savid;
  cmz.out = document.getElementById( "cmzoutput" );
  
  if ( !cmz.out )
    alert( "Failed to retrieve output area" );
  else
  {
    cmz.out.innerHTML = cmz.loadingMsg;
    
    // create divs for form and confirmation
    cmz.formDiv = document.createElement( "div" );
    cmz.formDiv.id = "cmzForm";
    cmz.cfrmDiv = document.createElement( "div" );
    cmz.cfrmDiv.id = "cmzConfirm";
    
    if ( window.XMLHttpRequest )
      cmz.req = new XMLHttpRequest();
    else if ( window.ActiveXObject )
      cmz.req = new ActiveXObject( "Microsoft.XMLHTTP" );
    
    if ( cmz.req )
    {
      try
      {
        cmz.req.onreadystatechange = cmz.onRSChange;
        cmz.req.open( "GET", cmz.fetchXML + "?id=" + cmz.sysid + "&s=" + cmz.savid, true );
        cmz.req.send( null );
      }
      catch( err )
      {
        cmz.out.innerHTML = "";
        cmz.reportErr( "Failed to retrieve configuration data" );
      }
    }
  }
}

// XML request onreadystatechange handler
cmz.onRSChange = function()
{
  if ( cmz.req.readyState == 4 )
  {
    if ( cmz.req.status == 200 || cmz.req.status == 0 )
      cmz.loadMetrics();
    else
    {
      cmz.out.innerHTML = "";
      cmz.reportErr( "Failed to retrieve configuration data" );
    }
  }
}

// load system metrics
cmz.loadMetrics = function()
{
  if ( !cmz.req.responseXML || !cmz.req.responseXML.documentElement )
  {
    cmz.out.innerHTML = "";
    cmz.reportErr( "Retrieved invalid XML document" );
  }
  else
  {
    var sysEl = cmz.req.responseXML.getElementsByTagName( "system" )[0];
    if ( !sysEl || sysEl.childNodes.length == 0 )
    {
      cmz.out.innerHTML = "";
      cmz.reportErr( "Configuration data is empty" );
    }
    else
    {
      var sysid = cmz.getXMLNodeVal( sysEl, "id" );
      var sysname = cmz.getXMLNodeVal( sysEl, "name" );
      var sysdesc = cmz.getXMLNodeVal( sysEl, "description" );
      var sysspecs = cmz.getXMLNodeVal( sysEl, "specs" );
      var price_type = cmz.getXMLNodeVal( sysEl, "price_type" );
      var flat_price = cmz.getXMLNodeVal( sysEl, "flat_price" );
      
      if ( !sysid || !sysname || !price_type || !flat_price )
      {
        cmz.out.innerHTML = "";
        cmz.reportErr( "Failed to retrieve configuration data" );
      }
      else
      {
        cmz.sysid = sysid;
        cmz.sysname = sysname;
        cmz.sysdesc = sysdesc;
        cmz.sysspecs = sysspecs;
        cmz.price_type = price_type;
        cmz.flat_price = parseFloat( flat_price );

        if ( !cmz.loadSects( sysEl ) )
        {
          cmz.out.innerHTML = "";
          cmz.reportErr( "Failed to retrieve configuration data" );
        }
        else
        {
          // if we're using a flat price, always set the total to the flat price
          if ( cmz.price_type == 'F' )
            cmz.total_price = cmz.flat_price;
          
          cmz.loadForm();
          cmz.priceWnd.load( cmz.priceWnd.corner, cmz.out );
          
          cmz.priceEl = document.getElementById( "cmz_priceSpan" );
          cmz.updateTotal();
        }
      }
    }
  }
}

// load sections from XML
cmz.loadSects = function( topEl )
{
  var sectEls = topEl.getElementsByTagName( "section" );
  if ( !sectEls || sectEls.length == 0 )
    return false;
  
  for( var i = 0; i < sectEls.length; i++ )
  {
    var sid = cmz.getXMLNodeVal( sectEls[i], "id" );
    var sname = cmz.getXMLNodeVal( sectEls[i], "name" );
    
    if ( sid && sname )
    {
      sname = sname.replace( "^^", "?" );
      var sidx = ( cmz.sects.push( new cmz.sect( sid, sname ) ) ) - 1;
      if ( sidx < 0 )
        return false;
        
      if ( !cmz.loadCats( sectEls[i], sidx ) )
        cmz.sects.pop();
    }
  }
  
  return ( cmz.sects.length > 0 );
}

// load categories from XML
cmz.loadCats = function( topEl, sidx )
{
  var catEls = topEl.getElementsByTagName( "category" );
  if ( !catEls || catEls.length == 0 )
    return false;
  
  for( var j = 0; j < catEls.length; j++ )
  {
    var cid = cmz.getXMLNodeVal( catEls[j], "id" );
    var clabel = cmz.getXMLNodeVal( catEls[j], "label" );
    var cname = cmz.getXMLNodeVal( catEls[j], "name" );
    var cimg = cmz.getXMLNodeVal( catEls[j], "image" );
    var cavail = cmz.getXMLNodeVal( catEls[j], "available" );
    var cfrcid = cmz.getXMLNodeVal( catEls[j], "force_identical" );
    
    if ( cid && clabel && cname && cavail && cfrcid )
    {
      cname = cname.replace( "^^", "?" );
      var cidx = ( cmz.sects[sidx].cats.push( new cmz.cat( cid, clabel, cname, cimg, cavail, cfrcid ) ) ) - 1;
      if ( cidx < 0 )
        return false;
        
      if ( !cmz.loadProds( catEls[j], sidx, cidx ) )
        cmz.sects[sidx].cats.pop();
      else
      {
        // make sure we only have one default product in each category
        var defSet = false;
        for( var k = 0; k < cmz.sects[sidx].cats[cidx].prods.length; k++ )
        {
          if ( defSet )
            cmz.sects[sidx].cats[cidx].prods[k].pdef = 0;
          else if ( cmz.sects[sidx].cats[cidx].prods[k].pdef == 1 )
          {
            defSet = true;
            cmz.total_price += parseFloat( cmz.sects[sidx].cats[cidx].prods[k].pprice );
            cmz.sects[sidx].cats[cidx].prods[k].psel = true;
          }
        }
        
        // if a default product wasn't found, use the first one in the array
        if ( !defSet && cmz.sects[sidx].cats[cidx].prods.length > 0 )
        {
          cmz.sects[sidx].cats[cidx].prods[0].pdef = 1;
          cmz.total_price += parseFloat( cmz.sects[sidx].cats[cidx].prods[0].pprice );
          cmz.sects[sidx].cats[cidx].prods[0].psel = true;
        }
      }
    }
  }
  
  return ( cmz.sects[sidx].cats.length > 0 );
}

// load products from XML
cmz.loadProds = function( topEl, sidx, cidx )
{
  var prodEls = topEl.getElementsByTagName( "product" );
  if ( !prodEls || prodEls.length == 0 )
    return false;
  
  for( var k = 0; k < prodEls.length; k++ )
  {
    var pid = cmz.getXMLNodeVal( prodEls[k], "id" );
    var plabel = cmz.getXMLNodeVal( prodEls[k], "label" );
    var pdef = cmz.getXMLNodeVal( prodEls[k], "default" );
    var pname = cmz.getXMLNodeVal( prodEls[k], "name" );
    var pprice = cmz.getXMLNodeVal( prodEls[k], "price" );
    var pimg = cmz.getXMLNodeVal( prodEls[k], "image" );
    
    if ( pid && plabel && pdef && pname && pprice && pimg )
    {
      pdef = parseInt( pdef );
      pname = pname.replace( "^^", "?" );
      var pidx = cmz.sects[sidx].cats[cidx].prods.push( new cmz.prod( pid, plabel, pdef, pname, pprice, pimg ) );
      if ( pidx < 1 )
        return false;
    }
  }
  
  return ( cmz.sects[sidx].cats[cidx].prods.length > 0 );
}

// load form
cmz.loadForm = function()
{
  cmz.out.innerHTML = "";
  cmz.out.appendChild( cmz.formDiv );
  
  // header area
  var headEl = document.createElement( "table" );
  headEl.id = "cmz_head";
  var headBodyEl = document.createElement( "tbody" );
  var headRowEl = document.createElement( "tr" );
  // left column
  var divEl = document.createElement( "td" );
  divEl.id = "cmz_head_img";
  var newEl = document.createElement( "img" );
  newEl.src = "/images/space.gif";
  newEl.id = "cmz_head_image";
  divEl.appendChild( newEl );
  headRowEl.appendChild( divEl );
  // middle column
  var divEl = document.createElement( "td" );
  divEl.id = "cmz_head_details";
  var newEl = document.createElement( "h1" );
  newEl.innerHTML = "Configure Your " + cmz.sysname;
  divEl.appendChild( newEl );

  if ( cmz.sysdesc != null )
  {
    newEl = document.createElement( "div" );
    newEl.className = 'system_description';
    newEl.innerHTML = cmz.sysdesc.replace( /\n/g, '<br />' ).replace('</li><br />', '</li>').replace('<ul><br />', '<ul>').replace('</ul><br />', '</ul>');
    divEl.appendChild( newEl );
  }

  if ( cmz.sysspecs != null )
  {
    newEl = document.createElement( "div" );
    newEl.className = 'system_description';
    newEl.innerHTML = cmz.sysspecs.replace( /\n/g, '<br />' ).replace('</li><br />', '</li>').replace('<ul><br />', '<ul>').replace('</ul><br />', '</ul>');
    divEl.appendChild( newEl );
  }

  headRowEl.appendChild( divEl );
  // right column
  var divEl = document.createElement( "td" );
  divEl.id = "cmz_head_pricing";
  newEl = document.createElement( "p" );
  newEl.appendChild( document.createTextNode( "Price as Configured: " ) );
  var spanEl = document.createElement( "span" );
  spanEl.id = "total_price";
  spanEl.innerHTML = cmz.moneyFormat( cmz.total_price );
  newEl.appendChild( spanEl );
  divEl.appendChild( newEl );
  var ulEl = document.createElement( "ul" );
  var liEl = document.createElement( "li" );
  liEl.innerHTML = "<a href=\"#\" onclick=\"cmz.onContinue('save');\">" + cmz.saveText + "</a>";
  ulEl.appendChild( liEl );
  liEl = document.createElement( "li" );
  liEl.innerHTML = "<a href=\"#\" onclick=\"cmz.onContinue('add');\">" + cmz.addText + "</a>";
  ulEl.appendChild( liEl );
  liEl = document.createElement( "li" );
  liEl.innerHTML = "<a href=\"#\" onclick=\"cmz.onContinue('send');\">" + cmz.sendText + "</a>";
  ulEl.appendChild( liEl );
  divEl.appendChild( ulEl );
  headRowEl.appendChild( divEl );

  headBodyEl.appendChild( headRowEl );
  headEl.appendChild( headBodyEl );
  cmz.formDiv.appendChild( headEl );

  // form declaration
  var formEl = document.createElement( "form" );
  formEl.id = cmz.priceWnd.formID;
  formEl.className = "configurator";
  formEl.action = cmz.formAction;
  formEl.method = cmz.formMethod;
  cmz.formDiv.appendChild( formEl );
  
  for( var i = 0; i < cmz.sects.length; i++ )
  {
    // section header
    newEl = document.createElement( "h2" );
    newEl.innerHTML = cmz.sects[i].sname;
    formEl.appendChild( newEl );
    
    for( var j = 0; j < cmz.sects[i].cats.length; j++ )
    {
      // category header
      var divEl = document.createElement( "div" );
      divEl.className = "section_head";
      newEl = document.createElement( "h3" );
      newEl.innerHTML = cmz.sects[i].cats[j].cname;
      var spanEl = document.createElement( "span" );
      spanEl.innerHTML = "<a href=\"\" onclick=\"cmz.openInfo(" + i + "," + j + ");return false;\">" + cmz.moreInfoText + "</span>";
      divEl.appendChild( spanEl );
      divEl.appendChild( newEl );
      formEl.appendChild( divEl );

      // category image
      if (cmz.sects[i].cats[j].cimg)
      {
        var divEl = document.createElement( "div" );
        divEl.className = "section_image";
        newEl = document.createElement( "img" );
        newEl.src = cmz.sects[i].cats[j].cimg;
        divEl.appendChild( newEl );
        formEl.appendChild( divEl );
      }
      
      for( var k = 0; k < cmz.sects[i].cats[j].prods.length; k++ )
      {
        // outer div
        divEl = document.createElement( "div" );
        divEl.className = "checkbox";
        formEl.appendChild( divEl );
        
        var check = "";
        if ( cmz.sects[i].cats[j].prods[k].pdef == 1 )
        {
          check = " checked=\"checked\"";

          if ( cmz.sects[i].cats[j].prods[k].pimg > 0 )
          {
            var prodImg = document.getElementById("cmz_head_image");
            prodImg.src = "/product_images/thumbs/" + cmz.sects[i].cats[j].prods[k].pimg + ".png";
          }
        }
        
        var priceStr = "";
        if ( cmz.priceView == "abs" )
          priceStr = cmz.moneyFormat( cmz.sects[i].cats[j].prods[k].pprice );
        
        // this part is ugly as hell, but supposedly is the best way to get this to
        // work in most browsers.  Honestly, IE is only browser that can't do it correctly.
        divEl.innerHTML = "<input type=\"radio\" name=\"" + cmz.sects[i].cats[j].clabel + "\"" +
          " id=\"" + cmz.sects[i].cats[j].prods[k].plabel + "\"" +
          " value=\"" + cmz.sects[i].cats[j].prods[k].pid + "\"" + check +
          " onclick=\"cmz.onClickRadio(this.id);\">" +
          "<label for=\"" + cmz.sects[i].cats[j].prods[k].plabel + "\">" +
          cmz.sects[i].cats[j].prods[k].pname +
          " <span id=\"" + cmz.sects[i].cats[j].prods[k].plabel + "_price\">" +
          priceStr + "</span>";
      }
      
      if ( cmz.priceView == "rel" )
        cmz.updateRadioGroup( i, j );
    }
  }
  
  cmz.cfrmDiv.style.display = "none";
  cmz.out.appendChild( cmz.cfrmDiv );
}

// radio button click handler
cmz.onClickRadio = function( fid )
{
  var pos = cmz.getPos( fid );
  if ( !pos )
  {
    alert( "Error retrieving price data-- prices may be miscalculated" );
    return;
  }
  
  // get previous selection and default from this category
  var prevIdx = -1;
  var defIdx = -1;
  for( var k = 0; k < cmz.sects[pos.sidx].cats[pos.cidx].prods.length; k++ )
  {
    if ( cmz.sects[pos.sidx].cats[pos.cidx].prods[k].psel == true )
      prevIdx = k;
    if ( cmz.sects[pos.sidx].cats[pos.cidx].prods[k].pdef == 1 )
      defIdx = k;
  }
  if ( prevIdx == -1 || defIdx == -1 )
  {
    alert( "Error encountered-- prices may be miscalculated" );
    return;
  }
  
  // if the selection has changed, update everything
  if ( prevIdx != pos.pidx )
  {
    if ( cmz.price_type == 'F' )
    {
      var pOld = cmz.sects[pos.sidx].cats[pos.cidx].prods[prevIdx].pprice;
      var pDef = cmz.sects[pos.sidx].cats[pos.cidx].prods[defIdx].pprice;
      var pNew = cmz.sects[pos.sidx].cats[pos.cidx].prods[pos.pidx].pprice;
      
      // if the price is fixed, we want to use the default price as a base. so first we restore
      // the default price to the total, then if the new price is greater than default, we add
      // the difference to the total.
      if ( ( pOld - pDef ) > 0 )
        cmz.total_price -= ( pOld - pDef );
      if ( pNew > pDef )
        cmz.total_price += ( pNew - pDef );
    }
    else
    {
      // if the price isn't fixed, we use the actual prices
      cmz.total_price -= parseFloat( cmz.sects[pos.sidx].cats[pos.cidx].prods[prevIdx].pprice );
      cmz.total_price += parseFloat( cmz.sects[pos.sidx].cats[pos.cidx].prods[pos.pidx].pprice );
    }
    
    cmz.sects[pos.sidx].cats[pos.cidx].prods[prevIdx].psel = false;
    cmz.sects[pos.sidx].cats[pos.cidx].prods[pos.pidx].psel = true;
    
    cmz.updateTotal();
  }
  
  if ( cmz.priceView == "rel" )
    cmz.updateRadioGroup( pos.sidx, pos.cidx );

  if ( cmz.sects[pos.sidx].cats[pos.cidx].prods[pos.pidx].pimg > 0 )
  {
    var prodImg = document.getElementById("cmz_head_image");
    prodImg.src = "/product_images/thumbs/" + cmz.sects[pos.sidx].cats[pos.cidx].prods[pos.pidx].pimg + ".png";
  }
}

// continue onclick handler
cmz.onContinue = function( name )
{
  cmz.submit_action = name;

  if ( cmz.cfrmDiv.hasChildNodes() )
  {
    while ( cmz.cfrmDiv.childNodes.length >= 1 )
      cmz.cfrmDiv.removeChild( cmz.cfrmDiv.firstChild );
  }
  
  cmz.formDiv.style.display = "none";
  var wndEl = document.getElementById( "cmz_priceWnd" );
  if ( wndEl )
  {
    wndEl.style.display = "none";
  }
  cmz.cfrmDiv.style.display = "block";
  
  // confirmation title
  var divEl = document.createElement( "h1" );
  divEl.appendChild( document.createTextNode( "Configuration Summary" ) );
  cmz.cfrmDiv.appendChild( divEl );
  
  // total price (top)
  var divEl = document.createElement( "div" );
  divEl.className = "cmz_confirmPriceLabel";
  divEl.appendChild( document.createTextNode( "Total Price:" ) );
  var spanEl = document.createElement( "span" );
  spanEl.innerHTML = cmz.moneyFormat( cmz.total_price );
  divEl.appendChild( spanEl );
  cmz.cfrmDiv.appendChild( divEl );
  
  // buttons (top)
  var ulEl = document.createElement( "ul" );
  ulEl.className = "cmz_confirmLinkList";
  var liEl = document.createElement( "li" );
  liEl.className = "cmz_confirmLink";
  liEl.innerHTML = "<a href=\"#\" onclick=\"cmz.onSubmit(cmz.submit_action);\">" + cmz.continueText + "</a>";
  ulEl.appendChild( liEl );
  liEl = document.createElement( "li" );
  liEl.className = "cmz_confirmLink";
  liEl.innerHTML = "<a href=\"#\" onclick=\"cmz.onSubmit('continue');\">" + cmz.reconfigureText + "</a>";
  ulEl.appendChild( liEl );
  cmz.cfrmDiv.appendChild( ulEl );

  // product table
  var tableEl = document.createElement( "table" );
  tableEl.className = cmz.sumTableClass;
  tableEl.setAttribute( "summary", "list of your system's components" );
  var tbodyEl = document.createElement( "tbody" );
  tableEl.appendChild( tbodyEl );
  
  var rowFlag = 1;
  for ( var i = 0; i < cmz.sects.length; i++ )
  {
    for ( var j = 0; j < cmz.sects[i].cats.length; j++ )
    {
      // get the selected product
      var pidx = -1;
      for ( var k = 0; k < cmz.sects[i].cats[j].prods.length; k++ )
      {
        if ( cmz.sects[i].cats[j].prods[k].psel == true )
        {
          pidx = k;
          break;
        }
      }
      if ( pidx != -1 )
      {
        // append product
        var trEl = document.createElement( "tr" );
        trEl.className = "row" + rowFlag.toString();
        var tdEl = document.createElement( "td" );
        tdEl.innerHTML = cmz.sects[i].cats[j].prods[pidx].pname;
        var thEl = document.createElement( "th" );
        thEl.setAttribute( "scope", "row" );
        thEl.innerHTML = cmz.sects[i].cats[j].cname;
        trEl.appendChild( thEl );
        trEl.appendChild( tdEl );
        tbodyEl.appendChild( trEl );
        
        rowFlag = ( rowFlag == 1 ) ? 2 : 1;
      }
    }
  }
  
  cmz.cfrmDiv.appendChild( tableEl );
  
  // total price (bottom)
  divEl = document.createElement( "div" );
  divEl.className = "cmz_confirmPriceLabel";
  divEl.appendChild( document.createTextNode( "Total Price:" ) );
  spanEl = document.createElement( "span" );
  spanEl.innerHTML = cmz.moneyFormat( cmz.total_price );
  divEl.appendChild( spanEl );
  cmz.cfrmDiv.appendChild( divEl );
  
  // buttons (bottom)
  var ulEl = document.createElement( "ul" );
  ulEl.className = "cmz_confirmLinkList";
  var liEl = document.createElement( "li" );
  liEl.className = "cmz_confirmLink";
  liEl.innerHTML = "<a href=\"#\" onclick=\"cmz.onSubmit(cmz.submit_action);\">" + cmz.continueText + "</a>";
  ulEl.appendChild( liEl );
  liEl = document.createElement( "li" );
  liEl.className = "cmz_confirmLink";
  liEl.innerHTML = "<a href=\"#\" onclick=\"cmz.onSubmit('continue');\">" + cmz.reconfigureText + "</a>";
  ulEl.appendChild( liEl );
  cmz.cfrmDiv.appendChild( ulEl );
}

// button handler(s)
cmz.onSubmit = function( name )
{
  if ( name == "continue" )
  {
    cmz.formDiv.style.display = "block";
    var wndEl = document.getElementById( "cmz_priceWnd" );
    if ( wndEl )
    {
      wndEl.style.display = "block";
    }
    cmz.cfrmDiv.style.display = "none";
  }
  else
  {
    var formEl = document.getElementById( cmz.priceWnd.formID );
    if ( !formEl )
    {
      alert( "Failed to retrieve submission form" );
      return;
    }
    var inputEl = document.createElement( "input" );
    inputEl.name = name;
    inputEl.value = "1";
    inputEl.type = "hidden";
    formEl.appendChild( inputEl );
    formEl.submit();
  }
}

// open info on selected product
cmz.openInfo = function( sidx, cidx )
{
  if ( cmz.sects[sidx].cats[cidx] )
  {
    // find selected product
    var cid = cmz.sects[sidx].cats[cidx].cid;
    var pid = -1;
    for ( var k = 0; k < cmz.sects[sidx].cats[cidx].prods.length; k++ )
    {
      if ( cmz.sects[sidx].cats[cidx].prods[k].psel == true )
      {
        pid = cmz.sects[sidx].cats[cidx].prods[k].pid;
        break;
      }
    }
    if ( pid != -1 )
      window.open("./more_info.php?c=" + cid + "&p=" + pid, "newwin", "width=" + cmz.infoWndWidth + ",height=" + cmz.infoWndHeight + ",toolbar=0, resizable=1, scrollbars=1");
  }
}

// update total price
cmz.updateTotal = function()
{
  // window
  if ( !cmz.priceEl )
    alert( "Failed to retrieve price window-- price will not be displayed" );
  else
    cmz.priceEl.innerHTML = cmz.moneyFormat( cmz.total_price );
    
  // ...and header
  var spanEl = document.getElementById( "total_price" );
  if ( spanEl )
    spanEl.innerHTML = cmz.moneyFormat( cmz.total_price );
}

// update prices displayed in product radio group
cmz.updateRadioGroup = function( sidx, cidx )
{
  var selPrice = null;
  var defPrice = null;
  for( var k = 0; k < cmz.sects[sidx].cats[cidx].prods.length; k++ )
  {
    if ( cmz.sects[sidx].cats[cidx].prods[k].psel == true )
      selPrice = parseFloat( cmz.sects[sidx].cats[cidx].prods[k].pprice );
    if ( cmz.sects[sidx].cats[cidx].prods[k].pdef == 1 )
      defPrice = parseFloat( cmz.sects[sidx].cats[cidx].prods[k].pprice );
  }
  
  if ( selPrice != null && defPrice != null )
  {
    for( var k = 0; k < cmz.sects[sidx].cats[cidx].prods.length; k++ )
    {
      // be sure to take flat pricing into account
      var priceStr = "";
      if ( cmz.sects[sidx].cats[cidx].prods[k].psel == false )
      {
        var thisPrice = parseFloat( cmz.sects[sidx].cats[cidx].prods[k].pprice );
        if ( cmz.price_type == "F" && ( thisPrice < defPrice ) )
          priceStr = "+$0.00";
        else
        {
          if ( thisPrice < selPrice )
            priceStr = "-" + cmz.moneyFormat( selPrice - thisPrice );
          else
            priceStr = "+" + cmz.moneyFormat( thisPrice - selPrice );
        }
      }
      
      var spanEl = document.getElementById( cmz.sects[sidx].cats[cidx].prods[k].plabel + "_price" );
      if ( !spanEl )
        alert("Error encountered-- prices may be miscalculated" );
      else
        spanEl.innerHTML = priceStr;
    }
  }
  else
    alert( "Error encountered-- prices may be miscalculated" );
}

// price window functions
////////////////////////////////////////////////////////////////////////////////

// loading
cmz.priceWnd.load = function( corner, el )
{
  cmz.priceWnd.corner = corner;
  
  if ( cmz.priceWnd.createDOM( el ) )
  {
    cmz.priceWnd.dock();
    cmz.priceWnd.show();
  }
}

// snap to corner (animated)
cmz.priceWnd.snap = function()
{
  var destX, destY;
  if ( cmz.priceWnd.corner == "top_right" || cmz.priceWnd.corner == "bottom_right" )
    destX = ( cmz.priceWnd.getWinWidth() - cmz.priceWnd.paddingRight - cmz.priceWnd.width ) +
      cmz.priceWnd.getPageOffsetX();
  else
    destX = cmz.priceWnd.paddingLeft + cmz.priceWnd.getPageOffsetX();
  if ( cmz.priceWnd.corner == "bottom_left" || cmz.priceWnd.corner == "bottom_right" )
    destY = ( cmz.priceWnd.getWinHeight() - cmz.priceWnd.paddingBottom - cmz.priceWnd.height ) +
      cmz.priceWnd.getPageOffsetY();
  else
    destY = cmz.priceWnd.paddingTop + cmz.priceWnd.getPageOffsetY();
    
  var curX = parseInt( cmz.priceWnd.div.style.left );
  var curY = parseInt( cmz.priceWnd.div.style.top );
  
  var diffX = destX - curX;
  var diffY = destY - curY;
  
  if ( diffX != 0 || diffY != 0 )
  {
    var newX = curX + Math.ceil( diffX * 0.2 );
    var newY = curY + Math.ceil( diffY * 0.2 );
    cmz.priceWnd.div.style.left = newX + "px";
    cmz.priceWnd.div.style.top  = newY + "px";
    
    setTimeout( cmz.priceWnd.snap, 30 );
  }
  else
  {
    // if we're already there, keep watching, but wait longer
    setTimeout( cmz.priceWnd.snap, 250 );
  }
}

// dock to corner (not animated)
cmz.priceWnd.dock = function()
{
  switch( cmz.priceWnd.corner )
  {
    case "top_left":
      cmz.priceWnd.div.style.top = cmz.priceWnd.paddingTop + "px";
      cmz.priceWnd.div.style.left = cmz.priceWnd.paddingLeft + "px";
      break;
    case "top_right":
      cmz.priceWnd.div.style.top = cmz.priceWnd.paddingTop + "px";
      cmz.priceWnd.div.style.left =
        ( cmz.priceWnd.getWinWidth() - cmz.priceWnd.width - cmz.priceWnd.paddingRight ) + "px";
      break;
    case "bottom_left":
      cmz.priceWnd.div.style.top =
        ( cmz.priceWnd.getWinHeight() - cmz.priceWnd.height - cmz.priceWnd.paddingBottom ) + "px";
      cmz.priceWnd.div.style.left = cmz.priceWnd.paddingLeft + "px";
      break;
    case "bottom_right":
      cmz.priceWnd.div.style.top =
        ( cmz.priceWnd.getWinHeight() - cmz.priceWnd.height - cmz.priceWnd.paddingBottom ) + "px";
      cmz.priceWnd.div.style.left =
        ( cmz.priceWnd.getWinWidth() - cmz.priceWnd.width - cmz.priceWnd.paddingRight ) + "px";
      break;
  }
  
  cmz.priceWnd.snap();
}

// switch corner
cmz.priceWnd.switchCorner = function( corner )
{
  if ( corner == "top_left" || corner == "top_right" ||
    corner == "bottom_left" || corner == "bottom_right" )
  {
    cmz.priceWnd.corner = corner;
    cmz.priceWnd.snap();
  }
}

// hide window
cmz.priceWnd.hide = function()
{
  cmz.priceWnd.div.style.display = "none";
}

// show window
cmz.priceWnd.show = function()
{
  cmz.priceWnd.div.style.display = "block";
}

// create DOM elements
cmz.priceWnd.createDOM = function( el )
{
  // outer div
  cmz.priceWnd.div = document.createElement( "div" );
  cmz.priceWnd.div.id = "cmz_priceWnd";
  cmz.priceWnd.div.className = "cmz_priceOuterDiv";
  cmz.priceWnd.div.style.position = "absolute";
  cmz.priceWnd.div.style.width = cmz.priceWnd.width + "px";
  cmz.priceWnd.div.style.height = cmz.priceWnd.height + "px";
  cmz.priceWnd.div.style.display = "none";
  
  // inner div
  var innerDiv = document.createElement( "div" );
  innerDiv.className = "cmz_priceInnerDiv";
  cmz.priceWnd.div.appendChild( innerDiv );
  
  // inner elements
  var newEl = document.createElement( "div" );
  newEl.className = "cmz_priceLabel";
  newEl.appendChild( document.createTextNode( "Total Price: " ) );
  var spanEl = document.createElement( "span" );
  spanEl.id = "cmz_priceSpan";
  newEl.appendChild( spanEl );
  innerDiv.appendChild( newEl );
  
  // submission elements

  var ulEl = document.createElement( "ul" );
  ulEl.className = "cmz_priceLinkList";
  var liEl = document.createElement( "li" );
  liEl.className = "cmz_priceLink";
  liEl.innerHTML = "<a href=\"#\" onclick=\"cmz.onContinue('save');\">" + cmz.saveText + "</a>";
  ulEl.appendChild( liEl );
  liEl = document.createElement( "li" );
  liEl.className = "cmz_priceLink";
  liEl.innerHTML = "<a href=\"#\" onclick=\"cmz.onContinue('add');\">" + cmz.addText + "</a>";
  ulEl.appendChild( liEl );
  liEl = document.createElement( "li" );
  liEl.className = "cmz_priceLink";
  liEl.innerHTML = "<a href=\"#\" onclick=\"cmz.onContinue('send');\">" + cmz.sendText + "</a>";
  ulEl.appendChild( liEl );
  innerDiv.appendChild( ulEl );
/*
  newEl = document.createElement( "div" );
  newEl.className = "cmz_continue";
  newEl.innerHTML = "<a href=\"#\" onclick=\"cmz.onContinue();\">" + cmz.priceWnd.continueText + "</a>";
  innerDiv.appendChild( newEl );
*/
  // hidden form elements
  var formEl = document.getElementById( cmz.priceWnd.formID );
  if ( !formEl )
  {
    alert( "Failed to retrieve configuration form" );
    return;
  }
  else
  {
    var inputEl = document.createElement( "input" );
    inputEl.name = cmz.priceWnd.idText;
    inputEl.value = cmz.sysid.toString();
    inputEl.type = "hidden";
    formEl.appendChild( inputEl );
  }
  
  // attach price window
  if ( el )
  {
    el.appendChild( cmz.priceWnd.div );
    return true;
  }
  else
  {
    alert( "Failed to create price window" );
    return false;
  }
}

// get window width
cmz.priceWnd.getWinWidth = function()
{
  var width = 0;
  if ( typeof( window.innerWidth ) == "number" )
    width = window.innerWidth;    // non-IE
  else if ( document.documentElement && document.documentElement.clientWidth )
    width = document.documentElement.clientWidth;   // IE 6+
  else if ( document.body && document.body.clientWidth )
    width = document.body.clientWidth;    // IE 4
  return width;
}

// get window height
cmz.priceWnd.getWinHeight = function()
{
  var height = 0;
  if ( typeof( window.innerHeight ) == "number" )
    height = window.innerHeight;    // non-IE
  else if ( document.documentElement && document.documentElement.clientHeight )
    height = document.documentElement.clientHeight;   // IE 6+
  else if ( document.body && document.body.clientHeight )
    height = document.body.clientHeight;    // IE 4
  return height;
}

// get left page offset
cmz.priceWnd.getPageOffsetX = function()
{
  var offset = 0;
  if ( typeof( window.pageXOffset ) == "number" )
    offset = window.pageXOffset;
  else if ( document.body && document.body.scrollLeft )
    offset = document.body.scrollLeft;
  else if ( document.documentElement && document.documentElement.scrollLeft )
    offset = document.documentElement.scrollLeft;
  return offset;
}

// get top page offset
cmz.priceWnd.getPageOffsetY = function()
{
  var offset = 0;
  if ( typeof( window.pageYOffset ) == "number" )
    offset = window.pageYOffset;
  else if ( document.body && document.body.offsetTop )
    offset = document.body.offsetTop;
  else if ( document.documentElement && document.documentElement.scrollTop )
    offset = document.documentElement.scrollTop;
  return offset;
}

// auxiliary functions
////////////////////////////////////////////////////////////////////////////////

// get XML node data
cmz.getXMLNodeVal = function( obj, tag )
{
  var ret = obj.getElementsByTagName( tag );
  if ( !ret || ret.length == 0 || !ret[0].firstChild )
    return null;
  else
    return ret[0].firstChild.nodeValue;
}

// get product position by label
cmz.getPos = function( label )
{
  var ids = label.split( "_" );
  if ( ids.length != 4 )
    return null;
    
  for( var i = 0; i < cmz.sects.length; i++ )
  {
    for( var j = 0; j < cmz.sects[i].cats.length; j++ ) 
    {
      if ( cmz.sects[i].cats[j].clabel == ( ids[0] + "_" + ids[1] + "_" + ids[2] ) )
      {
        for( var k = 0; k < cmz.sects[i].cats[j].prods.length; k++ )
        {
          if ( cmz.sects[i].cats[j].prods[k].plabel == label)
            return ( new cmz.pos( i, j, k ) );
        }
      }
    }
  }
  return null;
}

// report error
cmz.reportErr = function( err )
{
  var errEl = document.createElement( "b" );
  errEl.className = "cmzerr";
  errEl.innerHTML = err;
  cmz.out.appendChild( errEl );
}

// convert number to currency formatted string
// the following code was found at http://javascript.internet.com/ with
// slight code format updates.
// original author information follows:
// Original:  Cyanide_7 (leo7278@hotmail.com)
// Web Site:  http://www7.ewebcity.com/cyanide7
cmz.moneyFormat = function( num )
{
  num = num.toString().replace( /\$|\,/g,'' );
  if ( isNaN( num ) )
    num = "0";
  var sign = ( num == ( num = Math.abs( num ) ) );
  num = Math.floor( ( num * 100 ) + 0.50000000001 );
  var cents = num % 100;
  num = Math.floor( num / 100 ).toString();
  if ( cents < 10 )
    cents = "0" + cents;
  for( var a = 0; a < Math.floor( ( num.length - ( 1 + a ) ) / 3 ); a++ )
    num = num.substring( 0, num.length - ( ( 4 * a ) + 3 ) ) + ',' + num.substring( num.length - ( ( 4 * a ) + 3 ) );
  return ( ( ( sign ) ? '' : '-' ) + '$' + num + '.' + cents );
}
