function init() {
  Calc.init();
  Calc.serialize();
  // Calc.render();
  // initSlider();
}
function initSlider() {
  var slider = $('volume_slider');
  Calc.volume_slider = new Control.Slider(slider.select('.handle'), slider.select('.track')[0], {
    range: $R(0,140),
    sliderValue: 0,
    onSlide: function(value) {
      Calc.onSlide(value);
    },
    onChange: function(value) {
      Calc.onSliderChange(value);
    }
  });
  
  var marks = slider.select('span');
  var w = slider.getWidth();
  for (var i=0; i < marks.length; i++) {
    var mark = marks[i];
    var l = (w / (marks.length - 1)) * i;
    if (i > 0) l -= mark.getWidth() / 2;
    mark.setStyle({left:l+'px'});
  };
  
  // event for removing focus of any input fields
  Calc.volume_slider.handles[0].observe('mousedown', Calc.blur);
}
// Element.observe(window, 'load', init);
document.observe('dom:loaded', init);

function blank(value) {
  switch(typeof value) {
    case 'undefined': return true;
    case 'string':    return value.length == 0;
    case 'number':    return isNaN(value);
    default:          return false;
  }
}
function adjustedVolumeValue(val) {
  if (val > 100) val = (val - 100) / (140 - 100) * 400 + 100;
  return val;
}
function fillSlider(id, value, max) {
  $(id).setStyle({width : ((value / max) * 100) + '%'});
}
function calculate() {
  for (var i=0; i < Calc.inputs.length; i++) {
    if( blank(Calc.value(Calc.inputs[i])) ) {
      alert("Please complete all fields before calculating results.")
      return;
    }
  };
  $('intro').hide();
  $('outputs').show();
  $('volume').show();
  Calc.reveal = true;
  initSlider();
  Calc.render();
}

var Calc = {
  inputs: $w("cat alpm blpm acrt bcrt aasp basp"),
  outputs: $w("subscription auction_if bin_if auction_fvf bin_fvf total"),
  values: { },
  original_values: { },
  upper: Math.pow(10,10),
  reveal: false,
  zone: 'uk',
  
  init: function() {
    $$("input").each(function(input) {
      input.observe('change', Calc.onInputChange);
    });
  },
  
  serialize: function() {
    return Calc.values = $('form').serialize(true);
  },
  
  // return a value from the values object
  value: function(key) {
    var val = Calc.values[key];
    if (key == 'cat' || val == undefined) {
      return val;
    } 
    else {
      return val.toNumber();
    } 
  },
  
  // Form events
  onInputChange: function(evt) {
    var t = evt.target;
    if (t.name != "cat") {
      var val = t.value.toNumber();
      Calc.original_values[t.name] = val;
      if (isNaN(val)) {
        t.value = "";
      }
      else if (t.name.indexOf("crt") > 0) {
        // t.value = (val > 100) ? 100 : val;
      }
      else if (t.name.indexOf("asp") > 0) {
        t.value = (val > Calc.upper ? Calc.upper : val);
      }
      // reset volume slider
      if (!blank(Calc.volume_slider) && (t.name == 'blpm' || t.name == 'bcrt')) {
        Calc.volume_slider.setValue(0);
      };
    };
    Calc.serialize();
    if (Calc.reveal) Calc.render();
  },
  
  onSlide: function(value) {
    Calc.renderVolumeValue(value);
    Calc.adjustListingsFromVolume(value);
    Calc.serialize();
    Calc.render();
  },
  
  onSliderChange: function(value) {
    Calc.renderVolumeValue(value);
    Calc.adjustListingsFromVolume(value);
    Calc.serialize();
    Calc.render();
  },
  
  // kill focus of any input fields
  blur: function() {
    $('form').select('input').each(function(input){
      input.blur();
    });
  },
  
  adjustListingsFromVolume: function(value) {
    // increase fixed price listing values
    var adjusted_value = adjustedVolumeValue(value);
    var lpm = Calc.original_values.blpm;
    var crt = Calc.original_values.bcrt;
    if (blank(lpm)) {
      lpm = Calc.value('blpm');
      Calc.original_values.blpm = lpm;
    }
    if (blank(crt)) {
      crt = Calc.value('bcrt');
      Calc.original_values.bcrt = crt;
    }
    if (blank(lpm) || blank(crt)) return;
    var ratio = crt / lpm;
    var new_lpm = Math.round(lpm + lpm * (adjusted_value / 100));
    var new_crt = Math.round(new_lpm * ratio);
    
    // Prevent NaN from displaying
    if(isNaN(new_lpm)) new_lpm = 0;
    if(isNaN(new_crt)) new_crt = 0;
    
    $('blpm').value = new_lpm;
    $('bcrt').value = new_crt;
  },
  
  // Calculate values of each output
  
  // Subscription value:
  // Fixed for each store type
  calcSubscription: function(store_type) {
    if (Calc.zone == 'ie') {
      return [0, 19.99, 59.99, 449.99][store_type];
    }
    else {
      return [0, 14.99, 49.99, 349.99][store_type];
    }
  },
  
  // Auction insertion fees:
  // auction_listings_per_month * insertion_fee
  // Other:0.10, Tech:0.10, Media:0.05
  calcAuctionIf: function() {
    var cat = Calc.value('cat');    // selected category
    var lpm = Calc.value('alpm');   // auction listings per month
    if (blank(cat) || blank(lpm)) { return 0 };
    var fees = (Calc.zone == 'ie') ? [0.15, 0.07] : [0.1, 0.05]; // fees for [all+tech, media]
    var insertion_fee = (cat == 'media') ? fees[1] : fees[0];
    return lpm * insertion_fee;
  },
  
  calcBinIf: function(store_type) {
    var cat = Calc.value('cat');
    var lpm = Calc.value('blpm');
    if (blank(lpm) || blank(cat)) { return 0 };
    // Fees [no shop, basic, featured, anchor]
    if (Calc.zone == 'ie') {
      var fees = (cat == 'media') ? [0.25, 0.13, 0.06, 0.02] : [0.5, 0.2, 0.06, 0.02];
    }
    else {
      var fees = (cat == 'media') ? [0.2, 0.1, 0.05, 0.01] : [0.4, 0.2, 0.05, 0.01];
    }
    var insertion_fee = fees[store_type];
    return lpm * insertion_fee;
  },
  
  calcAuctionFvf: function() {
    var cat = Calc.value('cat');  // category
    var lpm = Calc.value('alpm')  // listings per month
    var crt = Calc.value('acrt'); // auction conversion rate
    var asp = Calc.value('aasp'); // average sell price
    var total = 0;
    var fees = [];
    if (blank(cat) || blank(crt) || blank(asp) || blank(lpm)) return 0;
    if (cat == 'media') {
      total = asp * 0.09;
    } 
    else if (cat == 'tech') {
      if (Calc.zone == 'ie') {
        fees = [[49.99, 0.0525], [149.99, 0.03], [299.99, 0.025], [499.99, 0.02], [899.99, 0.015], [Calc.upper, 0.01]];
      } 
      else {
        fees = [[29.99, 0.0525], [99.99, 0.03], [199.99, 0.025], [299.99, 0.02], [599.99, 0.015], [Calc.upper, 0.01]];
      }
      total = Calc.fvfTotal(asp, fees);
    } 
    else {
      if (Calc.zone == 'ie') {
        fees = [[49.99, 0.0875], [899.99, 0.0525], [Calc.upper, 0.015]];
      }
      else {
        fees = [[29.99, 0.0875], [599.99, 0.0525], [Calc.upper, 0.015]];
      }
      total = Calc.fvfTotal(asp, fees);
    }
    // return total * ((crt / 100) * lpm);
    return total * crt; // conversion rate has changed to absolute value
  },
  
  // Fixed price (Buy It Now) final value fee
  calcBinFvf: function(store_type) {
    var cat = Calc.value('cat');  // category
    var lpm = Calc.value('blpm')  // listings per month
    var crt = Calc.value('bcrt'); // auction conversion rate
    var asp = Calc.value('basp'); // average sell price
    var total = 0;
    var fees = [];
    if (blank(cat) || blank(crt) || blank(asp) || blank(lpm)) return 0;
    if (cat == 'media') {
      total = asp * 0.09;
    }
    else if (cat == 'tech') {
      if (Calc.zone == 'ie') {
        fees = [[49.99, 0.0525], [149.99, 0.03], [299.99, 0.025], [499.99, 0.02], [899.99, 0.015], [Calc.upper, 0.01]];
      } else {
        fees = [[29.99, 0.0525], [99.99, 0.03], [199.99, 0.025], [299.99, 0.02], [599.99, 0.015], [Calc.upper, 0.01]];
      }
      total = Calc.fvfTotal(asp, fees);
    } 
    else {
      if (Calc.zone == 'ie') {
        fees = [[69.99, 0.099], [899.99, 0.059], [Calc.upper, 0.019]];
      }
      else {
        fees = [[49.99, 0.099], [599.99, 0.059], [Calc.upper, 0.019]];
      }
      total = Calc.fvfTotal(asp, fees);
    };
    // return total * ((crt / 100) * lpm);
    return total * crt; // conversion rate has changed to absolute value
  },
  
  fvfTotal: function(average_sell_price, fees_array) {
    var total = 0;
    var previous_limit = 0;
    for (var i=0; i < fees_array.length; i++) {
      var limit = fees_array[i][0];
      var pct   = fees_array[i][1];
      var value = (average_sell_price > limit ? limit : average_sell_price) - previous_limit;
      if(value > 0) total += value * pct;
      previous_limit = limit;
    };
    return total;
  },
  
  // Sum of all values
  // Returns 0 if any input field is blank
  calcTotal: function(store_type) {
    if (Calc.inputs.any(function(input){ 
      return blank(Calc.value(input))
    })) return 0;
    return Calc.outputs.inject(0, function(sum, attribute) {
      return sum + (attribute == 'total' ? 0 : Calc.calcValue(attribute, store_type));
    });
  },
  
  // Calculation helper
  calcValue: function(attribute, store_type) {
    switch(attribute) {
      case 'subscription': return Calc.calcSubscription(store_type);
      case 'auction_if':   return Calc.calcAuctionIf();   
      case 'bin_if':       return Calc.calcBinIf(store_type);       
      case 'auction_fvf':  return Calc.calcAuctionFvf();  
      case 'bin_fvf':      return Calc.calcBinFvf(store_type);      
      case 'total':        return Calc.calcTotal(store_type);       
    }
  },
  
  render: function() {
    Calc.renderData();
  },
  
  // Display data matrix
  renderData: function() {
    Calc.outputs.each(function(output) {
      for (var store_type=0; store_type <= 3; store_type++) {
        var value = Calc.calcValue(output, store_type);
        
        // Values >= 1,000,000.00 blow the HTML outside of the iframe, so limit them
        if(value>=1000000) value = 999999.99;
        
        var id = output + '_' + store_type;
        $(id).innerHTML = value == 0 && id != 'subscription_0' ? '-' : value.toCurrency({unit:(Calc.zone == 'ie' ? '€' : '£')});
      };
    });
  },
  
  renderVolumeValue: function(value) {
    var adjusted_value = adjustedVolumeValue(value);
    fillSlider('volume_fill', value, 140);
    $('vol').value = adjusted_value;
    $('volume_value').innerHTML = '+' + Math.round(adjusted_value) + '%';
  }
};

Object.extend(Number.prototype, {
  toCurrency: function(options) {
    if (!options) var options = {};
    if (!options.unit) options.unit = '£';
    if (!options.precision) options.precision = 2;
    if (!options.delimiter) options.delimiter = ',';
    if (!options.separator) options.separator = '.';
    
    var parts = this.toFixed(options.precision).split('.');
    var dollars = Number(parts[0]).toDeliminated(options.delimiter);
    var cents = parts[1];
    
    return options.unit + dollars + options.separator + cents;
  },
  
  toDeliminated: function(delimiter, separator) {
    if (!delimiter) delimiter = ',';
    if (!separator) separator = '.';
    var output = '';
    var parts = String(this).split('.');
    output += parts[0].replace(/(\d)(?=(\d\d\d)+(?!\d))/g, "$1" + delimiter);
    if (parts[1] != undefined && parts[1].length > 0)
      output += separator + parts[1];
    return output;
  }
});

Object.extend(String.prototype, {
  toNumber: function() {
    val = this.replace(/[^0-9.]/g,'');
    return val == "" ? NaN : Number(val);
  }
});
