// Copyright (c) 2000-2006 VSX Vogel Software GmbH

var bVsxWarenkorb = true;

//
// Alle privaten Methoden sind mit "PRIVAT:" kommentiert
// 2001-03-15/Gey: NEU: awo.arttyp hinzugefuegt
// 2001-03-15/Gey: FIX: bugfix beim lesen aus cookie
// 2001-07-12/Gey: NEU: awo.wkbID und awo.parent  hinzugefuegt
// 2006-08-11/Gey: FIX: Fuer alle Nicht-Toplevel-Eintraege (zB. Zubehoer) funktionierte RemoveNullEntries() nicht mehr
//


//--- Wo ist mein Warenkorb? --------------------------------------------------


function FindWarenkorb()
/* Sucht in allen Parents und liefert den Warenkorb zurueck, das Objekt muss zwangsweise
   den Namen "warenkb" tragen (sonst wird es naemlich nicht gefunden).

   Bei Fehlern wird statt NULL als (rudimentaere) Fehlermeldung ein ungueltiges Objekt
   mit dem Praefix WKBERR_ zurueckgeliefert, 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 zurueck
{
  var s = '<tr';
  if( "" != aStyle)
    s += ' class=\"'+aStyle+'\"';

  return s + '>' + aTableColumn + '<\/tr>';
}


function AddTableHead( aStyle, aTableCell )
// Liefert eine fertig formatierte Tabellenkopfspalte zurueck
{
  if( "" != aStyle)
    return '<th class="sortCol" style="'+aStyle+'">' + aTableCell + '<\/th>';
  else  
    return '<th class="sortCol">' + aTableCell + '<\/th>';
}


function AddTableColumn( aText)
// Liefert eine fertig formatierte Tabellenspalte zurueck
{
  var sHtml = "";

  sHtml += "<td>";
  sHtml += "<span style='overflow: visible; white-space: nowrap;'>";
  if(aText)
    sHtml += aText;
  sHtml += "&nbsp;";
  sHtml += "<\/span>";
  sHtml += "<\/td>";
  return sHtml;
    
}



//--- 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"ubehoer 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 zurueck
{
  return (this.preisEP * this.anzahl);
}


function AuswObj_ParentID()
// Liefert die ID des Parent zurueck 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 fuer Editierfelder-Namen
  this.sPicDirUrl = "../html/picture"  // URL-Angabe PICTURE-Verzeichnis fuer die Icons

  // benutzerdefinierte Felder, intern nicht verwendet
  this.prevURL    = "";                // Merker fuer 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 fuer Logout aktueller Benutzer
  this.sUserKey   = "";                // aktueller UserKey oder Leerstring
  this.bLoginFlag = false;             // Flag waehrend Login-Prozess

  // 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)
// Prueft aKeyToTest auf uebereinstimmung mit dem Warenkorb-Key
// Rueckkgabewert ist aKeyToTest (=gueltiger Key) oder ein Leerstring (=Key ist ungueltig)
{
  // Zuallererst mal die Login-Frage klaeren und das Flag loeschen
  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 ungueltig  
  this.ClearLoginData();
  return "";
}


function Warenkb_ClearLoginData()
// Loeschen 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-Eintraege zurueck
// BEACHTE: Die Anzahl der Artikel kann groesser sein!
{
  return (this.objL.length);
}


function Warenkb_GetNextSibling( aAwObj)
// Liefert naechste 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 pruefen
  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)
// Durchlaeuft den Warenkorb und liefert die logisch folgenden Eintrag zurueck
// Mit aAwObj = null wird der logisch erste Eintrag des Warenkorbs gefunden
// Wird kein weiteres aAwObj gefunden, ist der Rueckgabewert null
{
  // Sonderfall "null"
  if( null == aAwObj)
    return GetFirstNode();

  // Hat das Objekt noch Kinder?
  if( 0 < aAwObj.childL.length)
    return aAwObj.childL[0];


  // suche naechstes 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;
  }

  // zurueckliefern, was wir haben
  return objFound;
}


function Warenkb_GetAllHerst( aStrL)
// Liefert alle im Warenkorb vertretenen Hersteller in aStrL zurueck
// INFO: Die Herstellerkuerzel werden in Grossbuchstaben 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 zurueck
  Es werden die mit cssStyle angegebenen Stile verwendet

  - aSprObj wird als assoziatives Array mit Sprachstrings verwendet
  - mit aEventHandler kann ein Eventhandler fuer das Element angegeben werden,
    uebergeben Sie nur den Funktionsnamen, aber KEINE Klammern
  - mit aFilterHerst kann die Ausgabe auf Daten eines bestimmten Herstellers
    beschraenkt 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 uebergeben:

     function OnChange( aInputName, aVarName, aIndex)
     {
       awo = warenkorb.objL[aIndex];
       if( document.forms[0].elements[aInputName].value != awo[aVarName])
         alert("Geaendert!");
     }

*/
{
  var result      = new String("");
  var bMitHandler = (aEventHandler && ("" != aEventHandler));
  var sOnChange   = "";
  var nWritten    = 0;


  // Bei Bedarf einfach umstellen
  var bMitPreisen = false;

  // table start
  result += '<table id="warenkorb" class="'+this.cssStyle+'">';

  result += "<colgroup>";
  result += "<col width='10px'>";
  result += "<col width='10px'>";
  result += "<col width='10px'>";
  result += "<col width='10px'>";
  result += "<col width='auto'>";
  if( bMitPreisen)
  {
    result += "<col width='10px'>";
    result += "<col width='10px'>";
  }
  result += "<\/colgroup>";

  // table caption
  var sRow = AddTableHead( "", "&nbsp;")  // Spalte fuer Icon
           + AddTableHead( "", aSprObj["Anza"])
           + AddTableHead( "", aSprObj["Herst"])
           + AddTableHead( "", aSprObj["ArtNmr"])
           + AddTableHead( "", aSprObj["Bezg"]);
  if( bMitPreisen)
  {
    sRow += AddTableHead( "", aSprObj["EP"])
          + AddTableHead( "", aSprObj["GP"]);
  }
  result += AddTableRow( sRow, "");


  // table content
  // NumToStr() needs spaix.js
  var sArtnr  = "";
  var sEditAnz    = "";
  var sBtnBearb   = "";
  var sBtnDetails = "";
  var sIcon, sIconPic;
  var sOnChange, sOnEdit, sOnDetail;
  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;
      sBtnDelete  = this.inpPrefix + 'btnD_' + sWkbID;
      //
      sOnChange   =  bMitHandler ?  aEventHandler+"('"+sEditAnz   +"','anzahl', "+sWkbID+")"  :  "";
      sOnDelete   =  bMitHandler ?  aEventHandler+"('"+sEditAnz   +"','delete', "+sWkbID+")"  :  "";
      sOnEdit     =  bMitHandler ?  aEventHandler+"('"+sBtnBearb  +"','edit',   "+sWkbID+")"  :  "";
      sOnDetail   =  bMitHandler ?  aEventHandler+"('"+sBtnDetails+"','details',"+sWkbID+")"  :  "";

      // Icon je nach Art des Objektes
      switch( awO.arttyp.toUpperCase())
      {
      case "P":  sIconPic = this.sPicDirUrl+"/wkbIconP";    break;
      case "Z":  sIconPic = this.sPicDirUrl+"/wkbIconZ";    break;
      default:   sIconPic = this.sPicDirUrl+"/wkbIconUnk";  break;
      }
      sIcon = "";
      sIcon += '<a class="no_addon_pic" href="javascript:'+sOnDelete+'">';
      sIcon += '<img class="bildlink"';
      sIcon += "     src='"+sIconPic+".gif'";
      sIcon += "     onmouseover='OnImgHover(this,\""+sIconPic+"_hover.gif\");' onmouseout='OnImgHover(this);'"
      sIcon += "     alt=''>";
      sIcon += "<\/a>";
      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
      var sTextID = ("" != awO.resultID)  ?  awO.resultID  :  awO.bez;
      if( bMitHandler && awO.url && ("" != awO.url))
        sRow += AddTableColumn( '<a href="javascript:'+sOnDetail+'">'+sTextID+'<\/a>');
      else      
        sRow += AddTableColumn( sTextID);

      // 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);
      }

      // neue Zeile anhaengen, 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"])
                         , "");
  }

  // table end
  result += "<\/table>";

  return result;
}


function Warenkb_AsUrlParams( aFilterHerst)
/* Liefert Inhalt des Warenkorbs als URL-Parameter formatiert zurueck,
   also in der Form "key=value&key=value&key=value".

  - mit aFilterHerst kann die Ausgabe auf Daten eines bestimmten Herstellers
    beschraenkt 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())) + "&";

      // naechstes Element
      nWritten++;
    }
  }


  // Anzahl geschriebener Warenkorb-Elemente anhaengen
  return result + "WkbAnz=" + nWritten;
}


function Warenkb_AsFormValues( aTargetForm, aMaxCount, aFilterHerst)
/* Fuellt die in aTargetForm enthaltenen Elemente mit den Daten des Warenkorbs,
   der Parameter aMaxCount gibt die maximale Kapazitaet des Formulars an.

   Rueckgabewert ist die Anzahl zu uebertragender Elemente. Ist dieser Wert groesser
   als aMaxCount, dann ist die Kapazitaet des Formulars nicht ausreichend.

   Das Targetform muss neben einem Input-Element fuer die Anzahl verwendeter Eintraege
   alle entsprechenden Input-Elemente in der angegebenen Anzahl bereitstellen, fuer
   die Angabe aMaxCount=20 waere das zB. (Ausschnitt):

      <!-- hier wird die Anzahl belegter Eintraege 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
   beschraenkt 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 Eintraege frei?
      if( nWritten < aMaxCount)
      {
        // Werte uebertragen
        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()));

        // naechstes Element
        nWritten++;
      }
    }
  }

  // Anzahl geschriebener Warenkorb-Elemente
  SetFormValue( aTargetForm, "WkbAnz", String(nWritten));

  // alle restlichen Elemente mit Leerstrings fuellen
  // nicht zwingend erforderlich, vermindert aber die zu uebertragende 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, "");

    // naechstes Element
    nWritten++;
  }

  // Anzahl zu schreibender Eintraege zurueckgeben
  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 Rueckgabewert geliefert
//
// WICHTIG: Das AuswObj muss 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 fuer 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
// Rueckgabewert ist das im Warenkorb befindliche Objekt (das muss 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 koennen
    // ja auch mit unterschiedl. Zubehoer ausgewaehlt 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 muessten eigentlich auch identisch sein

      // URL korrigieren?
      if( aAwO.url && ("" != aAwO.url))
        objFound.url = aAwO.url;

      // Menge erhoehen und fertich
      objFound.anzahl++;
      return objFound;
    }
  }

  // neues Objekt -> WkbID pruefen
  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 haetten wir weiter oben herausfinden muessen
    // Ansonsten stimmt die angegebene ParentID wohl nicht
    ASSERT( (null == objFound) || (objFound != aAwObj));
  }

  // WkbID erzeugen, falls noetig
  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()
// FIX: Kinder aller Toplevel-Eintraege (zB. Zubehoer) wurden nicht mehr durchsucht / 11.08.06 Gey
{
  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-Eintraege wieder einfuegen
  var awo = null;
  for( i = 0;  i < oldL.length;  i++)
  {
    awo = oldL[i];
    if( 0 >= awo.anzahl)                    // Menge = 0, der fliegt raus
    {
      bNeedUpdate = true;
      continue;
    } 
    
    // der bleibt drin - seine Kinderlein rekursiv durchsuchen
    aObjL[aObjL.length] = awo;
    if( this.RemoveNullEntriesFromList( awo.childL))
      bNeedUpdate = true;
  }

  // Rueckgabewert
  return bNeedUpdate;
}


function Warenkb_RemoveNullEntries()
// Entfernt alle Eintraege mit Anzahl=0 aus dem Warenkorb, ausserdem werden
// damit auch automatisch alle Kinder solcher Elemente entfernt
// Rueckgabewert true, wenn eine erneute Darstellung der HTML-Tabelle erforderlich ist
{
  return this.RemoveNullEntriesFromList( this.objL);
}


function Warenkb_Empty()
// Loescht den Inhalt des Warenkorbs
// Rueckgabewert 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)
/* uebernimmt Daten aus einem Formular
   Das Formular muss eine mit AsHtmlTable() erzeugte Tabelle enthalten
   Rueckgabewert true, wenn eine erneute Darstellung der HTML-Tabelle erforderlich ist

   Um Elemente mit Anzahl=0 aus dem Warenkorb zu entfernen, rufen Sie anschliessend
   die Methode RemoveNullEntries() auf. Falls diese Methode oder RemoveNullEntries()
   den Rueckgabewert "true" liefert, aktualisieren Sie zusaetzlich 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 fuer 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 zusamnmenhaengenden String, so dass
// 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 schliessende ) 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 Stueck dazwischen
  s = s.substr(0,iH);

  // die einzelnen AWO(...) heraussuchen
  while( 0 < s.length)
  {
    // naechsten 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 schliessende ) suchen
    iH = 0;
    while( (1 <= iKlammern) && (iH < s.length))
    {
      if( ")" == s.substr(iH,1))  iKlammern--;
      if( "(" == s.substr(iH,1))  iKlammern++;
      iH++;
    }

    // das naechste AWO ist das Stueck 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 schliessende ) 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 kuerzen
        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);
    }
  }
}




// *EOF*
