
/*  JavaScript: VolumeCalculator.js                   /
/   Provides class VolumeCalculatorObject             /
/   By eKerner@eKerner.com for CapitalRemoval.com.au */

// begin class volumeCalculator ...
function VolumeCalculatorObject()
{
  // form/input fields container ...
  this.inputItems          = new Array()
  var interfaceColspan     = 5;
  var interfaceWidthPixels = 750;
  
  // adds or sets a this.inputItems ...
  this.setInputItem = function(category, item, volume)
  {
    if (! this.inputItems[category]      ) this.inputItems[category]       = new Array();
    if (! this.inputItems[category][item]) this.inputItems[category][item] = new Array();
    this.inputItems[category][item]['volume'] = volume;
  }
  
  // sets private var interfaceColspan ...
  this.setInterfaceColspan = function(colspan)
  {
    interfaceColspan = colspan;
  }
  
  // sets private var interfaceWidthPixels ...
  this.setInterfaceWidthPixels = function(widthPixels)
  {
    interfaceWidthPixels = widthPixels;
  }
      
  // accessor for this.inputItems.category.item.volume ...
  this.getInputItemVolume = function(itemName)
  {
    for (categoryName in this.inputItems)
      if (this.inputItems[categoryName] && this.inputItems[categoryName][itemName])
        return this.inputItems[categoryName][itemName]['volume'];
    return 0;
  }
  
  // accessor for form.item.value ...
  this.getInputItemValue = function(itemName)
  {
    return document.volumeCalculatorForm[itemName].value
  }
  
  // accessor for form.item ...
  this.getInputItemElem = function(itemName)
  {
    return document.volumeCalculatorForm.elements[itemName];
  }
  
  // returns array of item names in category, or all items if category = '' ...
  this.getInputItemNames = function(category)
  {
    var itemNames = new Array();
    var categoryNames;
    if (category == '')
      categoryNames = this.getInputCategoryNames();
    else
      categoryNames = new Array(category);
    for (var categoryNamesIndex in categoryNames)
      for (var itemName in this.inputItems[categoryNames[categoryNamesIndex]])
        itemNames.push(itemName);
    return itemNames;
  }

  // returns array of category names/headings  ...
  this.getInputCategoryNames = function()
  {
    var categoryNames = new Array();
    for (var categoryName in this.inputItems)
      categoryNames.push(categoryName);    
    return categoryNames;
  }
  
  this.getInventoryList = function()
  {
    var inventory = Array();
    for (var categoryName in this.inputItems) {
      var itemNames = this.getInputItemNames(categoryName);
      for (var itemNamesIndex in itemNames) {
        var val = this.getInputItemValue(itemNames[itemNamesIndex]);
        if (val.match(/^\d+$/) && val > 0) inventory.push(val + ' x ' + itemNames[itemNamesIndex].replace(/_+/g, ' '));
      }
    }
    return inventory.join('\n');
  }

  // draw form in passed targetDivId and hook up calculate button to callbackHandler
  this.drawUserInterface = function(targetDivId, callbackHandler)
  {
    var volumeCalculatorDiv    = document.getElementById(targetDivId);
    var resultsTableRowIndex   = 0;
    var expandCollapseDivIndex = 0;
    var innerHTML  = '<form name=volumeCalculatorForm method=post action="" onsubmit="' + callbackHandler + '(); return false;">\n' +
                     '<table style="border:1px solid #0062A6" cellpadding=2px cellspacing=2px width="' + interfaceWidthPixels + 'px">\n' +
                     '<tr><td class=tableHeader>Furniture Removal Volume Calculator<br>\n<div style="text-align:right;width:100%;font-size:11px">by ' + 
                     '<a href="http://www.capitalremoval.com.au/" title="Visit Capital Removal" target="_blank">CapitalRemoval.com.au</a></div>\n' +
                     '</td></tr>\n' + this.buildResultsTableRow(callbackHandler, resultsTableRowIndex++) + this.buildMenuTableRow(callbackHandler);
    for (var categoryName in this.inputItems)
    {
      innerHTML += '<tr>\n<td class=categoryHeader>\n<a name="' + categoryName + 'Anchor"></a>\n' +
                   '<div style=float:left>' + categoryName.replace(/_/g, ' ').toUpperCase() + '</div>\n' +
                   '<div style=float:none align=right>\n<input type=button name="expandCollapseBtn' + expandCollapseDivIndex + 
                   '" title="Expand Category" value="+" onclick="expandCollapseVolumeCalculatorDiv(' + 
                    expandCollapseDivIndex + ', this)" class=button>\n</div>\n</td>\n</tr>\n' + 
                   '<tr>\n<td>\n<div id="expandCollapseDiv' + (expandCollapseDivIndex++) + '" style="position:relative;display:none">' +
                   '<table style="width:100%" cellpadding=2px cellspacing=2px>\n<tr>\n';
      var itemNames = this.getInputItemNames(categoryName);
      for (var itemNamesIndex = 0; itemNamesIndex < itemNames.length;)
      {
        for (var cellIndex = 0; cellIndex < interfaceColspan; cellIndex++)
          if (itemNamesIndex < itemNames.length)
          {
            innerHTML += '<td class=listBody>\n<table width="100%"><tr><td>' + itemNames[itemNamesIndex].replace(/_/g, ' ') + 
                         ':</td>\n<td style="text-align:right"><input type=text name="' + itemNames[itemNamesIndex] + 
                         '" value="" size=2></td></tr></table>\n</td>\n';
            itemNamesIndex++;
          }
          else
            innerHTML += '<td class=listBody>&nbsp;</td>\n';
          if (itemNamesIndex < itemNames.length)
            innerHTML += '</tr><tr>\n';
      }
      innerHTML += '</tr>\n</table>\n</div>\n</td>\n</tr>\n';
    }
    innerHTML += this.buildMenuTableRow(callbackHandler) + this.buildResultsTableRow(callbackHandler, resultsTableRowIndex); + '</table>\n</form>\n';
    volumeCalculatorDiv.innerHTML = innerHTML;
  }
  
  // builds the calculate button and results divs ...
  this.buildResultsTableRow = function(callbackHandler, resultsTableRowIndex)
  {
    return '<tr>\n<td class=calculateBar>\n' +
           '<table style="width:100%;" border=0 cellpadding="2px" cellspacing=0>\n' +
           '<tr>\n<td rowspan=2><input type=submit value=Calculate onclick="' + callbackHandler + '(); return false;" class=button></td>\n' +
           '<td style="text-align:right; font-weight:bold">Total Cubic Metres = </td>\n' +
           '<td><div id=cubicMetersResultDiv' + resultsTableRowIndex + ' style="width:100%; text-align:right; color:#F08000; font-weight:bold; font-size:14px">0.00</div></td>\n' +
           '</tr><tr>\n<td style="text-align:right; font-weight:bold">Total Cubic Feet&nbsp;&nbsp; = </td>\n' +
           '<td><div id=cubicFeetResultDiv' + resultsTableRowIndex + ' style="width:100%; text-align:right; color:#F08000; font-weight:bold; font-size:14px">0.00</div></td>\n' +
           '</tr>\n</table>\n</td>\n</tr>\n';
  }
  
  // builds the collapse/expand all buttons table row ...
  this.buildMenuTableRow = function(callbackHandler)
  {
    return '<tr>\n<td class=calculateBar style="text-align:right">\n<input type=button title="Reset Form" value="Reset" ' +
           'onClick="this.form.reset();expandCollapseVolumeCalculatorDivs(\'-\');' + callbackHandler + '()" class=button>\n' +
           '<input type=button title="Collapse All" value="--" onClick="expandCollapseVolumeCalculatorDivs(\'-\')" class=button>\n' +
           '<input type=button title="Expand All" value="++" onClick="expandCollapseVolumeCalculatorDivs(\'+\')" class=button>\n' +
           '</td>\n</tr>\n';
  }
  
  // tally input volumes - must be called by user from callbackHandler ...
  this.calculateVolume = function()
  {
    var totalCubicMeters = 0;
    var itemNames = this.getInputItemNames('');
    for (var itemNamesIndex in itemNames)    
    {
       var itemValue = this.getInputItemValue(itemNames[itemNamesIndex]);
       if (! itemValue)
         itemValue = 0;
       else if (! itemValue.match(/^\d+$/))
       {
         this.reportCalculationResult('error', 'error');
         alert('Invalid Qty Value: "' + itemValue + '" for Item: "' + itemNames[itemNamesIndex] + '"!');
         this.getInputItemElem(itemNames[itemNamesIndex]).focus();
         return 0;
       }
       totalCubicMeters += parseFloat(itemValue * this.getInputItemVolume(itemNames[itemNamesIndex]));
    }
    totalCubicMeters = this.roundUpToDecimalPlaces(totalCubicMeters, 2);
    this.reportCalculationResult(
      totalCubicMeters, 
      this.roundUpToDecimalPlaces(this.cubicMetersToCubicFeet(totalCubicMeters), 2)
    );
    return totalCubicMeters;
  }

  // sets the results divs as select ...
  this.reportCalculationResult = function(cubicMeters, cubicFeet)
  {
    document.getElementById('cubicMetersResultDiv0').innerHTML = cubicMeters;
    document.getElementById('cubicFeetResultDiv0'  ).innerHTML = cubicFeet;
    document.getElementById('cubicMetersResultDiv1').innerHTML = cubicMeters;
    document.getElementById('cubicFeetResultDiv1'  ).innerHTML = cubicFeet;
  }
  
  // conversion ...
  this.cubicFeetToCubicMeters = function(cubicFeet)
  {
    return (cubicFeet * 0.0283168466);
  }
  
  // conversion ...
  this.cubicMetersToCubicFeet = function(cubicMeters)
  {
    return (cubicMeters / 0.0283168466);
  }
  
  // round up to 2 decimal places ...
  this.roundUpToDecimalPlaces = function(floatingPointNumber, decimalPlaces)
  {
    var roundedUpValue = '' + (Math.ceil(floatingPointNumber * 100) / 100);
    var decimalIndex   = roundedUpValue.indexOf('.');
    var floatLength    = 0;
    if (decimalIndex == -1)
      roundedUpValue += decimalPlaces > 0 ? '.' : ''
    else
        floatLength = roundedUpValue.length - decimalIndex - 1;
    for (var i = 0; i < (decimalPlaces - floatLength); i++)
      roundedUpValue += '0';
    return roundedUpValue;
  }
  
} 
// ... end class volumeCalculator

// global func used by interface ...
function setExpandCollapseDivAndButton(divElem, btnElem, expand)
{
  if (expand)
  {
    divElem.style.display = 'block';
    btnElem.value         = '-';
    btnElem.title         = 'Collapse Category';
  }
  else
  {
    divElem.style.display = 'none';
    btnElem.value         = '+';
    btnElem.title         = 'Expand Category';
  }
}

// global func used by interface ...
function expandCollapseVolumeCalculatorDiv(divNo, btnElem)
{
  var divElem = document.getElementById('expandCollapseDiv' + divNo);
  setExpandCollapseDivAndButton(divElem, btnElem, divElem.style.display == 'none');
}

// global func used by interface ...
function expandCollapseVolumeCalculatorDivs(expandCollapse)
{
  for (var expandCollapseDivIndex = 0; ; expandCollapseDivIndex++)
  {
    var divElem = document.getElementById('expandCollapseDiv' + expandCollapseDivIndex);
    var btnElem = document.volumeCalculatorForm['expandCollapseBtn' + expandCollapseDivIndex];
    if (! divElem) break;
    setExpandCollapseDivAndButton(divElem, btnElem, expandCollapse == '+');
  }
}
