// Copyright (c) 2000-2001 VSX Vogel Software GmbH

// erste Zeile
var bVsxWarenkorb = false;

//
// Alle privaten Methoden sind mit "PRIVAT:" kommentiert
// 2001-03-15/Gey: awo.arttyp hinzugefügt, bugfix beim lesen aus cookie
// 2001-07-12/Gey: awo.wkbID und awo.parent  hinzugefügt
//


//--- Wo ist mein Warenkorb? --------------------------------------------------


function FindWarenkorb()
/* Sucht in allen Parents und liefert den Warenkorb zurück, das Objekt muß zwangsweise
   den Namen "warenkb" tragen (sonst wird es nämlich nicht gefunden).

   Bei Fehlern wird statt NULL als (rudimentäre) Fehlermeldung ein ungültiges Objekt
   mit dem Präfix WKBERR_ zurückgeliefert, dessen Name den aufgetretenen Fehler angibt.

   WICHTIG: Zum Zugriff auf den Warenkorb !!!IMMER!!! diese Funktion verwenden
*/
{
  var result = window; //parent;

  // ist es dieses window
  while( null != result)
  {
    if( "undefined" != typeof result.bVsxWarenkorb)  // das stimmt erstmal
    {
      // Korrekt initialisiert und ein Warenkorb vorhanden?
      // Es sollte immer genau eine Warenkorbinstanz mit den Namen 'warenkb' geben
      if( (result.bVsxWarenkorb) && ("undefined" != typeof result.warenkb))
        return result.warenkb;                     // gefunden!
    }

    // negativ, noch eine Frame-Ebene nach oben
    if( result.parent != result)
      result = result.parent;
    else
      return WKBERR_Basket_Instance_Not_Found;     // out of frames error, hier stimmt was nicht
  }

  // das war wohl nichts
  return WKBERR_No_Parent_Frames;
}



//--- globaler Kram -----------------------------------------------------------


function AddTableRow( aTableColumn, aStyle )
// Liefert eine fertig formatierte Tabellenzeile zurück
{
  var s = '<tr';
  if( "" != aStyle)
    s += ' class=\"'+aStyle+'\"';

  return s + '>' + aTableColumn + '</tr>';
}


function AddTableHead( aWidth, aTableCell )
// Liefert eine fertig formatierte Tabellenkopfspalte zurück
{
  //if (document.layers) {return '<td class="SORTCOL"><P>' + aTableCell + '</P></td>';}
  //else {return '<th width="'+aWidth+'"><P>' + aTableCell + '</P></th>';}
  return '<th class="sortCol" width="'+aWidth+'"><P>' + aTableCell + '</P></th>';
}


function AddTableColumn( aTableCell )
// Liefert eine fertig formatierte Tabellenspalte zurück
{
  if ((null==aTableCell) || (" "==aTableCell) || (""==aTableCell)) {
    return '<td><P>&nbsp</P></td>';}
  else {return '<td><P>'+ aTableCell + '</P></td>';}
}



//--- AuswObj -----------------------------------------------------------------

function AuswObj( aMake, aSerie, aName, aResultID, aAnzahl, aArtnr, aEP, aURL, aArtTyp)
// ctor
{
  // Parameter
  this.make     = aMake;
  this.serie    = aSerie;
  this.bez      = aName;
  this.resultID = aResultID;
  this.anzahl   = aAnzahl;
  this.artnr    = aArtnr;
  this.preisEP  = aEP.replace(",",".");
  this.url      = aURL;
  this.arttyp   = aArtTyp;              // "P"umpe, "Z"ubehör etc.

  // Warenkorb-IDs setzen
  this.wkbID    = -1;                   // eigene ID, wird beim Einwerfen aktualisiert
  this.parent   = null;                 // Zeiger auf den Parent, wenn es einen gibt
  this.childL   = new Array();          // Liste aller Kinder

  // Methoden anklemmen
  this.PreisGP  = AuswObj_PreisGP;
  this.ParentID = AuswObj_ParentID;
}


function AuswObj_PreisGP()
// Liefert den Gesamtpreis zurück
{
  return (this.preisEP * this.anzahl);
}


function AuswObj_ParentID()
// Liefert die ID des Parent zurück oder 0, wenn es keinen gibt
{
  if( null == this.parent)
    return 0;
  else
    return this.parent.wkbID;
}


//--- WarenKb -----------------------------------------------------------------

function Warenkb()
// ctor
{
  // Defaultwerte
  this.lastWkbID  = 0;
  this.objL       = new Array();
  this.cssStyle   = "WarenKb";         // -> CSS-Definitionen
  this.inpPrefix  = "awO_";            // Prefix für Editierfelder-Namen
  this.sPicDirUrl = "../html/picture"  // URL-Angabe PICTURE-Verzeichnis für die Icons

  // benutzerdefinierte Felder, intern nicht verwendet
  this.prevURL    = "";                // Merker für letzte URL
  this.sProjNr    = "";                // hier kann eine Projektnummer hinterlegt werden

  // Login-bezogene Daten
  this.sUserName  = "";                // Display-Name aktueller Benutzer (nicht der Login-Name!)
  this.urlLogout  = "";                // komplette URL für Logout aktueller Benutzer
  this.sUserKey   = "";                // aktueller UserKey oder Leerstring
  this.bLoginFlag = false;             // Flag während Login-Prozeß

  // Methoden anklemmen
  this.AsHtmlTable       = Warenkb_AsHtmlTable;
  this.AsUrlParams       = Warenkb_AsUrlParams;
  this.Length            = Warenkb_Length;
  this.AddAuswObj        = Warenkb_AddAuswObj;
  this.Empty             = Warenkb_Empty;
  this.RemoveNullEntries = Warenkb_RemoveNullEntries;
  this.SetDataFromForm   = Warenkb_SetDataFromForm
  this.GetAsString       = Warenkb_GetAsString;
  this.SetAsString       = Warenkb_SetAsString;
  this.GetAllHerst       = Warenkb_GetAllHerst;
  this.AsFormValues      = Warenkb_AsFormValues;
  this.FindWkbID         = Warenkb_FindWkbID;

  // PRIVAT:
  this.AddItem           = Warenkb_AddItem;
  this.GetListAsString   = Warenkb_GetListAsString;
  this.FindWkbIDInList   = Warenkb_FindWkbIDInList;
  this.GetFirstNode      = Warenkb_GetFirstNode;
  this.GetNextNode       = Warenkb_GetNextNode;
  this.GetNextSibling    = Warenkb_GetNextSibling;
  this.RemoveNullEntriesFromList = Warenkb_RemoveNullEntriesFromList;
  this.ValidateUserKey   = Warenkb_ValidateUserKey;
  this.ClearLoginData    = Warenkb_ClearLoginData;
}


function Warenkb_ValidateUserKey( aKeyToTest)
// Prüft aKeyToTest auf Übereinstimmung mit dem Warenkorb-Key
// Rückkgabewert ist aKeyToTest (=gültiger Key) oder ein Leerstring (=Key ist ungültig)
{
  // Zuallererst mal die Login-Frage klären und das Flag löschen
  var bIsLogin = this.bLoginFlag;
  this.bLoginFlag = false;

  // Keys identisch? Na das ist einfach ...
  if( this.sUserKey == aKeyToTest)
    return aKeyToTest;

  // Keys unterschiedlich, aber LoginFlag gesetzt -> Login passiert gerade
  if( bIsLogin)
  {
    this.sUserKey = aKeyToTest;  
    return aKeyToTest;
  }
  
  // Keys passen nicht zusammen, Login ist es auch nicht -> Key ungültig  
  this.ClearLoginData();
  return "";
}


function Warenkb_ClearLoginData()
// Löschen aller im Warenkorb gespeicherten Login-bezogenen Daten
{
  this.sUserName  = "";
  this.urlLogout  = "";
  this.sUserKey   = "";
  this.bLoginFlag = false;
}


function Warenkb_Length()
// Liefert Anzahl der im Warenkorb enthaltenen Toplevel-Einträge zurück
// BEACHTE: Die Anzahl der Artikel kann größer sein!
{
  return (this.objL.length);
}


function Warenkb_GetNextSibling( aAwObj)
// Liefert nächste nebengeordneten Eintrag oder null
{
  if( null == aAwObj)
    return null;

  // welche Liste?
  var awoList = this.objL;
  if( null != aAwObj.parent)
    awoList = aAwObj.parent.childL;

  // Position suchen und auf Nachfolger prüfen
  var obj;
  var i = 0;
  while( i < awoList.length)
  {
    obj = awoList[i];
    i++;

    if( obj != aAwObj)
      continue;

    if( i < awoList.length)
      return awoList[i];
    else
      return null;
  }

  // keiner da
  return null;
}


function Warenkb_GetFirstNode()
// Liefert den logisch ersten Warenkorbeintrag
{
  if( 0 < this.objL.length)
    return this.objL[0];
  else
    return null;
}


function Warenkb_GetNextNode( aAwObj)
// Durchläuft den Warenkorb und liefert die logisch folgenden Eintrag zurück
// Mit aAwObj = null wird der logisch erste Eintrag des Warenkorbs gefunden
// Wird kein weiteres aAwObj gefunden, ist der Rückgabewert null
{
  // Sonderfall "null"
  if( null == aAwObj)
    return GetFirstNode();

  // Hat das Objekt noch Kinder?
  if( 0 < aAwObj.childL.length)
    return aAwObj.childL[0];


  // suche nächstes Obj derselben Ebene
  // wenn nichts gefunden, dann dasselbe mit dem Parent versuchen
  var objFound = null;
  var objSuche = aAwObj;
  while( (null != objSuche) && (null == objFound))
  {
    objFound = this.GetNextSibling( objSuche);
    objSuche = objSuche.parent;
  }

  // zurückliefern, was wir haben
  return objFound;
}


function Warenkb_GetAllHerst( aStrL)
// Liefert alle im Warenkorb vertretenen Hersteller in aStrL zurück
// INFO: Die Herstellerkürzel werden in Großbuchstaben konvertiert
{
  var sTmp   = "|";
  var sHerst = "";
  var awO    = null;

  for( var i = 0;  i < this.objL.length;  i++)
  {
    awO    = this.objL[i];
    sHerst = awO.make.toUpperCase();

    if( 0 > sTmp.indexOf("|"+sHerst+"|"))
    {
      sTmp += sHerst+"|";
      aStrL[aStrL.length] = sHerst;
    }
  }
}


function Warenkb_AsHtmlTable( aSprObj, aEventHandler, aFilterHerst)
/* Liefert Inhalt des Warenkorbs als HTML-Tabelle formatiert zurück
  Es werden die mit cssStyle angegebenen Stile verwendet

  - aSprObj wird als assoziatives Array mit Sprachstrings verwendet
  - mit aEventHandler kann ein Eventhandler für das Element angegeben werden,
    übergeben Sie nur den Funktionsnamen, aber KEINE Klammern
  - mit aFilterHerst kann die Ausgabe auf Daten eines bestimmten Herstellers
    beschränkt werden

  Der Eventhandler bekommt den Namen des INPUT-Elementes, den Namen des editierten
  Wertes (zB. "anzahl") und den Index des Awo-Objektes in der Liste übergeben:

     function OnChange( aInputName, aVarName, aIndex)
     {
       awo = warenkorb.objL[aIndex];
       if( document.forms[0].elements[aInputName].value != awo[aVarName])
         alert("Geändert!");
     }

*/
{
  var result      = new String("");
  var bMitHandler = (aEventHandler && ("" != aEventHandler));
  var sOnChange   = "";
  var nWritten    = 0;


  // Bei Bedarf einfach umstellen
  var bMitPreisen = false;


  // table start
  result += '<table class="'+this.cssStyle+'" width="100%" cellspacing=0 cellpadding=2 border=0>';

  // table column definitions (alignment)
  result  += "<colgroup>"
           + "<col align=right>"
           + "<col align=right>"
           + "<col align=left>"
           + "<col align=left>"
           + "<col align=left>";
  if( bMitPreisen)
  {
    result  += "<col align=right>"
             + "<col align=right>";
  }
  if( bMitHandler)
    result  += "<col align=left>";      // Bearbeiten-Knopf
  result  += "</colgroup>";


  // table caption
  var sRow = AddTableHead( "16",  "&nbsp;")  // Spalte für Icon
           + AddTableHead( "8%",  aSprObj["Anza"])
           + AddTableHead( "10%", aSprObj["Herst"])
           + AddTableHead( "16%", aSprObj["ArtNmr"])
           + AddTableHead( "*",   aSprObj["Bezg"]);
  if( bMitPreisen)
  {
    sRow += AddTableHead( "10%", aSprObj["EP"])
          + AddTableHead( "10%", aSprObj["GP"]);
  }
  if( bMitHandler)
    sRow += AddTableHead( "40",  aSprObj["Opt"])     // feste Breite
  result += AddTableRow( sRow, "");


  // table content
  // NumToStr() needs spaix.js
  var sArtnr  = "";
  var sEditAnz    = "";
  var sBtnBearb   = "";
  var sBtnDetails = "";
  var sIcon       = "";
  var sWkbID = "";
  var i      = -1;
  for( var awO = this.GetFirstNode();  null != awO;  awO = this.GetNextNode(awO))
  {
    i++;

    // Hersteller gefiltert?
    if( ("" == aFilterHerst) || (awO.make.toUpperCase() == aFilterHerst.toUpperCase()))
    {
      // dann nehmen wir diese Zeile
      sRow   = "";
      sArtnr = awO.artnr;
      sWkbID = String(awO.wkbID);
      //if( "" == sArtnr)   sArtnr = awO.resultID;

      sEditAnz    = this.inpPrefix + 'anz_'  + sWkbID;
      sBtnBearb   = this.inpPrefix + 'btnE_' + sWkbID;
      sBtnDetails = this.inpPrefix + 'btnV_' + sWkbID;
      if( bMitHandler)
      {
        sOnChange = aEventHandler+"('"+sEditAnz   +"','anzahl', "+sWkbID+")";
        sOnClickE = aEventHandler+"('"+sBtnBearb  +"','edit',   "+sWkbID+")";
        sOnClickD = aEventHandler+"('"+sBtnDetails+"','details',"+sWkbID+")";
      }
      else
      {
        sOnChange = '';
        sOnClickE = '';
        sOnClickD = '';
      }

      // Icon je nach Art des Objektes
      if( "P" == awO.arttyp.toUpperCase())
        sIcon = "wkbIconP.gif";
      else if( "Z" == awO.arttyp.toUpperCase())
        sIcon = "wkbIconZ.gif";
      else
        sIcon = "wkbIconUnk.gif";
      //
      sIcon = "<img src='" + this.sPicDirUrl + "/" + sIcon + "' alt=''>";
      sRow += AddTableColumn( sIcon);


      // Anzahl ist manchmal editierbar
      if( "" != sOnChange)
        sRow += AddTableColumn( '<input type=text name="'+sEditAnz+'" size=5 '
                               + 'value="'+String(awO.anzahl)+'" onChange="'+sOnChange+'">');
      else
        sRow += AddTableColumn( awO.anzahl);

      // normaler Text
      sRow += AddTableColumn( awO.make);
      sRow += AddTableColumn( sArtnr);

      // ResultID, sonst Bezeichnung
      if( "" != awO.resultID)
        sRow += AddTableColumn( awO.resultID);
      else
        sRow += AddTableColumn( awO.bez);

      // Preise?
      if( bMitPreisen)
      {
        // EP
        var sPreis = NumToStr( awO.preisEP, 2);
        if( "N,AN" == sPreis.toUpperCase())    sPreis = aSprObj["Pr.a"];
        sRow += AddTableColumn( sPreis);

        // GP
        sPreis = NumToStr( awO.PreisGP(), 2);
        if( "N,AN" == sPreis.toUpperCase())    sPreis = aSprObj["Pr.a"];
        sRow += AddTableColumn( sPreis);
      }

      // Ansehen/Bearbeiten?
      if( bMitHandler)
      {
        if( awO.url && ("" != awO.url))
          sRow   += AddTableColumn( '<input type=button name="'   +sBtnDetails
                                  + '" value="'+aSprObj["Details"]+'" onclick="'+sOnClickD+'">');
//                                  + '&nbsp;'
//                                  + '<input type=button name="'   +sBtnBearb
//                                  + '" value="'+aSprObj["Bear"]   +'" onclick="'+sOnClickE+'">');
        else
          sRow   += AddTableColumn( aSprObj["GehtNicht"]);
      }

      // neue Zeile anhängen, ungerade Zeilen mit class="Odd" formatieren
      // nWritten statt i verwenden / fixed 10.05.01 Gey
      var sStyle = (0 != (nWritten % 2))  ?  "Odd" : "";
      result += AddTableRow( sRow, sStyle);
      nWritten++;
    }
  }

  // table empty message ?
  if( 1 > nWritten)
  {
    result += AddTableRow( AddTableColumn( "")
                         + AddTableColumn( "")
                         + AddTableColumn( "")
                         + AddTableColumn( "")
                         + AddTableColumn( aSprObj["MsgWakoL"])
                         + AddTableColumn( "")
                         , "");
  }

  // table end
  result += "</table>";

  return result;
}


function Warenkb_AsUrlParams( aFilterHerst)
/* Liefert Inhalt des Warenkorbs als URL-Parameter formatiert zurück,
   also in der Form "key=value&key=value&key=value".

  - mit aFilterHerst kann die Ausgabe auf Daten eines bestimmten Herstellers
    beschränkt werden
*/
{
  var result      = new String("");
  var nWritten    = 0;

  // content
  // NumToStr() needs spaix.js
  var awO    = null;
  var i      = -1;
  for( awO = this.GetFirstNode();  null != awO;  awO = this.GetNextNode(awO))
  {
    i++;

    // Hersteller gefiltert?
    if( ("" == aFilterHerst) || (awO.make.toUpperCase() == aFilterHerst.toUpperCase()))
    {
      result += "WkbHer" + nWritten + "=" + SafeEscape(awO.make)               + "&";
      result += "WkbSer" + nWritten + "=" + SafeEscape(awO.serie)              + "&";
      result += "WkbNam" + nWritten + "=" + SafeEscape(awO.bez)                + "&";
      result += "WkbRID" + nWritten + "=" + SafeEscape(awO.resultID)           + "&";
      result += "WkbQty" + nWritten + "=" + SafeEscape(String(awO.anzahl))     + "&";
      result += "WkbArt" + nWritten + "=" + SafeEscape(awO.artnr)              + "&";
      result += "WkbPrs" + nWritten + "=" + SafeEscape(String(awO.preisEP))    + "&";
      result += "WkbUrl" + nWritten + "=" + SafeEscape(awO.url)                + "&";
      result += "WkbTyp" + nWritten + "=" + SafeEscape(awO.arttyp)             + "&";
      result += "WkbID"  + nWritten + "=" + SafeEscape(String(awO.wkbID))      + "&";
      result += "WkbPID" + nWritten + "=" + SafeEscape(String(awO.ParentID())) + "&";

      // nächstes Element
      nWritten++;
    }
  }


  // Anzahl geschriebener Warenkorb-Elemente anhängen
  return result + "WkbAnz=" + nWritten;
}


function Warenkb_AsFormValues( aTargetForm, aMaxCount, aFilterHerst)
/* Füllt die in aTargetForm enthaltenen Elemente mit den Daten des Warenkorbs,
   der Parameter aMaxCount gibt die maximale Kapazität des Formulars an.

   Rückgabewert ist die Anzahl zu übertragender Elemente. Ist dieser Wert größer
   als aMaxCount, dann ist die Kapazität des Formulars nicht ausreichend.

   Das Targetform muß neben einem Input-Element für die Anzahl verwendeter Einträge
   alle entsprechenden Input-Elemente in der angegebenen Anzahl bereitstellen, für
   die Angabe aMaxCount=20 wäre das zB. (Ausschnitt):

      <!-- hier wird die Anzahl belegter Einträge hinterlegt -->
      <input type=hidden name="WkbAnz"  value="0">

      <!-- erster eintrag --->
      <input type=hidden name="WkbHer0" value="">
      ...
      <input type=hidden name="WkbTyp0" value="">

      ...

      <!-- letzter eintrag --->
      <input type=hidden name="WkbHer19" value="">
      ...
      <input type=hidden name="WkbTyp19" value="">

   Mit aFilterHerst kann die Ausgabe auf Daten eines bestimmten Herstellers
   beschränkt werden.

*/
{
  var nWritten     = 0;    // Anzahl geschriebener Elemente
  var nHaveToWrite = 0;    // Anzahl zu schreibender Elemente

  // content
  // NOTE: NumToStr() and SetFormValue() need spaix.js
  var awO    = null;
  var i      = -1;
  for( awO = this.GetFirstNode();  null != awO;  awO = this.GetNextNode(awO))
  {
    i++;

    // Hersteller gefiltert?
    if( ("" == aFilterHerst) || (awO.make.toUpperCase() == aFilterHerst.toUpperCase()))
    {
      nHaveToWrite++;

      // noch Einträge frei?
      if( nWritten < aMaxCount)
      {
        // Werte übertragen
        SetFormValue( aTargetForm, "WkbHer" + nWritten, awO.make);
        SetFormValue( aTargetForm, "WkbSer" + nWritten, awO.serie);
        SetFormValue( aTargetForm, "WkbNam" + nWritten, awO.bez);
        SetFormValue( aTargetForm, "WkbRID" + nWritten, awO.resultID);
        SetFormValue( aTargetForm, "WkbQty" + nWritten, String(awO.anzahl));
        SetFormValue( aTargetForm, "WkbArt" + nWritten, awO.artnr);
        SetFormValue( aTargetForm, "WkbPrs" + nWritten, String(awO.preisEP));
        SetFormValue( aTargetForm, "WkbUrl" + nWritten, awO.url);
        SetFormValue( aTargetForm, "WkbTyp" + nWritten, awO.arttyp);
        SetFormValue( aTargetForm, "WkbID"  + nWritten, String(awO.wkbID));
        SetFormValue( aTargetForm, "WkbPID" + nWritten, String(awO.ParentID()));

        // nächstes Element
        nWritten++;
      }
    }
  }

  // Anzahl geschriebener Warenkorb-Elemente
  SetFormValue( aTargetForm, "WkbAnz", String(nWritten));

  // alle restlichen Elemente mit Leerstrings füllen
  // nicht zwingend erforderlich, vermindert aber die zu übertragende Datenmenge
  while( nWritten < aMaxCount)
  {
    SetFormValue( aTargetForm, "WkbHer" + nWritten, "");
    SetFormValue( aTargetForm, "WkbSer" + nWritten, "");
    SetFormValue( aTargetForm, "WkbNam" + nWritten, "");
    SetFormValue( aTargetForm, "WkbRID" + nWritten, "");
    SetFormValue( aTargetForm, "WkbQty" + nWritten, "");
    SetFormValue( aTargetForm, "WkbArt" + nWritten, "");
    SetFormValue( aTargetForm, "WkbPrs" + nWritten, "");
    SetFormValue( aTargetForm, "WkbUrl" + nWritten, "");
    SetFormValue( aTargetForm, "WkbTyp" + nWritten, "");
    SetFormValue( aTargetForm, "WkbID"  + nWritten, "");
    SetFormValue( aTargetForm, "WkbPID" + nWritten, "");

    // nächstes Element
    nWritten++;
  }

  // Anzahl zu schreibender Einträge zurückgeben
  return nHaveToWrite;
}


function Warenkb_AddAuswObj( aMake, aSerie, aName, aResultID, aAnz, aArtnr, aEP, aURL, aArtTyp, aParentID)
// Erzeugt ein weiteres AuswObj  und legt es in den Warenkorb
// Der Zeiger auf das Objekt wird als Rückgabewert geliefert
//
// WICHTIG: Das AuswObj muß seine Methodenzeiger unbedingt in demselben Kontext
// erhalten, in dem sich auch die laufende Instanz des Warenkorbes befindet!
// Ansonsten zeigen diese irgendwann ins Nirwana -> Scriptfehler lauert
{
  return this.AddItem( new AuswObj( aMake, aSerie, aName, aResultID, aAnz, aArtnr, aEP, aURL, aArtTyp), aParentID);
}


function Warenkb_FindWkbIDInList( aObjL, aWkbID)
// PRIVAT: Implementierung für Warenkb_FindWkbID()
{
  var awo = null;
  if( null != aObjL)
  {
    for( var i = 0;  i < aObjL.length;  i++)
    {
      awo = aObjL[i];
      ASSERT( 0 < awo.wkbID, "WarenKb_FindWkbIDInList: invalid wkbID");

      // ist es dieses Objekt?
      if( awo.wkbID == aWkbID)
        return awo;

      // untergeordnete Objekte rekursiv durchsuchen
      awo = this.FindWkbIDInList( awo.childL, aWkbID);
      if( null != awo)
        return awo;
    }
  }

  // nichts gefunden
  return null;
}


function Warenkb_FindWkbID( aWkbID)
// Liefert das awO mit der angegebenen wkbID oder null
// Gesucht wird in der angegebenen Liste und rekursiv durch alle Kinder
{
  return this.FindWkbIDInList( this.objL, aWkbID);
}


function Warenkb_AddItem( aAwObj, aParentID)
// PRIVAT: Legt ein weiteres Element in den Warenkorb
// Rückgabewert ist das im Warenkorb befindliche Objekt (das muß nicht aAwO sein!)
// Falls es schon ein Teil mit derselben Artnr gibt, wird nur die Menge aktualisiert
{
  var objFound = null;

  // haben wir den Dingens schonmal?
  if( 0 < aAwObj.wkbID)
  {
    // NEU: Vergleich nur noch anhand der WkbID, mehrere identische Pumpen können
    // ja auch mit unterschiedl. Zubehör ausgewählt werden
    objFound = this.FindWkbID( aAwObj.wkbID);
    if( null != objFound)
    {
      ASSERT( 0 < objFound.wkbID, "Warenkb_AddItem: objFound has an invalid wkbID");
      ASSERT( objFound.parentID == aAwo.parentID, "Warenkb_AddItem: different parentIDs");  // die müßten eigentlich auch identisch sein

      // URL korrigieren?
      if( aAwO.url && ("" != aAwO.url))
        objFound.url = aAwO.url;

      // Menge erhöhen und fertich
      objFound.anzahl++;
      return objFound;
    }
  }

  // neues Objekt -> WkbID prüfen
  var bNewID = true;                                         // erstmal immer JA
  if( 0 <= aAwObj.wkbID)                                     // das Objekt hat schon eine ID?
  {
    objFound = this.FindWkbID( aAwObj.wkbID);                // mal sehen, was die Liste dazu sagt
    bNewID   = (null != objFound) && (objFound != aAwObj);   // wenn schon an anderes Objekt vergeben

    // dasselbe Objekt kann es nicht sein, das hätten wir weiter oben herausfinden müssen
    // Ansonsten stimmt die angegebene ParentID wohl nicht
    ASSERT( (null == objFound) || (objFound != aAwObj));
  }

  // WkbID erzeugen, falls nötig
  if( bNewID)
  {
    this.lastWkbID++;
    aAwObj.wkbID = this.lastWkbID;
  }
  else if( this.lastWkbID < aAwObj.wkbID)   // letzte vergebene ID anpassen?
  {
    this.lastWkbID = aAwObj.wkbID
  }


  // passende Liste ermitteln
  aAwObj.parent = null;
  var awoList   = this.objL;
  if( 0 < aParentID)
  {
    objFound = this.FindWkbID( aParentID);
    if( null != objFound)
    {
      aAwObj.parent = objFound;
      awoList = objFound.childL;
    }
  }

  // und einwerfen
  awoList[awoList.length] = aAwObj;
  return aAwObj;
}


function Warenkb_RemoveNullEntriesFromList( aObjL)
// PRIVAT: Implementierung von RemoveNullEntries()
{
  var bNeedUpdate = false;

  // Liste ist leer?
  if( (null == aObjL) || (0 >= aObjL.length))
    return false;


  // Liste kopieren
  var oldL  = new Array();
  for( var i = 0;  i < aObjL.length;  i++)
    oldL[oldL.length] = aObjL[i];

  // aObjL leeren
  aObjL.length = 0;

  // alle nicht-Null-Einträge wieder einfügen
  var awo = null;
  for( i = 0;  i < oldL.length;  i++)
  {
    awo = oldL[i];
    if( 0 < awo.anzahl)     // der bleibt drin
      aObjL[aObjL.length] = awo;
    else                    // Menge = 0, der fliegt raus
      bNeedUpdate = true;
  }


  // verbleibende Einträge rekursiv durchsuchen
  for( var i = 0;  i < aObjL.length;  i++)
    if( this.RemoveNullEntriesFromList( aObjL.childL))
      bNeedUpdate = true;

  // Rückgabewert
  return bNeedUpdate;
}


function Warenkb_RemoveNullEntries()
// Entfernt alle Einträge mit Anzahl=0 aus dem Warenkorb, außerdem werden
// damit auch automatisch alle Kinder solcher Elemente entfernt
// Rückgabewert true, wenn eine erneute Darstellung der HTML-Tabelle erforderlich ist
{
  return this.RemoveNullEntriesFromList( this.objL);
}


function Warenkb_Empty()
// Löscht den Inhalt des Warenkorbs
// Rückgabewert true, wenn eine erneute Darstellung der HTML-Tabelle erforderlich ist
{
  var bNeedUpdate = (0 < this.objL.length);
  this.objL       = new Array();
  this.lastWkbID  = 0;
  return bNeedUpdate;
}


function Warenkb_SetDataFromForm( aForm)
/* Übernimmt Daten aus einem Formular
   Das Formular muß eine mit AsHtmlTable() erzeugte Tabelle enthalten
   Rückgabewert true, wenn eine erneute Darstellung der HTML-Tabelle erforderlich ist

   Um Elemente mit Anzahl=0 aus dem Warenkorb zu entfernen, rufen Sie anschließend
   die Methode RemoveNullEntries() auf. Falls diese Methode oder RemoveNullEntries()
   den Rückgabewert "true" liefert, aktualisieren Sie zusätzlich die im Browser
   angezeigte Tabelle.
*/
{
  var inpAnz = null;
  var result = false;

  // Liste abgrasen
  var sWkbID = "";
  var awO    = null;
  var i      = -1;
  for( awO = this.GetFirstNode();  null != awO;  awO = this.GetNextNode(awO))
  {
    i++;
    sWkbID = String(awO.wkbID);

    // Formularelemente suchen
    inpAnz = aForm.elements[ this.inpPrefix+"anz_"+sWkbID];

    // alles da?
    if( (null != inpAnz))
    {
      result     = result || ((awO.anzahl != inpAnz.value) && (awO.preisEP != 0));
      awO.anzahl = Number(inpAnz.value);
    }
  }

  return result;
}


function Warenkb_GetListAsString( aObjL)
// INTERN: Implementierung für Warenkb_GetAsString()
{
  var result = new String();
  var awO    = null;

  // Inhalt
  for( var i = 0; i < aObjL.length;  i++)
  {
    awO = aObjL[i];

    // das Objekt selbst immer zuerst
    result += "AWO("
            + "MAKE(" + escape(awO.make)     + ")"
            + "BAUR(" + escape(awO.serie)    + ")"
            + "BEZ("  + escape(awO.bez)      + ")"
            + "RID("  + escape(awO.resultID) + ")"
            + "ANZ("  + escape(awO.anzahl)   + ")"
            + "ART("  + escape(awO.artnr)    + ")"
            + "EP("   + escape(awO.preisEP)  + ")"
            + "URL("  + escape(awO.url)      + ")"
            + "TYP("  + escape(awO.arttyp)   + ")"
            + "WID("  + escape(String(awO.wkbID))   + ")"
            + "PID("  + escape(String(awO.ParentID()))   + ")"
            + ")"

    // erst danach rekursiv alle Kinderchen einsammeln
    // wenn wir die Kinder vor dem Parent schreiben, kriegen wir ein Problem beim Lesen
    result += this.GetListAsString( awO.childL);
  }

  // das wars
  return result;
}


function Warenkb_GetAsString()
// Liefert den Inhalt des Warenkorbes als zusamnmenhängenden String, so daß
// dieser zB. als Cookie abgelegt werden kann
// Format zB. "key(wert)key(subkey(wert)subkey(wert))key(subkey(subkey(wert)subkey(wert))subkey(wert))"
{
  return "WKB_V1(" + this.GetListAsString( this.objL) + ")";
}


function Warenkb_SetAsString( aStr)
// Ersetzt den Inhalt des Warenkorbes durch die im angegebenen String enthalten
// Werte. Der String wird in dem Format erwartet, welches GetAsString() erzeugt.
{
  // getCookie() kann null liefern
  if( null == aStr)
    return;

  // lokale Variablen
  var s          = aStr;
  var sAwo       = "";
  var sKey, sVal = "";
  var iV, iH     = 0;
  var iKlammern  = 0;

  // vorderen Key suchen
  iV = s.indexOf("WKB_V1(") + String("WKB_V1(").length;
  if( 0 > iV)
    return;

  // key abtrennen
  s  = s.substr( iV, s.length);
  iKlammern = 1;

  // passende schließende ) suchen
  iH = 0;
  while( (1 <= iKlammern) && (iH < s.length))
  {
    if( ")" == s.substr(iH,1))  iKlammern--;
    if( "(" == s.substr(iH,1))  iKlammern++;
    iH++;
  }

  // der Warenkorb ist das Stück dazwischen
  s = s.substr(0,iH);

  // die einzelnen AWO(...) heraussuchen
  while( 0 < s.length)
  {
    // nächsten key "AWO(" suchen
    iV = s.indexOf("AWO(") + String("AWO(").length;
    if( 0 > iV)
      break;

    // key "AWO(" abtrennen
    s  = s.substr( iV, s.length);
    iKlammern = 1;

    // passende schließende ) suchen
    iH = 0;
    while( (1 <= iKlammern) && (iH < s.length))
    {
      if( ")" == s.substr(iH,1))  iKlammern--;
      if( "(" == s.substr(iH,1))  iKlammern++;
      iH++;
    }

    // das nächste AWO ist das Stück dazwischen
    sAwo = s.substr(0,iH-1);
    s    = s.substr(iH,s.length);

    // das AWO auseinandernehmen
    if( 0 < sAwo.length)
    {
      var sMake     = "";
      var sSerie    = "";
      var sBez      = "";
      var sResultID = "";
      var sAnz      = "";
      var sArt      = "";
      var sEP       = "";
      var sURL      = "";
      var sTyp      = "P";
      var nWkbID    = 0;
      //var nParent   = 0; (?) juv
      var nParentID = 0;

      while( 0 < sAwo.length)
      {
        // vordere ( suchen, Key abtrennen
        iV   = sAwo.indexOf("(");
        if( 0 > iV)
          break;

        // Key abtrennen
        sKey = sAwo.substr( 0,iV);
        iKlammern = 1;

        // passende schließende ) suchen, Value extrahieren
        iH = iV;
        while( (1 <= iKlammern) && (iH < sAwo.length))
        {
          iH++;
          if( ")" == sAwo.substr(iH,1))  iKlammern--;
          if( "(" == sAwo.substr(iH,1))  iKlammern++;
        }
        sVal = unescape(sAwo.substr(iV+1,iH-iV-1))

        // sAwo noch um den gelesenenen Anteil kürzen
        sAwo = sAwo.substr( iH+1, sAwo.length);

        // Wert zuweisen
        if( "MAKE" == sKey)   sMake     = sVal;
        if( "BAUR" == sKey)   sSerie    = sVal;
        if( "BEZ"  == sKey)   sBez      = sVal;
        if( "RID"  == sKey)   sResultID = sVal;
        if( "ANZ"  == sKey)   sAnz      = sVal;
        if( "ART"  == sKey)   sArt      = sVal;
        if( "EP"   == sKey)   sEP       = sVal;
        if( "URL"  == sKey)   sURL      = sVal;
        if( "TYP"  == sKey)   sTyp      = sVal;
        if( "WID"  == sKey)   nWkbID    = Number(sVal);
        if( "PID"  == sKey)   nParentID = Number(sVal);
      }

      // ein weiteres awO mit diesen Daten erzeugen
      var awO   = new AuswObj( sMake, sSerie, sBez, sResultID, sAnz, sArt, sEP, sURL, sTyp);
      awO.wkbID = nWkbID;
      this.AddItem( awO, nParentID);
    }
  }
}



// letzte Zeile
var bVsxWarenkorb = true;
//bVsxWarenkorb = true;  // Wir überschreiben die bereits deklarierte Variable!! //juv
                         // Völlig korrekt. Und wo ist bitteschön das Problem??? // gey
// *EOF*