/*
*  Spaix V3 Konfigurator
*  Common script functions library
*  (c) 2000-2006 VSX Vogel Software GmbH. All rights reserved.
*/

// ----  globale Variablen und Konstanten

var g_isGuest = true; /* gegenwaertig immer als Gast im system */


//--- globale Hooks ---------------

// Bei Bedarf kundenspezifische Anpassungen+Ergaenzungen in der Scriptdatei 
// customer.js (tmpl) vornehmen und diese dann in incHeader.htm einbinden

// Syntax:    function PanelbarFilter( aID, aData)
// Parameter: PanelbarID, Datenobjekt mit Werten und Eintraegen 
// Rueckgabe: true = Eintrag akzeptieren, false = Eintrag unterdruecken
var g_PanelbarFilterHook = null;

// Debugoptionen
var g_DebugWaitState = false;
var g_DebugCursor    = false;


//---- UI Funktionen ------------

function DetermineBrowserLanguage()
{
  // Browser befragen
  var sKzl;
  if(      navigator.systemLanguage)  
    sKzl = navigator.systemLanguage;
  else if( navigator.userLanguage)    
    sKzl = navigator.userLanguage;
  else if( navigator.browserLanguage) 
    sKzl = navigator.browserLanguage;
  else if( navigator.language)        
    sKzl = navigator.language;
  else
    sKzl = "en";
    
  // kleinschreibung durchsetzen
  sKzl = sKzl.toLowerCase()  ;

  /* moegliche Sprach-und Regionalcodes:
    MSDN Library Visual Studio 6.0
      Plattform-SDK
        Internet-/Intranet-/Extranet-Dienste
          Dynamic HTML
            DHTML References
              Document Object Model References
                Properties
                  Language Codes
  */

  // Spezielle Regionalcodes ("de-at") abtesten
  switch( sKzl)
  {
  case "pt-br" : return "PORTUGUESE_BRAZIL";
  default:
    // alle anderen auf ihre Standardsprache reduzieren
    if( 2 < sKzl.length)
      sKzl = sKzl.substr(0,2);
    break;  
  }  
  
  // Standardsprachen ("de") testen
  // Abweichungen zur vsProgram sind gekennzichnet
  switch( sKzl.toLowerCase())
  {
  // standard langs
  case "de"    : return "GERMAN";
  case "en"    : return "ENGLISH";
  case "fr"    : return "FRENCH";
  case "it"    : return "ITALIAN";
  case "es"    : return "SPANISH";
  // other supported langs
  case "hu"    : return "HUNGARIAN";
  case "pl"    : return "POLISH";
  case "sk"    : return "SLOVAKIAN";
  case "sv"    : return "SWEDISH";   // diff in spaix
  case "pt"    : return "PORTUGUESE";
  case "tr"    : return "TURKISH";
  case "ru"    : return "RUSSIAN";
  case "nl"    : return "DUTCH";
  case "hr"    : return "CROATIAN";
  case "fi"    : return "FINNISH";
  case "cs"    : return "CZECH";     // diff in spaix
  case "sl"    : return "SLOVENIAN"; // diff in spaix
  case "sr"    : return "SERBIAN";
  case "lv"    : return "LATVIAN";
  case "da"    : return "DANISH";    // diff in spaix
  case "ro"    : return "ROMANIAN";
  case "el"    : return "GREEK";     // diff in spaix
  case "lt"    : return "LITHUANIAN";
  case "bg"    : return "BULGARIAN";
  case "mk"    : return "MACEDONIAN";
  default:
    break;
  }  

  // default lang
  return "ENGLISH";
}

function GetIconLinkHtml( aHref, aCssID, aTarget, aText, aPicUrl)
// returns HTML for "iconized" Link
{
  var sHtml = "";
  sHtml += '<p> <a class="icon" ';
  if( "" != aCssID)
    sHtml += ' id="'+aCssID+'"';
  if( "" != aTarget)  
    sHtml += ' target='+aTarget;
  sHtml += ' href="'+aHref+'">';

  if( "" != aPicUrl)
    sHtml += '<img alt="'+aText+'" src="'+aPicUrl+'">';

  sHtml += aText;
  sHtml += '<\/a> <\/p>';
  return sHtml;
}


//--- CSS-Tools --------------------------------------------------------------


function ElementIncludesCssClass( aElm, aClass)
{
  // grober Test, reicht meist schon aus
  if( 0 <= aElm.className.indexOf(aClass))
  {
    // Suchstring gefunden, also genauer pruefen
    var i,s;
    var clsL = aElm.className.split(" ");
    for( i = 0;  i < clsL.length;  ++i)
      if( clsL[i])
        if( aClass == clsL[i])
          return true;    // ist schon drin
  }
  
  return false
}

function AddCssClass( aElm, aClass)
// Fuegt aElm die CSS-Klasse aClass hinzu
{
  // Parametertest
  if( (! aElm) || ("string" != typeof aElm.className))
    return
  
  if( ElementIncludesCssClass(aElm, aClass) )
    return;
    
  // anheften      
  aElm.className += " "+aClass;
}        


function RemoveCssClass( aElm, aClass)
// Entfernt die CSS-Klasse aClass von aElm
{
  // Parametertest
  if( (! aElm) || ("string" != typeof aElm.className))
    return
  
  // grober Test, reicht meist schon aus
  if( 0 > aElm.className.indexOf(aClass))
    return;
    
  // Suchstring gefunden, also genauer pruefen
  var i,s;
  var clsL = aElm.className.split(" ");
  var newL = new Array();
  for( i = 0;  i < clsL.length;  ++i)
    if( (clsL[i]) &&  (aClass != clsL[i]))
      AddToArray( newL, clsL[i]);
      
  // neuen Wert setzen    
  aElm.className = newL.join(" ");
}        


//--- Layertools -----

function SetLayerPosition( aDiv, aPosition)
// Setzt CSS-Position des Layers
{
  var lay = findLayer( document, aDiv);
  if( null != lay)
    lay.style.position = aPosition;  // zb. absolute, relative, ...
}


function ShowLayerEx( aDiv, aShow, aVisibleStyleStatic)
// Ein- und ausblenden, zusaetzlich wird der Layer in/aus dem Fluss genommen
// aVisibleStyleStatic (optional) gibt an, ob static statt relative verwendet werden soll
{
  if( aShow)
  {
    var sStyle = aVisibleStyleStatic ? "static" : "relative";
    SetLayerPosition( aDiv, sStyle);  // in den Fluss 
    showLayer( aDiv, true);
  }
  else
  {
    showLayer( aDiv, false);
    SetLayerPosition( aDiv, "absolute");  // aus dem Fluss
  }
}

function ShowBodyContentScrollbar()
// Darf der DIV "bodycontent" eine scrollbar zeigen?
// Wenn overflow = hidden dann nicht
{
  var bIsVisible = ( (null != document.body) && 
                     ("undefined" != typeof document.body) && 
                     (! ElementIncludesCssClass( document.body, "boxed") ) );
 
  /* Test */
  /*
   das geht nicht, da wir overflow-x /overflow-y setzen und diese werte aber nicht abfragen koennen.
   
   var elem = document.getElementById("bodycontent");
   if( null != elem)
   {
     alert( bIsVisible + ' ' + ( ("undefined" != typeof elem.style) &&
                                 ("undefined" != typeof elem.style.overflow) &&
                                 ("hidden" != elem.style.overflow) ) );     
   }
 */                                
  
  return bIsVisible;  
}


function ScrollbarVisible( elemID )
{
  var elem = document.getElementById(elemID);
  
  if( (null == elem) || ("undefined" == typeof elem.scrollHeight) || ("undefined" == typeof elem.clientHeight) )
  {
    ASSERT( false );
    return true; /* seite lieber mit scrollbar berechnen*/
  }  
  
  var bIsVisible;
  
  if (elem.scrollHeight == elem.clientHeight)
    bIsVisible = false;
  else
    bIsVisible = (elem.scrollHeight + 1) > elem.clientHeight;

  //alert(bIsVisible + ' ' + elem.scrollHeight + ' ' + elem.clientHeight );

  return bIsVisible;
}


function GetXScroll( elm)
// Liefert den Scrolloffset des Elements in X-Richtung
{
  if( elm.pageXOffset) alert("X"+elm.pageXOffset);
  if( "number" == typeof elm.pageXOffset)    return elm.pageXOffset;
  if( "number" == typeof elm.scrollLeft)     return elm.scrollLeft;
  return 0;  
}


function GetYScroll( elm)
// Liefert den Scrolloffset des Elements in Y-Richtung
{
  if(elm.pageYOffset) alert("Y"+elm.pageYOffset);
  if( "number" == typeof elm.pageYOffset)    return elm.pageYOffset;
  if( "number" == typeof elm.scrollTop)      return elm.scrollTop;
  return 0;  
}


function GetLayerScrollPos( aDoc, aName)
// Sichert die Scrollpos des Layers
{
  var lay  = findLayer( aDoc, aName);
  if( ! lay)
    return null;  // keinen Muell liefern

  var obj = new Object();
  if( lay.pageYOffset)
  {
    obj.nX = lay.pageXOffset;
    obj.nY = lay.pageYOffset;
  }
  else if( lay.scrollTop)
  {
    obj.nX = lay.scrollLeft;
    obj.nY = lay.scrollTop;
  }
  else
  {
    return null;    // keinen Muell liefern
  }    
  
  return obj;
}
  

function SetLayerScrollPos( aDoc, aName, aPos)
// Stellt gesicherte Scrollpos wieder her
{
  var lay  = findLayer( aDoc, aName);
  if( (! lay) || (! aPos))
    return;
    
  if( lay.scrollTo)
  {
    lay.scrollTo( aPos.nX, aPos.nY);
  }
  else if( ! isNaN(lay.scrollTop))   // einfaches if() liefert false bei 0 
  {
    lay.scrollLeft = aPos.nX;
    lay.scrollTop  = aPos.nY;
  }
}


//-- Tokenizing -------------------------------------------------------


function TokenizeEncode( aStr)
// Hex-Escaping der Trennzeichen (vgl. auch basketescape)
// Implementierungsaenderungen UNBEDINGT abgleichen mit FktHtml.pas
{
  var sData = ReplaceAll( aStr, /\%/, "%25");  // escaping the escape
  //
  sData = ReplaceAll( sData,    /\|/, "%7C");
  sData = ReplaceAll( sData,    /\;/, "%3B");
  //
  return sData;
}


//--- DIMs -------------------------------------------------------------

// Alle Funktionen erfordern ein dimsettings-Objekt, welches <#IS__DIM format=JSON> liefert
// Fuer weitere Parameter siehe TDimListCodeGenerator

function DlgToIntern( nValue, aDimNr, dimsettings)
{
  var i,obj;
  for( i = 0;  i < dimsettings.length;  ++i)
  {
    obj = dimsettings[i];
    if( aDimNr == obj.nr)
      return obj.DlgToInt(nValue);
  } 
  
  return nValue; 
}


function InternToDlg( nValue, aDimNr, dimsettings)
{
  var i,obj;
  for( i = 0;  i < dimsettings.length;  ++i)
  {
    obj = dimsettings[i];
    if( aDimNr == obj.nr)
      return obj.IntToDlg(nValue);
  } 
  
  return nValue; 
}


// --- Warenkorb-Utils, "Serverside" version ---------------------------


// Projektstatus
var cProj_Virgin   = 0x00;      // jungfraeuliches Projekt - unveraendert und nicht gespeichert
var cProj_Database = 0x01;      // ein Projekt-Datensatz in der DB existiert
var cProj_Modified = 0x02;      // Projekt hat ungespeicherte Aenderungen
var cProj_IsCRM    = 0x04;      // Projekt ist mit einer CRM-Entitaet verknuepft

// ausgewaehlte CRM-Entities (generisch!), exakt wie in der ISAPI
var cent_Invalid     = 0;      // der Nullwert
var cent_Account     = 1;      // Kunde
var cent_Contact     = 2;      // Kontaktperson
var cent_Opportunity = 3;      // Verkaufschance
var cent_Quote       = 4;      // Angebot


function basketescape( aStr)
// Sichere Formatierung oder Qoutierung fuer Zeichenketten, die an den Server zurueckgesendet werden
// Steuerzeichen sind Semikolon zum Trennen von Zellen und Senkrechter Strich zum Trennen von Zeilen
// Nutzzeichen werden durch Prozent gekennzeichnet (vgl. auch TokenizeEncode)
//"abc%;|def"	  
//"abc%%20%25def"	  
//"abc%77%7720%7725def"	  
{
  var sStr2 = aStr.replace(/%/g, "%%"); 
  sStr2 = sStr2.replace(/;/g, "%;"); 
  return sStr2.replace(/\|/g, "%|"); 
}  


// Detailfenster
var g_ArtikelWnd = null;  // static :-)

function ArtikelDetails( sArtNr, sMake, sLgg, sCaption)
// Default-Implementierung der Detailanzeige 
{
  var sUrl = MakeEtaDetailUrl( sMake, sArtNr, sLgg);
  if( (null != g_ArtikelWnd) && (! g_ArtikelWnd.closed))
    g_ArtikelWnd.close();
  g_ArtikelWnd = window.open( sUrl, sCaption); 
}


function MakeEtaDetailUrl( sHerst, sArtnr, sLgg)
// Berechne Default-Detaillink fuer Artikel in einem externen Browserfenster 
{
  return "../externlink.asp?IS__NEXTPAGE=bdyEtaDetail"
       + "&SZ__MAKE=" +SafeEscape(sHerst)
       + "&ET__ARTNR="+SafeEscape(sArtnr)
       + "&L__LGG="+SafeEscape(sLgg);
}

function ZubDetails( sArtnr, sSuppl, sLgg )  
// Neues Fenster um ein Zub zu besichtigen
{
  var sUrl =  "../externlink.asp?IS__NEXTPAGE=winZubInfos"
       + "&TP__HERST=" + SafeEscape( sSuppl)
       + "&TP__SELID=" + SafeEscape( sArtnr)
       + "&L__LGG=" + SafeEscape( sLgg );
       
  if( (null != g_ArtikelWnd) && (! g_ArtikelWnd.closed))
    g_ArtikelWnd.close();
  g_ArtikelWnd = window.open( sUrl, "ZubInfos"); 
}  


//--- Fokussierung in Listen --------

// Bug 1579 -> Kunde entscheidet sich dafuer die ausgewaehlte Zeile  einer Liste nicht hervorzuheben.
// Ich baue das nicht aus, weil sich der Kunde wahrscheinlich umentscheidet
var cFocusLineClass = ""; // "Focused"; // CSS Klasse fuer fokusierte Zeile

function SetFocusedStyle( aElm, bShowMouseHand)
// Fuegt aElm die CSS-Klasse "Focused" hinzu
// optionaler boolean parameter "bShowMouseHand" -> Soll eine Maushand angezeigt werden um
// dem anwender zu symbolisieren, das diese Zeile angeklickt werden kann?
{
  if ("" != cFocusLineClass) 
    AddCssClass( aElm, cFocusLineClass);
    
  if( (bShowMouseHand) || ("undefined" == typeof bShowMouseHand) )
  {
    // Und warum kann man das nicht uebers CSS machen?  
    // Warum muß das hier hartcodiert stehen?
    SetWinCursor( "pointer");
  }  
}        


function ClearFocusedStyle( aElm)
// Entfernt die CSS-Klasse "Focused" von aElm
{
  if ("" != cFocusLineClass) 
    RemoveCssClass( aElm, cFocusLineClass);
  
  // Und warum kann man das nicht uebers CSS machen?  
  // Warum muß das hier hartcodiert stehen?
  SetWinCursor( "auto");
}    

function FocusButton( aElmID )
{
  var aElem = document.getElementById(aElmID);
  if( aElem)
    aElem.focus();
}

//---- Selektion in Listen --------

function SetSelectedRow( aRow, LastSelRow )
// fuegt einen CSS Style an einen Zeile
// LastSelElm = Letztes selektieres Element
{
  // alter Zeile den Style entfernen (kein Multiselect!)
  ClearSelectedRow( LastSelRow )

  AddCssClass( aRow, "Selection");
} 

function ClearSelectedRow( aRow )
// Entfernt einen CSS Style an einen Zeile
{
  RemoveCssClass( aRow, "Selection");
} 


// --- Layout - Cursor ---------------------------


function SetWinCursor( sStyle )
// aendert den Cursor des Fensters
{
  if( document.all)  // und was ist mit FireFox?
    SetCursor( document.all.aBody, sStyle );
  else               // dann probieren wir das mal so... 
    SetCursor( document.getElementById("aBody"), sStyle )  
}


function SetCursor( aElem, sStyle )
// aendert den Cursor eines Elements
{
  if ((aElem) && ("undefined" != typeof aElem.style))
  {
    if (g_DebugCursor)
      alert( "SetCursor FROM: " + aElem.style.cursor + "   TO: " + sStyle.toLowerCase() );
    
    switch( sStyle.toLowerCase())
    {
    case "wait"      : aElem.style.cursor = "wait";    break;
    case "auto"      : aElem.style.cursor = "auto";    break;
    case "default"   : aElem.style.cursor = "default"; break;
    case "crosshair" : aElem.style.cursor = "crosshair"; break;     
    case "none"      : if ("" != aElem.style.cursor) aElem.style.cursor = "";        break;      
    case ""          : aElem.style.cursor = "";        break;    // Leerstring wie "none"  
    default:  /* einfach mal ignorieren? */ break;
    }
  }
}
  

//--- Hint-Funktionen ------------------------------------------

// Liefert den Code fuer die Eventhandler eines Links: onmouse, onclick etc.
var g_sLinkCode      = " onmouseout='return OnMouseOutInfo();'"
                     + " onmouseover='return OnMouseOverInfo(this);'";
// Wenn die Seite neu geladen / verlassen wird, dann in den Wartezustand gehen                     
var g_sLinkEventCode = g_sLinkCode
                     + " onclick='return OnClickInfo(this);'";


function GetControlText( aCtrl )
// es gibt verschiedene Moeglichkeiten den Text eines Elements zu ermitteln
{
  // Title
  if ( (aCtrl.title) && ("" != aCtrl.title) )
    return aCtrl.title;
  else  
  // InnerText (nur Opera, IE )
  if ( (aCtrl.innerText) && ("" != aCtrl.innerText) )
    return aCtrl.innerText;
  else
  // innerHTML (FireFox Notnagel)
  if ( (aCtrl.innerHTML) && ("" != aCtrl.innerHTML) )
    return aCtrl.innerHTML;
  else
    return "";
}

function CheckWaitMod()
// prueft ob wir uns im Wartezustand befinden
{
  return (window.bWaitMod) //&& (window.sWaitMsg) && ("" != window.sWaitMsg) )
}

function OnMouseOverInfo( aCtrl )
// setzt den hint eines Controls in die Statusleiste des Browsers
{
  // Wenn wir uns im wartezustand befinden ("Bitte Warten Aktion wird ausgefuehrt")
  if ( CheckWaitMod())
  {
    SetStatusMsg( true );
    SetCursor( aCtrl, "wait");
  }
  else
  {
    SetStatusMsg( true, GetControlText( aCtrl ) );
    SetCursor( aCtrl, "none");   // FIX: FFox bringt bei "auto" manchmal den falschen Cursor an, leer ist idR. besser / 27.09.06 Gey
  }
  return true;
}

function OnMouseOutInfo()
// Statusmeldung zuruecksetzen
{
  // Wenn wir uns im wartezustand befinden ("Bitte Warten Aktion wird ausgefuehrt")
  SetStatusMsg( CheckWaitMod());
  return true;
}

function OnClickInfo( aCtrl, sWaitMsg )
// Reaktion auf einen Klick, der das Fenster in den Wartezustand versetzt
{
  // zu verwendenden Text bestimmen
  var sTxt;
  if( "string" == typeof sWaitMsg)
    sTxt = sWaitMsg;
  else if( "string" == typeof g_lggActW)
    sTxt = g_lggActW;
  else
    sTxt = "Loading ...";   

  // ab die Post ...
  SetWaitState( sTxt);
  OnMouseOverInfo( aCtrl );
  
  // FIX: Rueckgabewert vergessen?
  return true;
}

function SetStatusMsg( bSet, sMsg )
// Setzen der Wartenmessage
{
  if( bSet)
  {
    if ( (sMsg) && ("" != sMsg) )
    {
      window.status        = DecodeString( sMsg);
      window.defaultStatus = window.status;
    }
    else if (window.sWaitMsg)
    {
      window.status        = window.sWaitMsg;
      window.defaultStatus = window.status;
    }  
    else
    {
      window.status        = '';  
      window.defaultStatus = '';
    }
  }
  else
  {
    window.status        = "";
    window.defaultStatus = "";
  }  
  return true;
}

function SetWaitState( sStatusMsg )
// Setzen des Fensters in den Wartezustand
{
  if (! window.bWaitMod)
  {
    if (g_DebugWaitState)
      alert( "SetWaitState");  
      
    window.bWaitMod = true; 
    window.sWaitMsg = DecodeString( sStatusMsg);
    window.onmouseover = SetStatusMsg( true );
    SetWinCursor( "wait");
  }
}

function SetNormalState()
// Setzen des Fensters in den Normalzustand
{
  if (window.bWaitMod)
  {
    if (g_DebugWaitState)
      alert( "SetNormalState");       

    window.bWaitMod = false; 
    window.sWaitMsg = "";
    window.onmouseover = null;
    SetStatusMsg( false);
    SetWinCursor( "none");   // FIX: FFox bringt bei "auto" manchmal den falschen Cursor an, leer ist idR. besser / 27.09.06 Gey
  }  
}

// --- Events -------------------------------------


function SetEnterEvent( aFkt )
// Erzeugt einen Eventhandler der beim Clicken auf Enter die uebergebene Fkt aufruft
// Sollte die Fkt null sien, dann wird der Eventhander geloescht
{
  if (null == aFkt)
  {
    // Eventhandler suchen
    var EventHandler = GetOnClickHandler( false );     

    // Event unregistrieren  
    if (null != EventHandler) 
      EventHandler.UnregisterKeyEvent( 13); // 13 = ENTER  
  
    //document.onkeyupHandler = null;
    //document.onkeyup        = null;
    return;
  }  
  
  // eine guelitegt Fkt muss sein
  if ("function" != typeof aFkt) 
    return;   
    
  // Eventhandler suchen
  var EventHandler = GetOnClickHandler( true );     

  // Event registrieren  
  if (null != EventHandler) 
    EventHandler.RegisterKeyEvent( 13, aFkt); // 13 = ENTER
}

function GetEnterEvent()
// Rueckgabe der Fkt die aktuell auf ein ENTER reagiert
{
  // Eventhandler suchen
  var EventHandler = GetOnClickHandler( false );   
  if (null != EventHandler)
    return EventHandler.GetEvent( 13 );  // 13 = ENTER
  else 
    return null;
  
}

function EventHandler_Create( aKeyArr)
{
  this.RegisterKeyEvent   = EventHandler_RegisterKeyEvent;
  this.UnregisterKeyEvent = EventHandler_UnregisterKeyEvent;
  this.OnClick            = EventHandler_OnClick;
  this.GetKeyCode         = EventHandler_GetKeyCode;
  this.GetEvent           = EventHandler_GetEvent;    
  
  this.KeyArr   = new Object; // Array mit gemappten Key = Fkt
  this.KeyCount = 0;          // Anzahl ueberwachter Keys
}

function EventHandler_GetKeyCode( iKey )
// Beim Mapping kann es probleme geben, wenn Zahlen gemappt werden
// Drum einfach in einen String umwandeln
{
  return "k" + iKey.toString(); 
}

function EventHandler_UnregisterKeyEvent( iKey )
{
  if ("function" == typeof this.KeyArr[ this.GetKeyCode( iKey) ])
  {
    this.KeyCount--;  
    this.KeyArr[ this.GetKeyCode( iKey ) ] = null;  
  }  
}

function EventHandler_RegisterKeyEvent( iKey, aEvent)
{
  // Anzahl nur hochzahlen wenn neuem Key
  if ("function" != typeof this.KeyArr[ this.GetKeyCode( iKey) ])
    this.KeyCount++;
  
  // schnelles mapping
  this.KeyArr[ this.GetKeyCode( iKey) ] = aEvent; 
}

function EventHandler_GetEvent( iKey )
// rueckgabe der Event Fkt zum Tastencode
{
  return this.KeyArr[ this.GetKeyCode( iKey) ];
}

function EventHandler_OnClick( iKey )
{
  var EventFkt = this.GetEvent( iKey )
  if ("function" == typeof EventFkt )
  { 
    // Wenn wir dieses Oncklick übernehmen, dann das Event abbiegen
    ClearEvent( window );
    EventFkt( iKey );
    return true;
  }  
  return false;
}

// -- allgemeine Eventhandler fuer OnClick ----------------

function GetOnClickHandler( bCanCreate )
// gibt den bestehenden Onclick hander oder erzeugt diesen neu und registriert ihn
{
  if ( ("object" == typeof document.onkeyupHandler) && (null != document.onkeyupHandler) )
    // bestehenen Eventhander nehmen
    EventHandler = document.onkeyupHandler;
  else  
  {
    if (bCanCreate)
      // Eventhandler erzeugen und ans dokument haengen
      EventHandler = new EventHandler_Create(); 
    else
      EventHandler = null;      
      
    document.onkeyupHandler = EventHandler
  }  
  
  // Eventhander anschliessen wenn vorhanden
  if (null != document.onkeyupHandler)
    document.onkeyup = OnKeyUpClick;   
  
  return EventHandler;
}
  
function OnKeyUpClick( Event )
// Reaktion auf onkeyup
{  
  // Eventhandler definiert?
  if ( ("object" != typeof document.onkeyupHandler) ||
       (null == document.onkeyupHandler) ||
       (0 == document.onkeyupHandler.KeyCount) )
    return;
  
  if (!Event)
    Event = window.event;
 
  var Code;
  if (Event.which) 
    Code = Event.which;
  else if (Event.keyCode) 
    Code = Event.keyCode;
  else
    Code = 0;
  
  // Evtl noch ein ? wenn return true?
  //ClearEvent( window);
   
  // Weiterreichen an Eventhandler  
  return document.onkeyupHandler.OnClick( Code );
}


// --- dynamisches HTML ---------------------------

function Build_InputEdit( sClass, sType, sID, sName, sValue, sOnChangeFkt)
// Bauen einer Eingabebox (Editfeld)
{
  var sHtml = "<input";
  
  // diverse Parameter
  if ( "" != sClass) 
    sHtml += " class='"+sClass+"'";

  if ( "" != sType) 
    sHtml += " type='"+sType+"'";    

  if ( "" != sID) 
    sHtml += " id='"+sID+"'";

  if ( "" != sName) 
    sHtml += " name='"+sName+"'";

  if ( "" != sValue) 
    sHtml += " value='"+sValue+"'";  

  if ( "" != sOnChangeFkt) 
    sHtml += " onchange='"+sOnChangeFkt+"'";    
   
  return sHtml+">";
}

function Build_SelectBox( sCtrID, sCtrName, sCurrVal, sValArr, sOnChangeFkt)
// Bauen einer Combobox
{
  var sHtml     = "<select";  
  var bSelected = false;

  // diverse Parameter
  if ("" != sCtrID)
    sHtml += " id='"+sCtrID+"'";  

  if ("" != sCtrName)
    sHtml += " name='"+sCtrName+"'";     

  if ( "" != sOnChangeFkt) 
    sHtml += " onchange='"+sOnChangeFkt+"'";        
  
  sHtml += '>';
    
  if (null != sValArr)     
  {
    var sCurrValDec = DecodeString( sCurrVal );
    for( var i = 0;  i < sValArr.length;  ++i) 
    {
      if ( (! bSelected) && ( (sValArr[i] == sCurrVal) || (sValArr[i] == sCurrValDec) ) )
      {
        bSelected = true; // gefunden
        sHtml += " <option selected>";
      }
      else
        sHtml += " <option>";
    
      sHtml += sValArr[i] + "<\/option>"; 
    }
  }  
  
  return sHtml + "<\/select>";   
}

function Build_Line3( sBez, sVal, isInput, sDim)
// Bauen einer Zeile vom Typ "3-Spaltig"
{
  var sHtml = "<tr><td class='lbl3'>" + sBez + "<\/td>";
  if (isInput)
    sHtml += "<td class='edt3'>";
  else
    sHtml += "<td class='txt3'>";  
  sHtml += sVal + "<\/td>"
           + "<td class='dim3'>" + sDim + "<\/td><\/tr>";
  return sHtml;         
}

function Build_Line2( sBez, sVal, isInput)
// Bauen einer Zeile vom Typ "2-Spaltig"
{
  var sHtml = "<tr><td class='lbl2'>" + sBez + "<\/td>";
  if (isInput)
    sHtml += "<td class='edt2'>";
  else
    sHtml += "<td class='txt2'>";  
  sHtml += sVal + "<\/td><\/tr>";
  return sHtml;         
}

function Build_RadioGroup( sCtrName, sValArr, sShowValArr, sChecked, sFkts, sTrenner)
// Radiogroup bauen
{
  var sDefHtml = "<input type='radio' class='radio'";

  if ("" != sCtrName)
    sDefHtml += " name='"+sCtrName+"'";     

  // Funktionen
  sDefHtml += sFkts;        

  var sHtml = "";

  if ( (null != sValArr) && (null != sShowValArr) && (sValArr.length == sShowValArr.length) )
  {
    var sCheckedDec = DecodeString( sChecked );
    var sValue;
    for( var i = 0;  i < sValArr.length;  ++i)
    {
      sValue = sValArr[i];
      sHtml += sDefHtml + " value='"+sValue+"'"
      if ( (sValue == sChecked) ||  (sValue == sCheckedDec) )
        sHtml += " checked>";
      else
        sHtml += ">";      
    
      sHtml += sShowValArr[i]
             + sTrenner;
    }
  }  
  return sHtml;
}

function Build_TextArea( sClass, sID, sName, sValue, sOptParam)
// Bauen eines Textfeldes
{
  var sHtml = "<textarea";
  
  // diverse Parameter
  if ( "" != sClass) 
    sHtml += " class='"+sClass+"'";

  if ( "" != sID) 
    sHtml += " id='"+sID+"'";

  if ( "" != sName) 
    sHtml += " name='"+sName+"'";
   
  return sHtml +" "+ sOptParam + ">" + sValue + "<\/textarea>";
}


//--- DOM Tools -------------------------------------------------------------


function DomGenerateElementID( aNameBase)
// DOM-Tool: erzeugt eine zufaellige ID fuer ein  Element
{
  return aNameBase + "_" + Math.round(1000000*Math.random()).toString();    
}


function DomCreateIframe( aNameAndID, aSrc, aFrameborder, aScrolling)
// DOM-Tool: Liefert einen vorkonfigurierten IFRAME
{
  // optionale Parameter mit defaultwert
  if( ("string" != typeof aNameAndID) || ("" == aNameAndID))
    aNameAndID = DomGenerateElementID("iframe");
  
  // und los gehts
  iframe = document.createElement('iframe'); 
  iframe.setAttributeNode( DomCreateAttribute( "id",      aNameAndID));
  iframe.setAttributeNode( DomCreateAttribute( "name",    aNameAndID));
  
  // noch mehr Optionales
  if( "string" == typeof aSrc)
    iframe.setAttributeNode( DomCreateAttribute( "src",  aSrc));
  if( "undefined" != typeof aFrameborder)
    iframe.setAttributeNode( DomCreateAttribute( "frameborder",  aFrameborder));
  if( "undefined" != typeof aScrolling)
    iframe.setAttributeNode( DomCreateAttribute( "scrolling",  aScrolling));
    
  return iframe;  
}


function DomCreateForm( aNameAndID, aMethod, aFormAction, aTarget)
// DOM-Tool: Liefert ein vorkonfiguriertes Formular
{
  // Pflichtparameter testen, sonst drohen unvorhergesehene Effekte bei submit()
  ASSERT( ("string" == typeof aFormAction) || ("" != aFormAction));
  
  // optionale Parameter mit defaultwert
  if( ("string" != typeof aNameAndID) || ("" == aNameAndID))
    aNameAndID = DomGenerateElementID("form");
  if( ("string" != typeof aMethod) || ("" == aMethod))
    aMethod = "post";
  
  // und los gehts
  form = document.createElement('form'); 
  form.setAttributeNode( DomCreateAttribute( "id",      aNameAndID));
  form.setAttributeNode( DomCreateAttribute( "name",    aNameAndID));
  form.setAttributeNode( DomCreateAttribute( "method",  aMethod));
  form.setAttributeNode( DomCreateAttribute( "action",  aFormAction));
  
  // noch mehr Optionales
  if( ("string" == typeof aTarget) || ("" != aTarget))   
    form.setAttributeNode( DomCreateAttribute( "target",  aTarget));
    
  return form;  
}


function DomCreateAttribute( aName, aValue)
// DOM-Tool: Liefert eine Attribute-Node
{
  var attr = document.createAttribute( aName);   
  attr.nodeValue = aValue;    
  return attr;
}


function DomCreateHiddenInput( aName, aValue)
// DOM-Tool: Liefert ein Hidden-Input-Element
{
  var inp = document.createElement('input'); 
  inp.setAttributeNode( DomCreateAttribute( "type",  "hidden"));
  inp.setAttributeNode( DomCreateAttribute( "name",  aName));
  inp.setAttributeNode( DomCreateAttribute( "value", aValue));
  return inp;
}




//--- Validierung von Eingaben in Inputs ------------------------------------
// Fuer Onchange bei Edits gut geeignet!

function ValidateInteger( aCtrl )
// Integer besteht aus Zahlen und hat keine Nachkommastellen
{
  if ("" != aCtrl.value)
    aCtrl.value = runden( GetDoubleFromStr( aCtrl.value ), 0);
}

function ValidateFloat( aCtrl )
// Float besteht aus Zahlen und hat Nachkommastellen
{
  if ("" != aCtrl.value) 
    aCtrl.value = GetDoubleFromStr( aCtrl.value );
}

function GetDoubleFromStr( aStr )
// Fkt um Str to int zu machen wenn '.' und ',' im String sind zb. 1.000,00
/*
  FRAGE: 
  - Wozu dient diese Funktion genau? 
  - Wo liegt der Unterschied zu StrToFloat()? 
  - Warum gibt es da einen Unterschied?
  - Funktioniert das auch mit allen Locales (Stichworte Dezimaltrennzeichen vs. Tausender-Trennzeichen)
*/  
{
  if ("" == aStr)
    return 0;
    
  // gibt es ein Komma   
  if (-1 != String(aStr).indexOf(",") )
    while (-1 != String(aStr).indexOf(".") )
      aStr = aStr.replace( ".", "");  // Wenn ja dann alle punkte entfernen
    
  return StrToFloat( aStr ); 
}

function CheckValue( aInp, aValue, sMsg)
// Prueft aValue, setzt im Fehlerfall den Focus auf aInp
{
  if( "" == aValue)
  {
    if ( (sMsg) && ("" != sMsg) )
      AlertBox( sMsg, false );
    else
    if ( (g_NeedInput) && ("" != g_NeedInput) )
      AlertBox( g_NeedInput, false );

    aInp.focus();
    return false;
  }
  return true;
}


// ---------------- Frame Funktionen ---------------------

function GetTargetFrame()   
{
  var frm = parent;  // des IFRAME
  if (null == frm)  
    AlertBox("ERR: GTF(): frame not found");  
  return frm;  
}

function GetTargetForm()
{
  var frm = GetTargetFrame();
  return (frm)  ?  frm.document.EDITFORM  :  null;  
}

function GetTargetFormValue( aName, aValue)
// Fragt einen Formularwert aus dem Sammelframe ab
// NICHT fuer Listen geeignet (NetScape)
{
  var inp = findScriptFormElement( GetTargetForm(), aName);
  if( null != inp)
    return inp.value;
  
  AlertBox("ERR: GTFV('"+aName+"'): target form element missing");  
  return "";
}    
    
function SetTargetFormValue( aName, aValue)
// setzt einen Formularwert *NUR* im Sammelframe
// NICHT fuer Listen geeignet (NetScape)
{
  var inp = findScriptFormElement( GetTargetForm(), aName);
  if( null != inp)
    inp.value = aValue;
  else 
    AlertBox("ERR: STFV('"+aName+"'): target form element missing");  
}

function SetTargetFormValueDynamic( sShortName, iIdx, sValue)
// bei dynamischen inputs sieht das anders aus
{
  var obj = new Object();
  obj.sShortName = sShortName;
  obj.iIdx       = iIdx;
  obj.sValue     = sValue;
  PerformFrameCallback( "setdyncolval", obj);
}
      
function PerformFrameCallback( aAction, aName, aParam)
// Client-Hilfsfunktion fuer den Frame-Callback-Aufruf
{
  var lpfnProc = GetCallbackFkt();
  if (null != lpfnProc)
    return lpfnProc( aAction, aName, aParam);

  AlertBox("ERR: PFC("+aAction+"): function OnFrameCallback() not found in parent frame.");  
  return "";
}


function PerformOpenerCallback( aAction, aName, aParam)
// Caller ermitteln, fuer Callback geaenderter BP-Daten
{
  // Gueltiger opener verfuegbar?
  if (null == opener) 
    return false;

  // Funktion bei jedem Aufruf erneut pruefen, sonst PRB falls 
  // jemand zwischenzeitlich das andre Fenster geschlossen hat
  var sType = typeof opener.OnFrameCallback;
  if( ("object" != sType) && ("function" != sType))  // beides moeglich, browserabhaengig
    return false;
   
  // Callback aufrufen
  return opener.OnFrameCallback( aAction, aName, aParam);
}


function GetCallbackFkt()
// rueckgabe des Frame-Callback-Aufruf
{
  var frm      = GetTargetFrame();
  var lpfnProc = frm.OnFrameCallback;
  var sTyp     = typeof lpfnProc;

  // Aufruf, wenn alles OK ist  
  switch( sTyp.toLowerCase())
  {
  case "function":
  case "object":    // beides moeglich, browserabhaengig
    return lpfnProc;
  default:
    return null; 
  }
}


// ---- GROESSENANPASSUNGEN ---------------------------------

// Ob diese speziellen Sachen nun auch wirklich hier in diese allgemeine 
// Scriptdatei gehoeren, daruer kann man sich streiten / Gey

var FRAMEHEADING_HEIGHT = 39;   // layoutbedingte Hoehe des oberen Pumpendetail-IFRAMEs, siehe CSS

function EncodeDgrAbm( iHeight, iWidth, bCalcWithDgrFactor)
// baut den Abm-String
// bCalcWithDgrFactor ist optional
{
  // allgemeinen Faktor abziehen wenn gewunscht
  if ( ("boolean" == typeof bCalcWithDgrFactor) && (bCalcWithDgrFactor) )  
  {
    // Mit diesen Faktor wird die Groesse des Diagramm umgerechnet
    var cFactor_Dgr = 0.85;
  
    iWidth  = iWidth * cFactor_Dgr;
    iHeight = iHeight * cFactor_Dgr;
  }  

  // Validieren
  if ( (10 > iWidth) || (2000 < iWidth) )
    iWidth = 500;
  if ( (10 > iHeight) || (2000 < iHeight) )
    iHeight = 500;

  return   "Dgr.W:" + Math.round( iWidth) + "|"
         + "Dgr.H:" + Math.round( iHeight);
}

function GetElementHeight( aElemId, iFactor )
// Gibt die hoehe des elements mit dieser ID zurueck
// optionaler Umrechnungsfaktor "iFactor"
{
  var Elem    = document.getElementById( aElemId );
  var iHeight = 0;
  if (Elem)
  {
    if (Elem.clientHeight) 
      iHeight = Elem.clientHeight;
    else
      iHeight = Elem.offsetHeight;
  }
  
  if(iFactor)  
    iHeight = iHeight * iFactor;
  
  return Math.round( iHeight);  
}

function GetElementWidth( aElemId, iFactor )
// Gibt die hoehe des elements mit dieser ID zurueck
// optionaler Umrechnungsfaktor "iFactor"
{
  var Elem   = document.getElementById( aElemId );
  var iWidth = 0;
  if (Elem)
  {
    if (Elem.clientWidth) 
      return Elem.clientWidth;
    else
      return Elem.offsetWidth;
  }
  if(iFactor)  
    iWidth = iWidth * iFactor;
  
  return Math.round( iWidth);  
}

function SetElementHeight( aElemId, sHeight )
// Setzt die hoehe des elements mit dieser ID
// Querverweis: Allgemeine Funktion SetElmHeight() in spaix.js
{
  var Elem = document.getElementById( aElemId );
  if ( ("undefined" != typeof Elem) && 
       ("undefined" != typeof Elem.style) && 
       ("undefined" != typeof Elem.style.height) && 
       (sHeight) &&
       ("" != sHeight) ) 
  {    
    var sHeightStr = sHeight.toString(); 
    // pruefen ob einheit bereits vorhanden
    if ( ("auto" != sHeight) &&
         ( -1 == sHeightStr.indexOf("em") ) &&
         ( -1 == sHeightStr.indexOf("px") ) )
      Elem.style.height = parseFloat( sHeight ) + "px";
    else  
      Elem.style.height = sHeight;
  }  
}

function CheckIFrameHeight( sParentElemId, ElemArr, sIframeId )
// hoehe des IFrames mit der ID <sIframeId> anpassen
// Der Iframe sitzt in einem großen Object mit der ID <sParentElemId>
// In diesem Objekt sitzen drueber oder drunter noch andere elemente die platz wegnehmen (Array mit IDs = ElemArr)
{
  // Parentgroesse ermitteln
  var iParent = GetElementHeight( sParentElemId );
  if (iParent) // <> 0
  {
    // groesse der anderen elemente ermitteln
    if (ElemArr)
    for (var i = 0; i < ElemArr.length; i++)
      iParent = iParent - GetElementHeight( ElemArr[i] );
    
    // Mindeshoehe von 50 px
    iParent = Math.max( iParent, 50 );
    // Maxhoehe 1500
    iParent = Math.min( iParent, 1500 );    

    // und setzen
    SetElementHeight( sIframeId, iParent);  
  }  
}

function UpdateListHeight( sScrollDivNm, iCount, iMaxLines )
// richtet die Groesse/Hoehe der Liste aus, je nachdem wieviele Zeilen vorhanden sind
// Anzahl der Zeilen mal Hoehe plus die Kopfzeile
// iCount    - Anzahl zum Anzeigen
// iMaxLines - Maximale Anzahl von Zeilen
{  
  var tabBody = document.getElementById( sScrollDivNm );
  if (null == tabBody) 
    return;
    
  var cLine = 1.5;

  var sum = cLine; // Kopfzeile
  
  if ( iMaxLines > iCount )
    sum += (iCount * cLine);
  else
    sum += (iMaxLines * cLine);

  tabBody.style.height = sum.toString() + "em";  
}


function HackSelectWidthsForDivID( aDivID)
// Hack for the problem (occurs in STD mode), that border widths of SELECT and INPUT are 
// used differently. The width of a SELECT is reduced by border size, while INPUT is not.
// See also: problem described in Bug #1102
{
  var div = findLayer( document, aDivID);
  if( null != div)
  {
    var i, obj;

    // alle INPUTs einsammeln und die Breite bestimmen
    var nWidth = 0;
    var emlL = GetChildsByTagName( div, "INPUT");
    for( i = 0;  i < emlL.length;  ++i)
    {
      obj = emlL[i];
      nWidth = Math.max( nWidth, obj.offsetWidth);  // Checkboxen und Radiobuttons sind idR. viel kleiner
    }

    // FIX: Wenn kein EDIT da ist, bekommen wir hier 0 raus 
    // In diesem Fall stoert es aber auch nicht, weil ja kein EDIT da ist!
    if( 0 >= nWidth)
      return;
    
    // alle SELECTs einsammeln und die korrekte Breite ueberhelfen
    var emlL = GetChildsByTagName( div, "SELECT");
    for( i = 0;  i < emlL.length;  ++i)
    {
      obj = emlL[i];
      obj.style.width = ValidCssValue( nWidth);  // border-with korrekt setzen, ist hier um border-width zu klein
    }
  }
}


//--- Visual Input Error Markings (tm) ----------------------------------


var g_ctlErrorL = new Array();


function SetErrorCtl( aCtl, aError)
// markiere das aktuelle Control als fehlerhaft, Control wird gemerkt
// aError ist optional, default ist g_lggNeedInput
{
  AddCssClass( aCtl, "checkfailed"); // Fehlerstelle optisch kennzeichnen
  
  var obj = new Object();
  obj.ctl    = aCtl;
  obj.sError = ("string" == typeof aError)  ?  aError  :  "";
  AddToArray( g_ctlErrorL, obj);
}    


function AnyErrorCtls()
// liefert true, wenn mindestens ein Ctl als fehlerhaft markiert wurde
{
  return (0 < g_ctlErrorL.length);
}    


function FocusErrorCtl()
// Fokussiere das erste fehlerhafte Control, gib Fehlermeldung aus
// Liefert true, wenn Fehler vorliegen, false wenn nicht
{
  // es liegt kein Fehlerzustand vor
  if( 0 >= g_ctlErrorL.length)
    return false;
  
  var obj  = g_ctlErrorL[0];
  var sMsg = ("" != obj.sError)  ?   obj.sError  :   g_lggNeedInput;
  InfoBox( sMsg, false);
  obj.ctl.focus();
  return true;
}


function ResetErrorCtl()
// Loescht alle Fehlermarken und setzt g_ctlError zurueck
{
  // Arrray zuruecksetzen
  var ctlL = g_ctlErrorL;
  g_ctlErrorL = new Array();
  
  // Fehlermarken entfernen
  for( var i = 0;  i < ctlL.length;  ++i)
    RemoveCssClass( ctlL[i].ctl, "checkfailed");       
}




//--- Dateidownload -----------------------------------


function DownloadFile( sName, sTitle, sTarget )
// Oeffnet ein neues Fenster zum runterladen einer Datei mit Alternativlink
// sName   = URL der Datei
// sTitle  = Fenstertitel (optional) 
// sTarget = Zielfenster (optional)
{
  if ( (sName) && ("" != sName ) )
  {
    var fm = document.DOWNLOADFORM;
    
    if ( (null == fm) || ("undefined" == typeof fm) )
    {  
      ErrorBox( "'DOWNLOADFORM' not found. No 'incDownloadData.htm' include?");
      return false; 
    } 
    fm.TP__FILENAME.value = sName;
    fm.TP__TITLE.value    = (sTitle) ? sTitle : "";    
    fm.target = (sTarget) ? sTarget : "_blank"; // Default: immer neue Seite
    fm.submit();
    return true;
  } 
  return false;    
}


function GetNavBackUrl()
// gibt die url des letzten elementes der navigationsliste zurueck. 
// Das geht nur wenn auch BodyTop eingebunden wurd, d.h. ein hauptfenster (keine ifmXXX)
// NavLink0 = aktuelle seite
// NavLink1 = vorherige seite
// ...
{
  /*
  var LastLink = null;
  var RunLink  = null;
  var cMAXLinks   = 10;
  
  for( var i = 0; i < cMAXLinks; ++i) 
  {
    RunLink = document.getElementById("NavLink" + i.toString() );
    if (RunLink)
      LastLink = RunLink;
    else
      break;  
  } 
  */
  var LastLink = document.getElementById("NavLink1");
  
  if ( (LastLink) && ("undefined" != typeof LastLink.href) )
    return LastLink.href;
  else
    return "";  
}


// EOF

