
var EPCM = {
 
 OTHER   : 0, 
 MSIE    : 1,
 NETSCAPE: 2,
 MOZILLA : 2, 
 OPERA   : 3,
 NOKIA   : 4,
 UP      : 5,
 ERICSSON: 6,
 MSPIE   : 7,
 PALM    : 8,   
    
 OTHER_PLATFORM : 0,
 NT_PLATFORM    : 1,
 WIN_PLATFORM   : 2,
 MAC_PLATFORM   : 3,
 LINUX_PLATFORM : 4, 
 WAP_PLATFORM   : 5,
 PDA_PLATFORM   : 6,
  
  _private: {
    id: "EPCM",
    envRef:     window, 
    version:    null, 
    level:      null, 
    instanceId: null, 
    uaType:     null, 
    uaVersion:  null, 
    uaPlatform: null,
    domainFull: document.domain,
    compList:   null,
    dbgException: false,
    implDB      :null,
    implDSM     :null,
    dirty:      false,
    uipmode:    null,
    uipWinFeatures: null,
    uipPortalPath: null
  }   
}


EPCM.init = function( cfg ){

 var priv = this._private;
 if( priv.version != null ) return;

//  Relaxing of origin : handled directly in EPCM-constructor !!
//  priv.domainFull = 
 
// Level downgrade: Fallback to pure JavaScript when client switched Java OFF
 if (cfg.Level>=2 && (!navigator.javaEnabled())){
   cfg.Level=1;	
 } 
 
// store parameters of EPCM instance
 priv.version    = cfg.Version;
 priv.level      = cfg.Level;
 priv.instanceId = cfg.InstanceId;
 priv.uaType     = cfg.UAType;
 priv.uaVersion  = cfg.UAVersion;
 priv.uaPlatform = cfg.UAPlatform;
 
 priv.compList   = new Array();

// hook databag implementation and logoff envent
 priv.implDB  = (cfg.Level<2) ? this.DB1  : this.DB2;
 EPCM.subscribeEvent("urn:com.sapportals.portal:user","logoff",EPCM._private.clearClientDataBag );

// initialize WindowId but beeing Relaxed
 if(document.domain == EPCM.getRelaxedDomain()){
    var WID = this.getUniqueWindowId(); 
 }   
 
// initialize UIPMode for Navigation, Features for Window.open  and PortalPath for 
 priv.uipmode        = cfg.UIPMode; 
 priv.uipWinFeatures = cfg.UIPWinFeatures; 
 priv.uipPortalPath  = cfg.UIPPortalPath;  
 
// initialize debugging flags (Exception in Debugging) 
 priv.dbgException   = cfg.DBGException
 
}




EPCM.getUAType = function() {
  return this._private.uaType;
}



EPCM.getUAVersion = function() {
  return this._private.uaVersion;
}


EPCM.getUAPlatform = function() {
  return this._private.uaPlatform;
}



EPCM.getVersion = function() {
  return this._private.version;
}


EPCM.getLevel = function() {
  return this._private.level;
}


EPCM.getInstanceId = function() {
  return this._private.instanceId;
}

EPCM.getUniqueWindowId = function() {
  try{
    if( (typeof(top.name ) != "string") || (top.name.length == 0) ){
       top.name="WID"+(new Date()).getTime();
    }
    return top.name;
  }catch (ex) {
    return null;
  }
}


EPCM.getComponentById = function( id ) {
  return this._private.compList[id];
}





EPCM.relaxDocumentDomain = function(){
    var newDomain = this.getRelaxedDomain();
    if( newDomain != document.domain ){
      document.domain = newDomain; 
    }
}


EPCM.getNotRelaxedDomain = function(){
 return this._private.domainFull;
}


EPCM.getRelaxedDomain = function(){
 return this.getRelaxed(this._private.domainFull); 
}


EPCM.getRelaxed = function( input ){

 if (input.search(/^\d+\.\d+\.\d+\.\d+$/) >=0 ){
  return input; 
 }
 var lnDotPos = input.indexOf( "." );
 return (lnDotPos >= 0) ?  input.substr( lnDotPos + 1 ) : input;

}






EPCM.setDirty = function ( val ){
   this._private.dirty = ( val == true );
}


EPCM.getDirty = function( ){
  return this._private.dirty;	
}



EPCM.getGlobalDirty = function( ){

  var result = false;
  switch(this._private.uipmode){

    case "0":  // UIP_MODE_UNDEFINED   
    case "1":  // UIP_MODE_NEWWIN

      // get all EPCMs object which are reachable
      var laEPCM = this._private.getAdjacentEPCM();

      // iterate over all EPCM objects
      for (var idx = 0; idx < laEPCM.length && !result; idx++) {
         result = result || laEPCM[idx].getDirty();
      } // for
      return result;  

    case "2": // UIP_MODE_DESKTOP
      return false;

    default:  // wrong data
      return false;               
  }     
  return result;
}
       

EPCM.doNavigate = function( target, mode, winfeatures, winname, history){

  // isSubscribed => at least one listener registered to navigation event   
  var isSubscribed  = false;
  var lsEvtId   = 'urn:com.sapportals:navigation&Navigate';
  var lsEvtAll  = 'urn:com.sapportals:navigation&*';

  var laEPCM = this._private.getAdjacentEPCM();
  for (var idx = 0; idx < laEPCM.length; idx++) {
    
    if (laEPCM[idx]._private.eList == null) continue;

    // get array of event handlers for the given event id
    var laListener = laEPCM[idx]._private.eList[lsEvtId];
    if ( laListener != null){
      isSubscribed = true;
      break;
    } 
    laListener = laEPCM[idx]._private.eList[lsEvtAll];
    if ( laListener != null){
      isSubscribed = true;
      break;
    }     
  } 

  // openNewWin => Check where to open new target  
  var openNewWin;
  
  if (mode == null ||  mode == 0){  // Dirty & subscribers controlled
      openNewWin = EPCM.getGlobalDirty() ||  (! isSubscribed);
  
  } else {                          // mode>0 results always new window  
      openNewWin = true;
  } 

  // Trigger the action  
  if(openNewWin){
     if (mode        == null)  mode = 2;   
     if (winfeatures == null)  winfeatures = EPCM._private.uipWinFeatures;
     if (winname     == null)  winname = "";

     if (isSubscribed && (mode != 2)){      
         // handled by TLN 
         EPCM.raiseEvent("urn:com.sapportals:navigation", "Navigate", 
                       { target: target, mode:mode, winname: winname, winfeatures: winfeatures } );
         return false;  
  
     }else{ 
         // handled by own, also mode 2, passing via targetQuery
         var qpos = target.indexOf("?");
         var targetQuery = "?NavigationTarget="
         if(qpos < 1 ){
             targetQuery += escape(target);
         }else{
             targetQuery += escape(target.substring(0,qpos)) + "&" + target.substr(qpos+1);
         }  

         // handled by own, also mode 2 !
         window.open( EPCM._private.uipPortalPath + targetQuery, winname, winfeatures);
         return false;  
     }    
  } else {
         //history tracking
         // 0 - for tracking with duplication
         // 1 - track with no duplications
         // 2 - do not track

		 historyStr = "HistoryMode=";
		 var qpos = target.indexOf("?");
		 if(qpos == -1)
			 target = target+"?"+historyStr;
		 else
			 target = target+"&"+historyStr;

         if (history == "undefined" || history == "0" || history == null)
         {
			target = target + "0";
         }
         else if (history == "1")
         {
			target = target + "1";
         }
         else if (history == "2")
         {
         	// no tracking
			target = target + "2";
         }
         // handled by TLN
         EPCM.raiseEvent('urn:com.sapportals:navigation','Navigate', target);
         return false;   
  }

}

EPCM.doObjBasedNavigate = function( systemAlias, businessObjName, objValue, operation ){
	EPCM.raiseEvent('urn:com.sapportals:navigation','ObjBasedNavigate', {systemAlias: systemAlias, businessObjName: businessObjName, objValue: objValue, operation: operation});
}




EPCM.storeClientData = function(pUrn, pName, pValue){
 EPCM._private.implDB.storeClientData(pUrn, pName, pValue); 
}


EPCM.loadClientData = function(pUrn, pName){
  return EPCM._private.implDB.loadClientData(pUrn, pName);
}


EPCM.deleteClientData = function(pUrn, pName){
  EPCM._private.implDB.deleteClientData(pUrn, pName);
}


EPCM._private.clearClientDataBag = function(){
  EPCM._private.implDB.clearClientDataBag();
}


EPCM._private.printClientDataBag = function(){
  EPCM._private.implDB.printClientDataBag(); 
}



EPCM.DB1 = new Object;

EPCM.DB1.MCOOKIE_PREFIX = "SAPPORTALSDB";
EPCM.DB1.MCOOKIE_PARTS  = 10;
EPCM.DB1.MCOOKIE_SPLIT  = 4000;

EPCM.DB1.MSG_TOTAL_LIMIT_EXCEEDED = "Error: Client Databag (Total data limit exceeded)";
EPCM.DB1.MSG_LIMIT_EXCEEDED       = "Error: Client Databag (Single data limit exceeded)";
EPCM.DB1.MSG_WRONG_TYPE           = "Error: Client Databag (Unsupported data type)";

EPCM.DB1.getHashName = function(pUrn, pName){
  return "" + pUrn + "&" + pName; 
}

// Cookie manipulation (move into _private ??
EPCM.DB1.cookieParam = function( name, value ){
  	return (value != null)? name + "=" + value + ";": "";
}

EPCM.DB1.setCookie = function(name, value, expires, path, domain, secure){

  if ( (name != null)	&& (name != "") ) {
    if (value == null) value = "";
       document.cookie = this.cookieParam( name, escape( value ) ) + 
                         this.cookieParam( "expires", expires ) +
                         this.cookieParam( "path", path ) +
                         this.cookieParam( "domain", domain ) +
                         ( (secure == true)? "secure": "" );
    }
}

EPCM.DB1.getCookieArray = function(){
  var laResult= new Array();
  
  if (document.cookie != "") {
    var laCookieList = document.cookie.split( "; " );

	for (var i = 0; i < laCookieList.length; i++) {
      var lsNameValue = laCookieList[i].split( "=" );
      switch (lsNameValue.length) {
       case 1:  laResult[unescape( lsNameValue[0] )] = "";
                break;
       case 2:  laResult[unescape( lsNameValue[0] )] = unescape( lsNameValue[1] );
                break;
       default: break;  
      }
    }
  }
  return laResult;
}

EPCM.DB1.getCookie = function(name){
  var lsCookie = this.getCookieArray()[name];
  if ( lsCookie == "deleted" ) lsCookie = null;
  return lsCookie;
}

EPCM.DB1.deleteCookie = function( name, path, domain ){
 var loPast = new Date();
 loPast.setYear( 1971 );
 this.setCookie( name, "deleted", loPast.toGMTString(), path, domain );
}

// -----------------------------------------------------------------------
EPCM.DB1.getMultiCookieDomain = function(){
   // Other browsers allows cross domain access !! 
     return (document.domain.indexOf(".")<0) ? null : document.domain;
}

EPCM.DB1.setMultiCookie = function(parts){
  
   for(var i = 0; i< this.MCOOKIE_PARTS; i++){
     var lsName   = "" + this.MCOOKIE_PREFIX + i;
   
     if (i < parts.length){
       // something must be stored
       this.setCookie(lsName, parts[i], null, "/", this.getMultiCookieDomain() );
     } else {
       // nothing to store
       this.deleteCookie(lsName, "/", this.getMultiCookieDomain() );
     }
   } //for
}

EPCM.DB1.getMultiCookie = function(){
  var laCookies = this.getCookieArray();
  var lsResult  = ""; 

  for(var i = 0; i< this.MCOOKIE_PARTS; i++){
    var lsName   = "" + this.MCOOKIE_PREFIX + i;
    var lsCookie = laCookies[lsName];
    if (lsCookie != null && lsCookie != "" && lsCookie !="deleted"){
       var lsSepar = (lsResult.length>0)? "; " : "";
       lsResult += lsSepar+lsCookie;
    }
  } 
  return lsResult;
}

EPCM.DB1.clearMultiCookie = function(){

  for(var i = 0; i< this.MCOOKIE_PARTS; i++){
    var lsName   = "" + this.MCOOKIE_PREFIX + i;
    this.deleteCookie(lsName, "/", this.getMultiCookieDomain());
  } 
}

EPCM.DB1.serializeData = function( dataList ){
  var lsString = "";
  var lsSepar;
  
  for( var key in dataList ){
    lsSepar   = (lsString.length >0)? "; " : "";
    if (dataList[key]!=null){
      lsString += lsSepar + escape(key) + "=" + escape(dataList[key]) 
    }  
  }
  return lsString;
}

EPCM.DB1.serializeDataParts = function( dataList ){
  var lsSepar    = "; "
  var lsSeparEsc = escape(lsSepar);
  
  var laParts    = new Array();
  var laPartsEsc = new Array() 

  var lsElem;
  var lsElemEsc;
  var isDistributed;
  
  // Process the optimal distribution into the minimum of parts
  for( var key in dataList ){
    if(dataList[key]==null){
      continue;
    }
    lsElem    = escape(key) + "=" + escape(dataList[key]);
    lsElemEsc = escape(lsElem);
    xlen = lsElemEsc.length;
    isDistributed = false;
     
    for(var i=0; i<laPartsEsc.length;i++){
      if (( laPartsEsc[i].length + xlen ) < this.MCOOKIE_SPLIT){
        laParts[i]    += ((laParts[i].length>0)    ? lsSepar    : "" ) + lsElem;
        laPartsEsc[i] += ((laPartsEsc[i].length>0) ? lsSeparEsc : "" ) + lsElemEsc;
        isDistributed = true;
        break;     
      }
    }  
    if (! isDistributed){
      if (xlen < this.MCOOKIE_SPLIT){
        laParts[i]    = lsElem;
        laPartsEsc[i] = lsElemEsc;
      }else{
        alert(this.MSG_LIMIT_EXCEEDED); 
      }  
    }
  }
  if (laParts.length > this.MCOOKIE_PARTS){
    alert(this.MSG_TOTAL_LIMIT_EXCEEDED);
    laParts.length = this.MCOOKIE_PARTS;
  }   
  return laParts;
}

EPCM.DB1.deserializeData = function( data ){
  var laResult = new Array();

  if ( data!=null && data != "") {
    var laDataList	= data.split( "; " );
	
    for (var i = 0; i < laDataList.length; i++) {
      var lsNameValue = laDataList[i].split( "=" );
      switch (lsNameValue.length) {
       case 1:
         laResult[unescape( lsNameValue[0] )] = "";
         break;
       case 2:
         laResult[unescape( lsNameValue[0] )] = unescape( lsNameValue[1] );
         break;
       default:
         break;  
      }
    }
  }
  return laResult;
}

// --------------------------------------------------------------------------

EPCM.DB1.storeClientData = function(pUrn, pName, pValue){

  var lsType = typeof pValue;

  if (pValue != null){
    if (lsType == "number" || lsType == "string" || lsType =="boolean"){
      pValue = "" + pValue;	
    } else {
      alert(this.MSG_WRONG_TYPE);
      return; 
    }
  } 
  var lsDatabag  = this.getMultiCookie();
  var loArray    = this.deserializeData(lsDatabag);
  
  var xName      = this.getHashName(pUrn,pName);    
  loArray[xName] = pValue;
  
  var lsDatabagParts = this.serializeDataParts(loArray);
  this.setMultiCookie(lsDatabagParts);
}

EPCM.DB1.loadClientData = function(pUrn, pName){
  
  var lsDatabag = this.getMultiCookie();
  var loArray   = this.deserializeData(lsDatabag);
 
  var xName     = this.getHashName(pUrn,pName);  
  return loArray[xName];
}

EPCM.DB1.deleteClientData = function(pUrn, pName){
  this.storeClientData(pUrn,pName,null);
}

EPCM.DB1.clearClientDataBag = function(){
 this.clearMultiCookie();
}

EPCM.DB1.printClientDataBag = function(){
 alert("document.cookie(" +document.cookie.length + ")= " + document.cookie );
}




EPCM.DB2 = new Object;

EPCM.DB2.storeClientData = function(pUrn, pName, pValue){
 var loApplet = EPCM._private.getApplet();

 if (pValue == null){
   loApplet.getDataBag().removeObject( new String(pUrn), new String(pName));
 } else {

   var lsType = typeof pValue;

   if (lsType == "number") {
     loApplet.getDataBag().putNumber (new String(pUrn), new String(pName), pValue);
   } else if (lsType == "string"){
     loApplet.getDataBag().putString (new String(pUrn), new String(pName), pValue);
   } else if (lsType == "boolean"){
     loApplet.getDataBag().putBoolean(new String(pUrn), new String(pName), pValue);
   } else {
     loApplet.getDataBag().putObject (new String(pUrn), new String(pName), pValue);
   }
 }
}

EPCM.DB2.loadClientData = function(pUrn, pName){
 var loApplet = EPCM._private.getApplet();
 var lsType   = loApplet.getDataBag().getObjectType(new String(pUrn), new String(pName));
 var loResult = loApplet.getDataBag().getObject    (new String(pUrn), new String(pName));
 var Result   = null;

 if        (lsType == "class java.lang.Double" ){
   Result = parseFloat(loResult);
 } else if (lsType == "class java.lang.Boolean"){
   Result = loResult == "true";
 } else if (lsType == "class java.lang.String"){
   Result = "" + loResult;
 } else {
   Result = loResult;
 }
 return Result;
}

EPCM.DB2.deleteClientData = function(pUrn, pName){
 var loApplet = EPCM._private.getApplet();
 loApplet.getDataBag().removeObject( new String(pUrn), new String(pName));
}

EPCM.DB2.clearClientDataBag = function(){
 var loApplet = EPCM._private.getApplet();
 loApplet.getDataBag().removeAllObjects();
}

EPCM.DB2.printClientDataBag = function(){
 var loApplet = EPCM._private.getApplet();
 loApplet.getDataBag().showContent(null);
}





EPCM._private.getHTTP = function(pathURL, queryParam){
 if ( EPCM.getLevel()<2 ) return null;
 var loApplet = this.getApplet();
 var lsType   = loApplet.getDataChannel().getHTTP(new String(pathURL), new String(queryParam));
 return lsType;
}


EPCM._private.postHTTP = function(pathURL, queryParam){
 if ( EPCM.getLevel()<2 ) return null;
 var loApplet = this.getApplet();
 var lsType   = loApplet.getDataChannel().postHTTP(new String(pathURL), new String(queryParam));
 return lsType;
}




EPCM.EventObject = function(eventNamespace, eventName, dataObject, sourceId ){
  this.eventNamespace = eventNamespace;
  this.eventName      = eventName;
  this.dataObject     = dataObject;
  this.sourceId       = sourceId;
}

EPCM._private.eGlobHistory   = new Array();     // Global Evenging History Table  
EPCM._private.eLocHistory    = new Array();     // Local Evenging History Table


EPCM._private.getEvtGlobTable = function(){
   var topEPCM = this.getTopmostEPCM(); 
   return topEPCM._private.eGlobHistory;
}
EPCM._private.getEvtLocTable = function(){
   return this.eLocHistory;
}
EPCM._private.optimizeEvtGlobTable = function(){
   var topEPCM = this.getTopmostEPCM(); 
   var oldTab = topEPCM._private.eGlobHistory; 
   var newTab = new Array();

   var activeKeys = ""; 
   var allEPCM = this.getAdjacentEPCM();
   for (var i = 0; i< allEPCM.length; i++){
      activeKeys += allEPCM[i].getInstanceId() + ", ";
   }
   for(var tabKey in oldTab){ 
     if( activeKeys.indexOf(oldTab[tabKey]) >=0){
        newTab[tabKey] = oldTab[tabKey];
     }
   }
   topEPCM._private.eGlobHistory = newTab; 
}






EPCM.subscribeEvent = function( nameSpace, eventName, handlerRef, methodName ){
  // a) define FunctionListener constructor
  function FunctionListener( fref ) {
    this.fref = fref;
    this.call = function ( data ) { return this.fref( data ); }
  }
  // b1) define MethodListener constructor
  function MethodListener( oref, mname ) {
    this.oref   = oref;
    this.method = mname;
    this.call   = function ( data ) { return this.oref[this.method]( data ); }
  }
  // b2) define FrameMethodListener constructor
  function FrameMethodListener ( fname, mname) {
    this.frame  = fname
    this.method = mname;
    this.call   = function ( data ) { return window.frames[this.frame][this.method]( data ); } 	
  } 

  function isFrameMethodDuplicity(olist, fname, mname){
     for(var i=0; i< olist.length; i++){
       var xobj = olist[i];
       if (   xobj.frame != null  && xobj.method != null 
           && xobj.frame == fname && xobj.method == mname ){
         return true   
       }
     }
     return false;
  } 

  // concatenate name space and event name to single event id
  // ('&' is forbidden inside URNs)
  var lsEvtId = nameSpace + "&" + eventName;

  var loSys   = this._private;

  // create subscription list at the first time
  if (loSys.eList == null) loSys.eList = new Array();
  if (loSys.eList[lsEvtId] == null) loSys.eList[lsEvtId] = new Array();
  var laListener = loSys.eList[lsEvtId];

  var eListener = null;
  // check, if variant a) ,b1) or b2)

  if ( ("function" == typeof handlerRef) && (arguments.length == 3) ) {
    // a) create new function event listener
    eListener = new FunctionListener( handlerRef );

  } else if ( ("object" == typeof handlerRef) && (arguments.length == 4) ) {
    // create new frame-method or method listener
    for(var i=0; i<frames.length;i++){
     if (handlerRef == frames[i]){
       // b1) create frame-method listener (if valid and no duplicity !)  
       if (isFrameMethodDuplicity(laListener,frames[i].name, methodName )) return;
       eListener = new FrameMethodListener(frames[i].name, methodName);	          	
       break; 
     }
    } 
    if (eListener == null){
      // b2) create new method event listener
      eListener = new MethodListener( handlerRef, methodName );
    } 
  } else {
    var polluter = caller;
    alert( "EPCM ERROR\n" +
           "\tIllegal argument type in method EPCM.subscribeEvent()" +
           "\tThe function was called from " + polluter.toString() );
  }
  // add new event listener to subscription list
  laListener[laListener.length] = eListener;

}




EPCM.subscribeEventReliable = function( nameSpace, eventName, handlerRef, methodName ){

  // a) define FunctionListener constructor
  function FunctionListener( fref ) {
    this.fref = fref;
    this.call = function ( data ) { return this.fref( data ); }
  }
  // b1) define MethodListener constructor
  function MethodListener( oref, mname ) {
    this.oref   = oref;
    this.method = mname;
    this.call   = function ( data ) { return this.oref[this.method]( data ); }
  }
  // b2) define FrameMethodListener constructor
  function FrameMethodListener ( fname, mname) {
    this.frame  = fname
    this.method = mname;
    this.call   = function ( data ) { return window.frames[this.frame][this.method]( data ); } 	
  } 

  function isFrameMethodDuplicity(olist, fname, mname){
     for(var i=0; i< olist.length; i++){
       var xobj = olist[i];
       if (   xobj.frame != null  && xobj.method != null 
           && xobj.frame == fname && xobj.method == mname ){
         return true   
       }
     }
     return false;
  } 

  // concatenate name space and event name to single event id
  // ('&' is forbidden inside URNs)
  var lsEvtId = nameSpace + "&" + eventName;

  var loSys   = this._private;

  // create subscription list at the first time
  if (loSys.eList == null) loSys.eList = new Array();
  if (loSys.eList[lsEvtId] == null) loSys.eList[lsEvtId] = new Array();
  var laListener = loSys.eList[lsEvtId];

  var eListener = null;
  // check, if variant a) ,b1) or b2)

  if ( ("function" == typeof handlerRef) && (arguments.length == 3) ) {
    // a) create new function event listener
    eListener = new FunctionListener( handlerRef );

  } else if ( ("object" == typeof handlerRef) && (arguments.length == 4) ) {
    // create new frame-method or method listener
    for(var i=0; i<frames.length;i++){
     if (handlerRef == frames[i]){
       // b1) create frame-method listener (if valid and no duplicity !)  
       if (isFrameMethodDuplicity(laListener,frames[i].name, methodName )) return;
       eListener = new FrameMethodListener(frames[i].name, methodName);	          	
       break; 
     }
    } 
    if (eListener == null){
      // b2) create new method event listener
      eListener = new MethodListener( handlerRef, methodName );
    } 
  } else {
    var polluter = caller;
    alert( "EPCM ERROR\n" +
           "\tIllegal argument type in method EPCM.subscribeEventReliable()" +
           "\tThe function was called from " + polluter.toString() );
  }
  // add new event listener to subscription list
  laListener[laListener.length] = eListener;


// ----------------

   var subscriberKey       = nameSpace + "&" + eventName;
   var subscriberKeyPrefix = nameSpace + "&";

   // clean up invalid entries in global table
   this._private.optimizeEvtGlobTable();

   // build decode decode table over active EPCMs
   var decodeTab = new Array();
   var allEPCM = this._private.getAdjacentEPCM();
   for (var i = 0; i< allEPCM.length; i++){
      decodeTab[allEPCM[i].getInstanceId()] = allEPCM[i];
   }

   // Access global event table
   var globTab = this._private.getEvtGlobTable();
   
   for(var globTabKey in globTab){

     // check all entries in global Tab which match to the given pattern     
     if(eventName == "*"){
        if (globTabKey.indexOf(subscriberKeyPrefix) != 0)  continue;
     }else{
        if (globTabKey != subscriberKey)  continue;
     }
     
     // Find sender EPCM
     var senderEPCM = decodeTab[globTab[globTabKey]];
     if (senderEPCM != null){
        var locTabEntry = senderEPCM._private.getEvtLocTable()[globTabKey];
        if (locTabEntry !=null){
           var locEventObject = locTabEntry;
           try {
             // try to call registerd event handler and pass dataObject
             eListener.call( locEventObject );
           } catch( e ) {
               if (EPCM._private.dbgException){
                 if(!confirm("Exception in EPCM.raiseEvent occured.\nContinue ?")) throw(e);
               }
           } 


      	} //if locTabEntry
     } // ifSender
     
   }
}


EPCM.raiseEvent = function( nameSpace, eventName, dataObject, sourceId ) {

  function distribute( consumers, eventObject ) {
    for (var idx in consumers) {
      // get event handler (should be function or object)
      var eListener = consumers[idx];

//    encapsulate event handler call into try-catch block for JS13
      try {
        // try to call registerd event handler and pass dataObject
        eListener.call( eventObject );
      } catch( e ) {
          /* @todo@ error in event handler */ 
          if (EPCM._private.dbgException){
            if(!confirm("Exception in EPCM.raiseEvent occured.\nContinue ?")) throw(e);
          }
      } 
//    no try-catch for older browsers
    } // for
  } // distribute

  // concatenate name space and event name to single event id
  // ('&' is forbidden inside URNs)
  var lsEvtId   = nameSpace + "&" + eventName;
  var lsEvtAll  = nameSpace + "&*";
  var loEvtObj  = new EPCM.EventObject( nameSpace, eventName, dataObject, sourceId );

  // get all EPCMs object which are reachable
  var laEPCM = this._private.getAdjacentEPCM();

  // iterate over all EPCM objects
  for (var idx = 0; idx < laEPCM.length; idx++) {

    if (laEPCM[idx]._private.eList == null) continue;

      // get array of event handlers for the given event id
      var laListener = laEPCM[idx]._private.eList[lsEvtId];
      if ( laListener != null) {
        distribute( laListener, loEvtObj );
      } // if

      // get array of event handlers which are registered to all events
      laListener = laEPCM[idx]._private.eList[lsEvtAll];
      if ( laListener != null) {
        distribute( laListener, loEvtObj );
      } // if
   } // for
   
   
   // store event in Histories with given key
   // add local detail Entry
   this._private.getEvtLocTable()[lsEvtId]= new EPCM.EventObject( nameSpace,
                                                                  eventName,     
                                                                  dataObject,
                                                                  sourceId );
   // add global index Entry
   this._private.getEvtGlobTable()[lsEvtId]= this.getInstanceId();
   
}


EPCM.raiseEventLocal = function( nameSpace, eventName, dataObject, sourceId ) {

  function distribute( consumers, eventObject ) {
    for (var idx in consumers) {
      // get event handler (should be function or object)
      var eListener = consumers[idx];

//    encapsulate event handler call into try-catch block for JS13
      try {
        // try to call registerd event handler and pass dataObject
        eListener.call( eventObject );
      } catch( e ) {
          /* @todo@ error in event handler */ 
          if (EPCM._private.dbgException){
            if(!confirm("Exception in EPCM.raiseEventLocal occured.\nContinue ?")) throw(e);
          }
      }
//    no try-catch for older browsers
    } // for
  } // distribute

  // concatenate name space and event name to single event id
  // ('&' is forbidden inside URNs)
  var lsEvtId   = nameSpace + "&" + eventName;
  var lsEvtAll  = nameSpace + "&*";
  var loEvtObj  = new EPCM.EventObject( nameSpace, eventName, dataObject, sourceId );
  var leList    = this._private.eList;

  if ( leList!= null) {

    // get array of event handlers for the given event id
    var laListener = leList[lsEvtId];
    if ( laListener != null) {
      distribute( laListener, loEvtObj );
    } // if

    // get array of event handlers which are registered to all events
    laListener = leList[lsEvtAll];
    if ( laListener != null) {
      distribute( laListener, loEvtObj );
    } // if
 } // if
}




EPCM.DSM = new Object();



EPCM.DSM.init = function( cfg ){
  
 // hook dsm implementation (always JavaScript) and debugging (level=1 only!)
 EPCM._private.implDSM = EPCM.DSM1;
 EPCM.subscribeEvent("urn:com.sapportals.portal:browser","unload" , EPCM.DSM.terminateAll );
 EPCM.subscribeEvent("urn:com.sapportals.portal:user",   "logoff" , EPCM.DSM.terminateAll );

 if (EPCM.getLevel() == 1){
   var lbDsmDebug = EPCM.loadClientData("urn:com.sapportals.portal:dsm", "debug");  
   EPCM.DSM1.Debug        = (lbDsmDebug != null && lbDsmDebug.indexOf("X") >=0 );
   EPCM.DSM1.PopupReceipt = (lbDsmDebug != null && lbDsmDebug.indexOf("P") >=0 );
 } 

 // initialize  
 EPCM._private.implDSM.init( cfg );  
  
}


EPCM.DSM.processSession = function( si , frameRef ){
 
 EPCM._private.implDSM.log("Client: SessionInfoReceived \r\n" + this.formatSession(si), true );
 this.popupReceipt(si);  
 
 if(si.lastSessCmd=="USR_OPEN" || si.lastSessCmd == null || si.lastSessCmd == ""){
   EPCM._private.implDSM.registerSession(si); 
 }
 if(si.lastSessCmd=="SRV_ERROR" || si.lastSessCmd=="SRV_CLOSE"){
   EPCM._private.implDSM.removeSessionByGUSID(si.GUSID)
   if(si.redirectURL!=null && si.redirectURL!="" ){
      if ( frameRef!=null && si.redirectURL.indexOf("!")>0 && si.redirectURL.indexOf("~")>0 ){
        // it *seems* that this url point to ITS (nobody else uses ! an ~ in url), let the 
        // EPCM and replace only inner IFRAME
        frameRef.location.href = si.redirectURL;  
      } else { 
        // replace the "outer" frame with destroying of EPCM
        location.href=si.redirectURL; 
      } 
   }
 }  
}


EPCM.DSM.notifyMonitor = function(si){
 EPCM.raiseEvent("urn:com.sapportals.portal.epcm.dsm","receiveSessInfo", si);
}


EPCM.DSM.registerSession = function(si){
  EPCM._private.implDSM.registerSession(si);
}  


EPCM.DSM.removeSessionByGUSID = function (GUSID){
  EPCM._private.implDSM.removeSessionByGUSID(GUSID);
}


EPCM.DSM.terminateAll = function(){
  EPCM._private.implDSM.terminateAll();
}


EPCM.DSM.terminateByGUSID = function(GUSID){
  EPCM._private.implDSM.terminateByGUSID(GUSID);
}


EPCM.DSM.getAllToArray = function(){
  return EPCM._private.implDSM.getAllToArray();
}


EPCM.DSM.getSize = function(){
 return EPCM._private.implDSM.getSize();
}


EPCM.DSM.log = function( logString, isDebugControlled ){
 var isDC = ( isDebugControlled != null ) ?  isDebugControlled : true;
 return EPCM._private.implDSM.log( logString, isDC );
}

EPCM.DSM.popupReceipt = function(si){
  if (EPCM._private.implDSM.PopupReceipt){
     alert("Session Info Received:" + "\n\n" + this.formatSession(si));
  } 
}
    
    
    
    
    

EPCM.DSM.formatSession = function( si ){
 var result = "";
 for(var item in si ){
    result += item + "=" + si[ item ] + "\r\n";
 }
 return result;
}




EPCM.DSM1 = new Object();

EPCM.DSM1.SessStore = new Array();
EPCM.DSM1.TermString = "";
EPCM.DSM1.TerminatorUrl = null;
EPCM.DSM1.FormName = "";
EPCM.DSM1.Debug=false;
EPCM.DSM1.PopupReceipt=false;
EPCM.DSM1.GoViaForm=true;
EPCM.DSM1.WinParamsHidden = "height=100,width=200,resizable,left=20042,screenX=20042,top=0,screenY=0";
EPCM.DSM1.WinParamsDebug  = "height=400,width=600,resizable,menubar,scrolbars";

EPCM.DSM1.init = function( cfg ){
 this.TerminatorUrl = cfg.TerminatorURL;
 this.FormName      = cfg.DSMFormGuid; 
}

EPCM.DSM1.registerSession = function(si){
 var loSi = this.copySessInfo(si); 
 this.SessStore[loSi.GUSID] = loSi; 
 this.TermString = this.computeTermString();
}

EPCM.DSM1.removeSessionByGUSID = function (GUSID){
  this.SessStore[GUSID] = null;
  this.TermString = this.computeTermString();
}

EPCM.DSM1.terminateAll = function(){
 this.sendTermString(); 
 this.TermString="";
 this.SessStore=new Array();   
}

EPCM.DSM1.terminateByGUSID = function(GUSID){
 if (this.SessStore[GUSID] == null ) return;
 this.TermString = escape(this.computeKillCmd(this.SessStore[GUSID]));
 this.sendTermString(); 
 this.removeSessionByGUSID(GUSID);
}

EPCM.DSM1.getAllToArray = function(){
  loArr = new Array();
  for(var elem in this.SessStore){
    if (this.SessStore[elem] != null){
      loArr[elem] = this.copySessInfo(this.SessStore[elem]); 	
    }
  }
  return loArr;
}

EPCM.DSM1.getSize = function(){
  var cnt=0;
  for(var idx in this.SessStore){
    if (this.SessStore[idx] != null) cnt++;
  }
  return cnt;
}

EPCM.DSM1.copySessInfo = function(si){
 var loSi = new Object(); 
 loSi.protocolVersion = ((si.protocolVersion)? new String(si.protocolVersion) : "");
 loSi.GUSID           = ((si.GUSID)          ? new String(si.GUSID)           : "");
 loSi.sessUrl         = ((si.sessUrl)        ? new String(si.sessUrl)         : "");
 loSi.lastSessCmd     = ((si.lastSessCmd)    ? new String(si.lastSessCmd)     : "");
 loSi.redirectURL     = ((si.redirectURL)    ? new String(si.redirectURL)     : "");
 loSi.dTimeout        = ((si.dTimeout)       ? new String(si.dTimeout)        : "");
 loSi.label           = ((si.label)          ? new String(si.label)           : "");
 return loSi;
}

EPCM.DSM1.computeKillCmd = function(si){
 var url =  si.sessUrl;
 var sep =  (url.indexOf("?")>=0) ? "&" : "?";  
 return (url + sep + "~SAPSessionCmd=USR_ABORT&SAPWP_ACTIVE=1");
} 	

EPCM.DSM1.computeTermString = function(){
 var collector = "";
 var separ     = "";
 for(var i in this.SessStore){
   if(this.SessStore[i] == null) continue;
   separ = (collector.length>0) ? "&" : "";
   collector += separ + escape(this.computeKillCmd(this.SessStore[i]));  
 }
 return collector;
} 	

EPCM.DSM1.sendTermString = function(){
 if(this.TermString == null || this.TermString == "") return;
 if(this.GoViaForm){ 
   this.sendTermStringViaForm();
 }else{
   this.sendTermStringViaWindow();
 }  
}  

EPCM.DSM1.sendTermStringViaForm = function(){

 var myWinParams;
 var myTarget = "Window"+this.FormName;
 var myForm   = document.forms[this.FormName]; 
 
 myForm.method = "POST";
 myForm.action = this.TerminatorUrl;
 myForm.target = myTarget;

 myForm.TermString.value= this.TermString; 

 if (this.Debug){
   myForm.Autoclose.value = "";
   myForm.LogTerm.value = "true";
   myWinParams = this.WinParamsDebug;
 }else{
   myForm.Autoclose.value = "1000";
   myForm.LogTerm.value = "false";
   myWinParams = this.WinParamsHidden; 
 } 
 window.open("about:blank",myTarget, myWinParams);
 window.focus();
 myForm.submit();
}

EPCM.DSM1.sendTermStringViaWindow = function(){

 var myURL,myWinParams;   
 
 if (this.Debug){
    myURL       = this.TerminatorUrl+"?LogTerm=true&TermString="+escape(this.TermString);
    myWinParams = this.WinParamsDebug;     
 }else{
    myURL       = this.TerminatorUrl+"?Autoclose=1000&TermString="+escape(this.TermString);
    myWinParams = this.WinParamsHidden; 
 } 
 window.open(myURL,"_blank", myWinParams);
 window.focus();
}

EPCM.DSM1.log = function( logString, isDebugControlled ){
  if (logString == null) return;
  if (isDebugControlled && (! this.Debug )) return;
  (new Image).src = this.TerminatorUrl + "?LogString=" + escape(logString);
}




EPCM.DSM2 = new Object();
EPCM.DSM2.PopupReceipt=false;

EPCM.DSM2.getApplet = function(){
  return EPCM._private.getApplet();
}

EPCM.DSM2.init = function( cfg ){}

EPCM.DSM2.registerSession = function(si){
 if ( EPCM.getLevel()<2 ) return;
 var loApplet = this.getApplet();
   
 loApplet.getSessionManager().registerSession(
  "",
  (si.protocolVersion) ? new String(si.protocolVersion) : "",
  (si.GUSID)           ? new String(si.GUSID)           : "",
  (si.sessUrl)         ? new String(si.sessUrl)         : "",
  (si.lastSessCmd)     ? new String(si.lastSessCmd)     : "",
  (si.redirectURL)     ? new String(si.redirectURL)     : "",
  (si.dTimeout)        ? new String(si.dTimeout)        : "",
  (si.label)           ? new String(si.label)           : ""
 );
}	

EPCM.DSM2.removeSessionByGUSID = function (GUSID){
 if ( EPCM.getLevel()<2 ) return;
 var loApplet = this.getApplet();
 loApplet.getSessionManager().removeSessionByGUSID ("", GUSID );
}

EPCM.DSM2.terminateAll = function(){
 if ( EPCM.getLevel()<2 ) return;
 var loApplet = this.getApplet();
 loApplet.getSessionManager().terminateAll("");
}	

EPCM.DSM2.terminateByGUSID = function(GUSID){
 if ( EPCM.getLevel()<2 ) return;
 var loApplet = this.getApplet();
 loApplet.getSessionManager().terminateByGUSID ("", GUSID );
}	

EPCM.DSM2.getAllToArray = function(){
 if ( EPCM.getLevel()<2 ) return null;
 var loApplet        = this.getApplet(); 
 var laFinArr        = new Object();
 var lsKeyPairString = loApplet.getSessionManager().getQSKeys("");  
 var laKeyPairs      = this.convertQSToArray(lsKeyPairString);
 var lsPropertyString; 
 var laProperty;        

 for(var i in laKeyPairs){
  lsPropertyString= loApplet.getSessionManager().getQSPropertiesByGUSID("",laKeyPairs[i]);
  laFinArr[laKeyPairs[i]] = this.convertQSToArray(lsPropertyString);
 }
 return laFinArr;
}	

EPCM.DSM2.getSize = function(){
 if ( EPCM.getLevel()<2 ) return 0;
 var loApplet = this.getApplet(); 
 return loApplet.getSessionManager().getSize("");
}

EPCM.DSM2.printStore = function(){
 if ( EPCM.getLevel()<2 ) return;
 var loApplet = this.getApplet(); 
 loApplet.getSessionManager().printStore("");
}

EPCM.DSM2.getQSKeys = function(){
 if ( EPCM.getLevel()<2 ) return null;
 var loApplet = this.getApplet();
 return loApplet.getSessionManager().getQSKeys("");
}
	
EPCM.DSM2.getQSPropertiesByGUSID = function(GUSID){
 if ( EPCM.getLevel()<2 ) return null;
 var loApplet = this.getApplet();
 return loApplet.getSessionManager().getQSPropertiesByGUSID("", GUSID );
}

EPCM.DSM2.convertQSToArray = function(xquery){
 var query  = new String( (xquery.substring(0,1)  == "?") ?  xquery.substring(1) : xquery );
 var pairs  = query.split("&");
 var finArr = new Array();

 for(var i=0; i<pairs.length; i++){
   var pos = pairs[i].indexOf("=");
   if (pos == -1) continue;
     var argname= pairs[i].substring(0,pos);
     var value  = pairs[i].substring(pos+1);
     finArr[argname] = unescape(value);
 }
 return finArr;
}

EPCM.DSM2.log = function( logString, isDebugControlled  ){
  // no logging implemented, use JavaConsole
}




EPCM.adjustHeight = function( force, height ) {
  try {
    var myIFrame = EPCM._private.getContainerElement( window );
    if (myIFrame != null) {

      if (!force && myIFrame.getAttribute( "autoHeight" ) != "true"){
        return false;
      }  
      if (height == null) {
        height = EPCM._private.getDocumentHeight( window );
      }

      if (height > 0) {
      
      	var minAutoHeight = myIFrame.getAttribute("minAutoHeight");
		var maxAutoHeight = myIFrame.getAttribute("maxAutoHeight");

		if((minAutoHeight != "") && (minAutoHeight != null)){
			height=Math.max(height,minAutoHeight);
		}
		if((maxAutoHeight != "") && (maxAutoHeight != null)){
			height=Math.min(height,maxAutoHeight);		
		}      
      
        if (EPCM.getUAType() == EPCM.MSIE) {
          myIFrame.style.pixelHeight = height;
          return true;
        } else if ((EPCM.getUAType() == EPCM.MOZILLA) && (EPCM.getUAVersion() >= 5)) {
          myIFrame.height = height;
          return true;
        }
      }
    }
  } catch( ex ) {
    /* resizing of the container iframe failed */
    return false;
  }
}


EPCM.adjustWidth = function( force, width ) {
  try {
    var myIFrame = EPCM._private.getContainerElement( window );
    if (myIFrame != null) {

      if (!force && myIFrame.getAttribute( "autoWidth" ) != "true") {
        return false;
      }
      if (width == null){
         width = EPCM._private.getDocumentWidth( window );
      }   

      if (width > 0) {
        if (EPCM.getUAType() == EPCM.MSIE) {
          myIFrame.style.pixelWidth = width;
          return true;
        } else if ((EPCM.getUAType() == EPCM.MOZILLA) && (EPCM.getUAVersion() >= 5)) {
          myIFrame.width = width;
          return true;
        }
      }
    }
  } catch( ex ) {
    /* resizing of the container iframe failed */
    return false;
  }
}





EPCM._private.getApplet = function(){
  loApplet = document.applets["_EPCMfactory_"];
  if (loApplet == null){
    alert( "EPCM ERROR\n" +
           "\tApplet _EPCMfactory_ not available" );
  }
  return loApplet;
}




EPCM._private.registerComponent = function( oref, id ){
  if (this.compList[id] == null) {
    this.compList[id] = oref;
  } return oref;
}


EPCM._private.getAdjacentEPCM = function() {
  // find root EPCM and get all child EPCM objects of it.
  var ldTopFrame = this.getTopmostFrame();
  return this.getChildrenEPCM( ldTopFrame );
}


EPCM._private.getTopmostFrame = function(){
  var ldFrame   = window;
  try {
    /* try to walk the frame hierarchy upwards as long as possible */
    while (ldFrame.parent != ldFrame) {
      ldFrame   = ldFrame.parent;
    }
  } catch (ex) { /* ignore, take current frame */ }
  return ldFrame;
}


EPCM._private.getTopmostEPCM = function() {
  var result = EPCM;
  var ldFrame   = window;
  try {
    // go frame hierarchy as long as possible
    while (ldFrame.parent != ldFrame) {
      ldFrame   = ldFrame.parent;
      if (ldFrame.EPCM != null) {
        result = ldFrame.EPCM;
      }
    }
  } catch (ex) { 
      // ignore, take the current EPCM
  }
  return result;
}

    

EPCM._private.getChildrenEPCM = function( froot, paList ) {
  // create EPCM-array on demand
  if (paList == null) paList = new Array();

  // add current frame to result list, if it contains a EPCM object
  if (froot.EPCM != null) paList[paList.length] = froot.EPCM;

  // look for EPCM objects in child frames recursively
  for (var idx = 0; idx < froot.frames.length; idx++) {
    try {
      this.getChildrenEPCM( froot.frames[idx], paList );
    } catch (ex) {
      /* access to frame object denied, stop further search at this sub-frame */
    }
  }
  return paList;
}


EPCM._private.handleBrowserEvent = function ( evt ) {
  // create cross platform access to event object
  //   Mozilla/Netscape gives access via function parameter 'evt'
  //   MSIE gives access via 'window.event' reference
  if (evt == null) evt = window.event;

  // distribute browser events
  EPCM.raiseEventLocal( "urn:com.sapportals.portal:browser", evt.type, evt );
}

EPCM._private.getContainerElement = function( wnd ) {
  var myParent = wnd.parent;
  if (wnd != myParent) {
    // search this frame object inside the parent's frame collection
    var parentFrames = myParent.frames;
    for (var idx = 0; idx < parentFrames.length; idx++) {
      if (parentFrames[idx] == wnd) { // found reference to wnd in parent frame's collection
        // retrieve collection of IFrames
        var eFrames = myParent.document.getElementsByTagName( "IFRAME" );
        if (eFrames.length < idx) return null; // this should never happen!
        return eFrames[idx]; // found container
      }
    }
  }
  return null;
}

EPCM._private.getDocumentHeight = function( wndRef ) {
  var result = 0;
  try {
    if (EPCM.getUAType() == EPCM.MSIE) {
      var loBody = wndRef.document.body;
      result = loBody.scrollHeight +
               loBody.offsetHeight -
               loBody.clientHeight;
    } else if ((EPCM.getUAType() == EPCM.MOZILLA) && (EPCM.getUAVersion() >= 5)) {
      result = wndRef.document.height + 32;
    }
  } catch (e) {
    result = 0;
  }
  return result;
}

EPCM._private.getDocumentWidth = function( wndRef ) {
  var result = 0;
  try {
    if (EPCM.getUAType() == EPCM.MSIE) {
      var loBody = wndRef.document.body;
      result = loBody.scrollWidth +
               loBody.offsetWidth -
               loBody.clientWidth;
    } else if ((EPCM.getUAType() == EPCM.MOZILLA) && (EPCM.getUAVersion() >= 5)) {
      var loBody = wndRef.document.documentElement;
      result = loBody.offsetWidth;
    }
  } catch (e) {
    result = 0;
  }
  return result;
}

// register common browser events for distribution
window.onload   = EPCM._private.handleBrowserEvent;
window.onunload = EPCM._private.handleBrowserEvent;
window.onresize = EPCM._private.handleBrowserEvent;
/*
todo: reactivate for release
document.onclick = EPCM._private.handleBrowserEvent;
window.onfocus = EPCM._private.handleBrowserEvent;
window.onblur = EPCM._private.handleBrowserEvent;
*/

// try to adjust correponding iframe onload.
EPCM.subscribeEvent( "urn:com.sapportals.portal:browser", "load", function() { EPCM.adjustHeight( false ); } );

