/**
 * Author: Sebastian Rose <sebastian_rose at gmx.de>
 * ALL RIGHTS RESERVED
 *
 *
 * Zunächst wird der Grundpreis an Hand der Staffelungen errechnet.
 * 2. werden die Summanden als erstes auf den Grundpreis
 * aufgeschlagen.
 * 3. wird der Grundpreis mit den Faktoren multiplizert. Im Falle
 * des Plakatshops sollte das nur das Format sein.
 * 4. werden die Equals (Fixkosten) einfach aufaddiert.
 * Zu guter Letzt kommt die MwSt drauf und gut.
 *
 * Wird ein Rabatt gewährt, wird dieser schließlich aus dem Endpreis
 * errechnet.
 *
 * Staffel- oder Stückpreise werden es von ganz allein. Gibt man nur
 * eine Preisstaffel an, wird die gesammte Betellmenge mit diesem Preis
 * berechnet.
 */


/**
 * Konstruktor eines Preisrechners.
 */
function SRJSPreisrechner (formElement)
{
  // Konstanten:
  this.FACTOR  = 0;             // Alles hiermit multiplizieren.
  this.SUMMAND = 1;             // Preisaufschlag. Wird mit Auflage
                                // Multipliziert.
  this.EQUAL   = 2;             // Genau diesen Preis auf alles
                                // aufschlagen: z.B. Einrichtungsgeb.
  this.TEXT    = 3;             // Bestellmengeneingabe = Textfeld
  this.SELECT  = 4;             // Bestellmengeneingabe = select
  // Fields. PRIVATE
  this.Rex            = /\D$/;
  this.FloatExchange  = /(\d*)+(\.)?(\d*)/;
  this.IntExchange    = /(\d*)/;
  this.FacSelects     = new Object();
  this.SumSelects     = new Object();
  this.EquSelects     = new Object();
  this.Taxrate        = 0;
  this.FixPrice       = 0;
  this.FORM           = formElement;
  this.QElement       = null;
  this.QType          = this.TEXT; // Tatsächlicher Typ der
                                   // Bestellmengeneingabe.
  this.QTY            = 1;         // Voreingest. Bestellmenge.
  this.PPBElement     = null;
  this.BSelect        = null;
  this.PPB            = 1;         // Voreingest. Menge der Seiten pro Bindung
  this.PPBType        = this.TEXT; // Tatsächlicher Typ der
                                   // Bindungsmengeneingabe.
  this.Prices          = new Array();
  this.BindPrices      = new Array();
  this.someOfThePages  = new Array();
  this.showIfPrice     = new Array();
  this.FixPrice        = 0;
  this.Surcharge       = -1; // absoluter Wert
}


SRJSPreisrechner.prototype.useBindings = function()
{
  if ( null != this.PPBElement && null != this.BSelect) return true;
  return false;
};


SRJSPreisrechner.prototype.addFixpreis = function(floatPreis)
{
  this.FixPrice += parseFloat(floatPreis);
};


SRJSPreisrechner.prototype.update = function()
{
  this.getQuantity(); // Alles updaten, was zum Rechnen erforderlich ist.
  if ( isNaN(this.QTY) || this.QTY == 0 ) {
    if(this.FORM.srjsPRDisplayNetto) { this.FORM.srjsPRDisplayNetto.value = '0.00'; this.resizeDisplay(this.FORM.srjsPRDisplayNetto, 4); }
    if(this.FORM.srjsPRDisplayMwst) { this.FORM.srjsPRDisplayMwst.value = '0.00'; this.resizeDisplay(this.FORM.srjsPRDisplayMwst, 4); }
    if(this.FORM.srjsPRDisplayBrutto) { this.FORM.srjsPRDisplayBrutto.value = '0.00'; this.resizeDisplay(this.FORM.srjsPRDisplayBrutto, 4); }
    if(-1 != this.Surcharge) {
      if(this.FORM.srjsPRSurchargeNettoDisplay) { this.FORM.srjsPRSurchargeNettoDisplay.value = '0.00'; this.resizeDisplay(srjsPRSurchargeNettoDisplay, 4); }
      if(this.FORM.srjsPRSurchargeMwstDisplay) { this.FORM.srjsPRSurchargeMwstDisplay.value = '0.00'; this.resizeDisplay(srjsPRSurchargeMwstDisplay, 4); }
      if(this.FORM.srjsPRSurchargeBruttoDisplay) { this.FORM.srjsPRSurchargeBruttoDisplay.value = '0.00'; this.resizeDisplay(srjsPRSurchargeBruttoDisplay, 4); }
    }
    for(var i = 0; i < this.showIfPrice.length;++i) {
      this.showIfPrice[i].style["visibility"]='hidden';
      this.showIfPrice[i].style["display"]='none';
    }
    return true;
  }

  var newPrice = this.FixPrice;
  var price_factor = 0;
  var last_amount_step = 0;
  var rest = this.QTY;
  if ( this.QType == this.TEXT ) { // STÜCKPREIS
    // Erstmal Grundpreis anhand der Staffelung berechnen:
    for ( var i = 0; i < this.Prices.length; i++ ) {
      price_factor = this.Prices[i][1];
      var menge    = this.Prices[i][0] - last_amount_step;
      if ( rest < menge ) menge = rest;
      newPrice += price_factor * menge;
      last_amount_step = this.Prices[i][0];
      rest = this.QTY - this.Prices[i][0];
      if ( rest < 1 ) break;
    }
    // ds-gestaffelter Stueckpreis, Restpreis berechnen:
    if ( rest > 0 ) {
      newPrice += price_factor * rest;
    }
  }
  else {                        // STAFFELPREIS
    newPrice += this.Prices[this.QElement.selectedIndex][1];
  }

  // Sumanden auf Grundpreis addieren:
  var output = "";
  for(var i in this.SumSelects) {
    var j = document.getElementById(i).selectedIndex;
    newPrice += this.SumSelects[i][j] * this.QTY;
  }
  for(var i in this.FacSelects) {
    var j = document.getElementById(i).selectedIndex;
    newPrice *= this.FacSelects[i][j];
  }
  for(var i in this.EquSelects) {
    var j = document.getElementById(i).selectedIndex;
    newPrice += this.EquSelects[i][j];
  }

  // specials (z.B. 4-farbig), sotp == someOfThePages:
  if(0 < this.someOfThePages.length) {
    var sotp_price = 0.00;
    for(var i=0;i<this.someOfThePages.length;++i) {
      if(this.someOfThePages[i]['field']) {
        var c = parseInt(this.checkInteger(this.someOfThePages[i]['field'].value));
        sotp_price += c * parseFloat(this.someOfThePages[i]['price']);
      }
    }
    if(this.PPB > 0)
      newPrice += (sotp_price * (this.QTY / this.PPB));
  }

  if(this.useBindings()) {
    newPrice += this.getBindingsPrice();
  }

  var newBruttoPrice = newPrice * ((this.Taxrate / 100) + 1);
  var p = this.doRound(newPrice, 4);
  if(this.FORM.srjsPRDisplayNetto) {
    var val = this.padoutPrice(p);
    this.FORM.srjsPRDisplayNetto.value  = val;
    this.resizeDisplay(this.FORM.srjsPRDisplayNetto, val.length);
  }
  if(this.FORM.srjsPRDisplayMwst) {
    var val = this.padoutPrice(this.doRound(newBruttoPrice - newPrice, 4));
    this.FORM.srjsPRDisplayMwst.value = val;
    this.resizeDisplay(this.FORM.srjsPRDisplayMwst, val.length);
  }
  if(this.FORM.srjsPRDisplayBrutto) {
    var val = this.padoutPrice(this.doRound(newBruttoPrice, 4));
    this.FORM.srjsPRDisplayBrutto.value = val;
    this.resizeDisplay(this.FORM.srjsPRDisplayBrutto, val.length);
  }

  if(-1 != this.Surcharge) {
    var n = this.doRound(p + this.Surcharge, 2);
    var b = this.doRound(n * ((this.Taxrate / 100) + 1), 4);

    if(this.FORM.srjsPRSurchargeNettoDisplay) this.FORM.srjsPRSurchargeNettoDisplay.value  = this.padoutPrice(n);
    if(this.FORM.srjsPRSurchargeMwstDisplay) this.FORM.srjsPRSurchargeBruttoDisplay.value = this.padoutPrice(b);
    if(this.FORM.srjsPRSurchargeBruttoDisplay) this.FORM.srjsPRSurchargeMwstDisplay.value   = this.padoutPrice(b - n);
  }

  // show/hide regions if price:
  if(0 < newPrice) { // show elements
    for(var i = 0; i < this.showIfPrice.length;++i) {
      this.showIfPrice[i].style["visibility"]='visible';
      this.showIfPrice[i].style["display"]='block';
    }
  }
  return true;
};


SRJSPreisrechner.prototype.getBindingsPrice = function()
{
  var ret = 0;
  if(this.useBindings()) {
    var auflage = this.getQuantity() / this.PPB;
    ret = auflage * this.BindPrices[this.BSelect.selectedIndex];
  }
  return ret;
};


SRJSPreisrechner.prototype.setQuantity = function(type, inputName)
{
  switch ( type )
    {
    case this.TEXT:
      this.QType = type;
      break;
    case this.SELECT:
      this.QType = type;
      break;
    default:
      alert ("Unbekannter Feld-Typ: " + type + "\n"
             + "Bekannte Feld-Typen sind:\n"
             + "           SRJSPreisrechner::TEXT\n"
             + "       und SRJSPreisrechner::SELECT");
    }
  this.QElement = this.FORM.elements[inputName];
};


/**
 * Die Felder zur Eingabe der Seitenzahlen können derzeit nur normale
 * text-Eingaben sein. Der Name der Funktion ist nicht ganz korrekt. Eigentlich
 * wird die Anzahl der Seiten pro Exemplar wiedergegeben, auch wenn keine
 * Bindungen zum Einsatz.
 * @param amountFieldType Typ des Eingabeelements für die Seitenzahlen. Nur
 * Textfelder werden unterstützt.
 * @param amountInputName HTML-Eigenschaft Name des Eingabeelements für die
 * Seitenzahlen.
 * @param selectName Name des Select-Elements, mit dem eine Bindug ausgewählt
 * werden kann. Wird hier nichts oder <code>null</code> übergeben, werden keine
 * Bindungen genutzt (nur Auflagen und Seitenzahlen).
 */
SRJSPreisrechner.prototype.setPagesPerBinding = function(amountFieldType, amountInputName, selectName)
{
  switch ( amountFieldType )
    {
    case this.TEXT:
      this.PPBType = amountFieldType;
      break;
    default:
      alert ("Unbekannter Feld-Typ: " + amountFieldType + "\n"
             + "Bekannte Feld-Typen sind:\n"
             + "           SRJSPreisrechner::TEXT\n"
             + "       und SRJSPreisrechner::SELECT");
    }
  this.PPBElement = this.FORM.elements[amountInputName];
  if(null != selectName) this.BSelect = this.FORM.elements[selectName];
};


/**
 * Die Felder zur Eingabe der Seitenzahlen können derzeit nur normale
 * text-Eingaben sein.
 * Optionale Zusätze, die nur für einen Teil der bestellten Seiten gelten.
 * Z.B. 100 x (200 Seiten, davon 4-farbig=N).
 */
SRJSPreisrechner.prototype.addSomeOfThePagesAditional = function(amountFieldType, amountInputName, price)
{
  this.someOfThePages[i] = new Object();
  switch ( amountFieldType )
  {
    case this.TEXT:
      this.someOfThePages[i]['field'] = amountFieldType;
    break;
    default:
    alert ("Unbekannter Feld-Typ: " + amountFieldType + "\n"
           + "Bekannte Feld-Typen sind:\n"
           + "           SRJSPreisrechner::TEXT\n"
           + "       und SRJSPreisrechner::SELECT");
  }
  var i = this.someOfThePages.length;
  this.someOfThePages[i] = new Object();
  this.someOfThePages[i]['field'] = this.FORM.elements[amountInputName];
  this.someOfThePages[i]['price'] = price;
};


/**
 * Berechnet die gesamte Seitenzahl und setzt <code>this.QTY</code>.
 * Durch Aufruf von getBindPages() wird auch <code>this.PPB</code> aktualisiert.
 */
SRJSPreisrechner.prototype.getQuantity = function()
{
  switch(this.QType)
    {
    case this.TEXT:
      this.QTY = this.checkInteger(this.QElement.value);
      break;
    case this.SELECT:
      this.QTY = this.Prices[this.QElement.selectedIndex][0];
      break;
    default:
      alert ("Unbekannter Feld-Typ: " + type + "\n"
             + "Bekannte Feld-Typen sind:\n"
             + "           SRJSPreisrechner::TEXT\n"
             + "       und SRJSPreisrechner::SELECT");
    }
  this.getBindPages();
  if(null != this.PPBElement ) // Falls wir Seiten benutzen...
    this.QTY = this.QTY * this.PPB;
  return this.QTY;
};


/**
 * Anzahl der Seiten pro Exemplar.
 * @return <code>0</code>, wenn keine Seiten genutzt werden oder keine
 * Seitenzahl angegeben ist.
 */
SRJSPreisrechner.prototype.getBindPages = function()
{
  this.PPB = 0;
  switch(this.PPBType)
  {
    case this.TEXT:
      if(null != this.PPBElement) {
        this.PPB += parseInt(this.checkInteger(this.PPBElement.value));
      }
      break;
    default:
      alert ("Unbekannter Feld-Typ: " + PPBType + "\n"
             + "Bekannte Feld-Typen sind:\n"
             + "           SRJSPreisrechner::TEXT\n"
             + "       und SRJSPreisrechner::SELECT");
  }
  return this.PPB;
};


SRJSPreisrechner.prototype.addBindungspreis = function(preis)
{
  var p = parseFloat(this.FloatExchange.exec(preis));
  this.BindPrices.push(p);
};


SRJSPreisrechner.prototype.addStaffelpreis = function(oberesLimit, preis)
{
  if(! oberesLimit) oberesLimit = Number.MAX_VALUE;
  var l = parseInt(this.IntExchange.exec(oberesLimit));
  var p = parseFloat(this.FloatExchange.exec(preis));
  this.Prices.push(new Array(l, p));
};


SRJSPreisrechner.prototype.addSelect = function(type, elementsId)
{
  var values = new Array();
  if(arguments) {               // JavaScript >= 1.4
    for(var i = 2; i < arguments.length; ++i) {
      var j = parseFloat(arguments[i]);
      if(isNaN(j)) alert ("AddSelect: j isNaN!");
      values.push(j);
    }
  }
  else {
    for(var i = 2; i < srjsprechnerAddSelect.arguments.length; ++i) {
      var j = parseFloat(srjsprechnerAddSelect.arguments[i]);
      if(isNaN(j)) alert ("AddSelect: j isNaN!");
      values.push(parseFloat(j));
    }
  }

  switch(type)
    {
    case this.SUMMAND:
      this.SumSelects["" + elementsId] = values;
      break;
    case this.EQUAL:
      this.EquSelects["" + elementsId] = values;
      break;
    case this.FACTOR:
      this.FacSelects["" + elementsId] = values;
      break;
    default:
      alert ("Unbekannter Operator-Typ: " + type + "\n"
             + "Bekannte Operator-Typen sind:\n"
             + "           SRJSPreisrechner::SUMMAND,\n"
             + "           SRJSPreisrechner::FACTOR,\n"
             + "       und SRJSPreisrechner::EQUAL");
    }
};


SRJSPreisrechner.prototype.nettoDisplay = function(value, style)
{
  document.write ('<input type="text" id="srjsPRDisplayNetto" name="srjsPRDisplayNetto"'
                  +' value="' + value + '" size="13" maxlength="12"'
                  + style + ' readonly="readonly" />');
};


SRJSPreisrechner.prototype.mwstDisplay = function(value, style)
{
  document.write ('<input type="text" id="srjsPRDisplayMwst" name="srjsPRDisplayMwst"'
                  +' value="' + value + '" size="13" maxlength="9"'
                  + style + ' readonly="readonly" />');
};


SRJSPreisrechner.prototype.bruttoDisplay = function(value, style)
{
  document.write ('<input type="text" id="srjsPRDisplayBrutto" name="srjsPRDisplayBrutto"'
                  +' value="' + value + '" size="13" maxlength="12"'
                  + style + ' readonly="readonly" />');
};


/*
 * Falls Rabatt gewährt wird, fügen wir drei weitere Felder ein.
 * Dieses ist für endgültiges Netto + Rabatt.
 */
SRJSPreisrechner.prototype.surchargeNettoDisplay = function(value, style)
{
  document.write ('<input type="text" id="srjsPRSurchargeNettoDisplay" name="srjsPRSurchargeNettoDisplay"'
                  +' value="' + value + '" size="13" maxlength="12"'
                  + style + ' readonly="readonly" />');
};


/*
 * Falls Rabatt gewährt wird, fügen wir drei weitere Felder ein.
 * Dieses ist für den Rabatt selbst.
 */
SRJSPreisrechner.prototype.surchargeBruttoDisplay = function(value, style)
{
  document.write ('<input type="text" id="srjsPRSurchargeBruttoDisplay" name="srjsPRSurchargeBruttoDisplay"'
                  +' value="- ' + value + '" size="13" maxlength="12"'
                  + style + ' readonly="readonly" />');
};


/*
 * Falls Rabatt gewährt wird, fügen wir drei weitere Felder ein.
 * Dieses ist für den Rabatt selbst.
 */
SRJSPreisrechner.prototype.surchargeMwstDisplay = function(value, style)
{
  document.write ('<input type="text" id="srjsPRSurchargeMwstDisplay" name="srjsPRSurchargeMwstDisplay"'
                  +' value="- ' + value + '" size="13" maxlength="12"'
                  + style + ' readonly="readonly" />');
};


/**
 * Festen Zuschlag f. Offline-Kauf einstellen.
 */
SRJSPreisrechner.prototype.setSurcharge = function(floatVal)
{
  this.Surcharge = floatVal;
};


SRJSPreisrechner.prototype.checkInteger = function(intValue)
{
  if ( ! intValue ) intValue = 0;
  var value = this.IntExchange.exec(intValue);
  var newValue = "";
  for (var i = 1; i < value.length; i++) {
    if ( value[i] )
      newValue = newValue + "" + value[i];
  }
  value = parseInt(newValue);
  if(isNaN(value)) return 0;
  else return value;
};


SRJSPreisrechner.prototype.checkFloat = function(floatValue)
{
  if ( ! floatValue ) floatValue = 0;
  var value = this.FloatExchange.exec(floatValue);
  var newValue = "";
  for (var i = 1; i < value.length; i++) {
    if ( value[i] )
      newValue = newValue + "" + value[i];
  }
  return newValue;
};


SRJSPreisrechner.prototype.doRound = function(x, places)
{
  return Math.round(x * Math.pow(10, places)) / Math.pow(10, places);
};


SRJSPreisrechner.prototype.padoutPrice = function(number) {
  if(! number) number = 0.00;
  number = number.toFixed(2); // kaufmännisch runden.
  var mark    = Math.floor(number);
  var pfennig = Math.floor(number * 100) + "";
  if("0" == pfennig) pfennig = "00";
  else pfennig = pfennig.substr(pfennig.length - 2, pfennig.length);
  return "" + mark + "," + pfennig;
};


SRJSPreisrechner.prototype.setTaxRate = function(rate) {
  this.Taxrate = rate;
};


SRJSPreisrechner.prototype.addExpander = function(id) {
  var i = document.getElementById(id);
  if(i) this.showIfPrice.push(i);
};


SRJSPreisrechner.prototype.resizeDisplay = function(element, length) {
  length -= 1; // TODO: Test im IE!
  if(element.setAttribute) element.setAttribute("size", length);
  else element.size = length;
};

