/*
LiquidPriceCompare.js
2010-04-17T16:12:35-08:00 - Remove addLoadEvent and add addListener(). 
   For validation.
2010-04-16T15:52:09-08:00 - Add 15, 20 and 32 pk, and .373 and 2L
2009-11-12T07:42:40PST - Update event handlers, add more conversions.
2009-05-26T15:07:25PST - Initial release

All code in this file runs in the com.YourFriendPaul.pbLiquidCompare namespace

*/
   // publicly available items
   //  ns.addListener;
   //  ns.addEventHandlers;
   //  ns.showConverters; (shows the calculators if JavaScript is enabled)
   //      and the functions called by the event handlers:
   //  ns.priceChanged;
   //  ns.liquidChanged;
   //  ns.eventInfo;
   
   // for jsLint:
   /*global window */


var com = com || {}; // "var" does nothing if com already exists
com.YourFriendPaul = com.YourFriendPaul || {}; // make the object if needed
com.YourFriendPaul.pbLiquidCompare = com.YourFriendPaul.pbLiquidCompare || {};

(function( ns ){

   function addListener( elem, eType, funcName ){
   
      var oldE, onName = "on" + eType;
      
      if( elem.addEventListener ){
         // add event on the 'bubbling' phase
         return elem.addEventListener( eType, funcName, false );
      }
      
      if( elem.attachEvent ){
         
         return elem.attachEvent( onName, funcName );
      } 
      
      if( elem[ onName ] !== null ){
         
         oldE = elem[ onName ];
         elem[ onName ] = function(e){ oldE(e); funcName(e); };
      }
      
      else {
         
         elem[ onName ] = funcName;
      }
      
      return elem[ onName ];
   }

   function removeListener( elem, eType, funcName ){
   
      var onName = "on" + eType;
      
      if ( elem.removeEventListener ){
         return elem.removeEventListener( eType, funcName, false);
      }
      
      if( elem.detachEvent ){
         
         return elem.detachEvent( onName, funcName );
      }
      
      // don't even try with the functions added like onload=...
      return null;
      
   }
   
   // elem can be an id or an element
   ns.addListener = function( elem, eType, funcName ){
   
      var oldE, onName = "on" + eType, elemName = elem;
      
      if( typeof elem === 'string' ){
      
         elem = document.getElementById( elemName );
         if( null === elem ){ 
            //alert( 'addListener: no name for ' + elemName );
            alert( 'addListener :' + elem.id + ', ' + eType + ', ' + funcName );
            return elem; 
         }
      }
      
      //alert( 'addListener: ' + elem.id + ', ' + eType + ', ' + funcName );
      if( elem.addEventListener ){
         // add event on the 'bubbling' phase
         return elem.addEventListener( eType, funcName, false );
      }
      
      if( elem.attachEvent ){
         
         return elem.attachEvent( onName, funcName );
      } 
      
      if( elem[ onName ] !== null ){
         
         oldE = elem[ onName ];
         elem[ onName ] = function(e){ oldE(e); funcName(e); };
      }
      
      else {
         
         elem[ onName ] = funcName;
      }
      
      return elem[ onName ];
   };

   function literToFlOz( lit ){
      return( lit * 33.8140225589 );
   }

   function flOzToLiter( floz ){
      return( floz / 33.8140225589 );
   }
   

   // all of the IDs that will be affected by a price change
   function priceIdList(){
      return [ "cp1p", "cp6p", "cp12p", "cp15p", "cp20p", "cp24p", "cp30p", "cp32p", "cp36p", "cp375ml", "cp500ml", "cp750ml", "cp1l", "cp1750ml", "cp2l", "cp3l", "cp5l" ];
   }
   
   function fluidIdList(){
   
      return [ "lfFloz", "lfLit", "lf12oz", "lf2Lit" ];
   }

   // gives the number to multiply by the 1oz cost to get the total cost
   function conversions(){
      var convList = { 
         "cp1p": 12, 
         "cp6p": 6*12, 
         "cp12p": 12*12,
         "cp15p": 15*12,
         "cp20p": 20*12,
         "cp24p": 24*12,
         "cp30p": 30*12,
         "cp32p": 32*12,
         "cp36p": 36*12,
         "cp375ml": literToFlOz( 0.375 ),
         "cp500ml": literToFlOz( 0.5 ),
         "cp750ml": literToFlOz( 0.75 ),
         "cp1l": literToFlOz( 1 ),
         "cp1750ml": literToFlOz( 1.75 ),
         "cp2l": literToFlOz( 2 ),
         "cp3l": literToFlOz( 3 ),
         "cp5l": literToFlOz( 5 ),

         "lfFloz": 1,
         "lfLit": literToFlOz( 1 ),
         "lf12oz": 12,
         "lf2Lit": literToFlOz( 2 )
      }; 
      return convList; 
   }


   function make2dFixed( num ){
   
      return ( Math.round ( 100 * num ) / 100 ).toFixed( 2 );
   }
   
   function hasIllegalChar( val ){
   
      /*
      find if any illegal characters: 
      allow 0-9, whitespace and .*+/-= and xX (in case someone uses x to multiply)
      also allow $ and ()
      */
      var illegalPos = val.search( /[^\d\.\*\+\/\-=xX\$\(\)]/ );
      
      if( illegalPos !== -1 ){
         alert( "'" + val.charAt ( illegalPos ) + "' is not allowed in\n\"" + val + "\"" );
         return true;
      }
      
      return false;
   }

   // perform simple math, such as to allow inputs like $10/4
   function doTheMath( val ){
   
      var intVal, iv;
      
      // get rid of and whitespace, dollar and equal signs 
      val = val.replace( /[\s\$=]+/g, '' );
      intVal = parseFloat( val );
      // it's just a number, no processing needed
      if( intVal === val - 0 ){ return intVal; }
      
      // x isn't a valid way to multiply, so fix it
      val = val.replace( /[xX]+/g, '*' );
      iv = eval( val );

      //else alert( 'val, iv: ' + val + ', ' + iv );
      //alert( 'intVal is a ' + typeof intVal + ", iv is a " + typeof iv );
      return iv;
   }
   
   // a liquid value changed
   ns.liquidChanged = function( e ){

      var elem, iCount, ids, oneOzValue, convValue, convList, val;
      
      if( null === e || typeof e.id !== "string" ){ return; }
      
      elem = document.getElementById( e.id );
      
      // don't process if illegal
      if( hasIllegalChar( elem.value ) ){
      
         return;
      }

      try{
         // evaluate any expressions
         val = doTheMath( elem.value );
      } catch( err ) {
         alert( "There is a problem with the equation:\n" + elem.value );
         return;
      }

      // handle an empty field
      if( typeof val !== 'number' ) { return; }
      
      convValue = 0;
      ids = fluidIdList();
      convList = conversions();
      
      // find the conversion factor for the field that changed
      for( iCount = 0; iCount < ids.length; iCount++ ){
      
         if( e.id === ids[ iCount ] ){

            convValue = convList[ ids[ iCount ] ];
            //alert( "conversion is " + convValue );
            break;
         }
      }
      
      if( convValue === 0 ){ alert( e.id + " not found" ); }

      // convert the number input to ounces
      oneOzValue = val * convValue;

      // change all the other values to match the new cost per ounce
      for( iCount = 0; iCount < ids.length; iCount++ ){
      
         elem = document.getElementById( ids[ iCount ] );
         
         // don't change the value the was entered
         if( ids[ iCount ] !== e.id ){
         
            elem.value = Math.round ( 10000 * oneOzValue / convList[ ids[ iCount ] ] ) / 10000;
         }
         else {
         
            elem.value = val;
         }
      }
   };
   
   // deal with a price change
   ns.priceChanged = function( e ){

      var elem, oneOzValue, convValue, iCount, priceIds, val, convList;
      
      if( null === e || typeof e.id !== "string" ){ return; }
      
      elem = document.getElementById( e.id );

      if( hasIllegalChar( elem.value ) ){
      
         return;
      }

      try {
         val = doTheMath( elem.value );
      } catch( err ) {
         alert( "There is a problem with the equation:\n" + elem.value );
         return;
      }
      
      // handle an empty field
      if( typeof val !== 'number' ) { return; }

      convValue = 0;
      priceIds = priceIdList();
      convList = conversions();
      
      // find the conversion factor for the field that changed
      for( iCount = 0; iCount < priceIds.length; iCount++ ){
      
         if( e.id === priceIds[ iCount ] ){
            
            convValue = convList[ priceIds[ iCount ] ];
            break;
         }
      }
      
      if( convValue === 0 ){ alert( e.id + " not found" ); }

      // convert to a standard cost per ounce
      oneOzValue = val / convValue;

      // change all the other values to match the new cost per ounce
      for( iCount = 0; iCount < priceIds.length; iCount++ ){
      
         elem = document.getElementById( priceIds[ iCount ] );

         // don't change the value the was entered
         if( priceIds[ iCount ] !== e.id ){
         
            //elem.value = Math.round ( 100 * oneOzValue * convList[ priceIds[ iCount ] ] ) / 100;
            elem.value = "$" + make2dFixed( oneOzValue * convList[ priceIds[ iCount ] ] );
         }
         else {
         
            // can loose precision now and make the display the same as the others
            elem.value = "$" + make2dFixed( val );
         }
      }
   };
   
   ns.eventInfo = function( e ){

      var ei = {
         event: e || window.event,
         target: null,
         keycode: null
      };
      
      ei.keycode = ei.event.keyCode || ei.event.which;
      ei.target = ei.event.target || ei.event.srcElement;
      if( ei.target.nodeType === 3 ){ // defeat Safari bug
            ei.target = ei.target.parentNode;
      }
      
      return ei;
   };

   // event handlers
   // only keydown is now used
   var fPriceKeydown = function( e ){
      var ei = ns.eventInfo( e );
      if ( ei.keycode === 13 ) { return ns.priceChanged( ei.target ); }
      return(e);
   };

   var fLiquidKeydown = function( e ){
      var ei = ns.eventInfo( e );
      if ( ei.keycode === 13 ) { return ns.liquidChanged( ei.target ); }
      return(e);
   };

   ns.addEventHandlers = function(){
   
      var iCount, elem, ids = [];

      ids = priceIdList();
      
      // set price converter listeners
      for( iCount = 0; iCount < ids.length; iCount++ ){
      
         elem = document.getElementById( ids[ iCount ] );
         addListener( elem, "keydown", fPriceKeydown );
      }

      ids = fluidIdList();
      
      // set price converter listeners
      for( iCount = 0; iCount < ids.length; iCount++ ){
      
         elem = document.getElementById( ids[ iCount ] );
         addListener( elem, "keydown", fLiquidKeydown );
      }
   };
   
   // show the converters if JavaScript is enabled
   ns.showConverters = function(){
      var elem = document.getElementById( "converters" );
      elem.style.display = "block";

   };
   

// execute with namespace to be used
})( com.YourFriendPaul.pbLiquidCompare );

com.YourFriendPaul.pbLiquidCompare.addListener( window, 'load', com.YourFriendPaul.pbLiquidCompare.addEventHandlers );
com.YourFriendPaul.pbLiquidCompare.addListener( window, 'load', com.YourFriendPaul.pbLiquidCompare.showConverters );
