/** GSWSession.m - <title>GSWeb: Class GSWSession</title>

   Copyright (C) 1999-2003 Free Software Foundation, Inc.
   
   Written by:	Manuel Guesdon <mguesdon@orange-concept.com>
   Date: 	Jan 1999
   
   $Revision: 1.21 $
   $Date: 2003/06/25 15:36:28 $
   $Id: GSWSession.m,v 1.21 2003/06/25 15:36:28 mguesdon Exp $

   This file is part of the GNUstep Web Library.
   
   <license>
   This library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Library General Public
   License as published by the Free Software Foundation; either
   version 2 of the License, or (at your option) any later version.
   
   This library is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   Library General Public License for more details.
   
   You should have received a copy of the GNU Library General Public
   License along with this library; if not, write to the Free
   Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
   </license>
**/

#include "config.h"

RCS_ID("$Id: GSWSession.m,v 1.21 2003/06/25 15:36:28 mguesdon Exp $")

#include "GSWeb.h"
#include <gnustep/base/GSCategories.h>

#include <time.h>
#if __linux__
#include <linux/kernel.h>
#include <linux/sys.h>
#include <sys/sysinfo.h>
#endif

//====================================================================

@implementation GSWSession

//--------------------------------------------------------------------
//	init
-(id)init
{
  LOGObjectFnStart();
  if ((self = [super init]))
    {
      NSTimeInterval sessionTimeOut=[GSWApplication sessionTimeOutValue];
      NSDebugMLLog(@"sessions",@"sessionTimeOut=%ld",(long)sessionTimeOut);
      [self setTimeOut:sessionTimeOut];
      [self _initWithSessionID:[[self class]createSessionID]];
    };
  LOGObjectFnStop();
  return self;
};

//--------------------------------------------------------------------
-(id)copyWithZone: (NSZone*)zone
{
  GSWSession* clone = [[isa allocWithZone: zone] init];
  LOGObjectFnNotImplemented();	//TODOFN
  /*
  [clone setSessionID:sessionID];
  [clone setLanguages:languages];
  [clone setTimeOut:timeOut];
  [clone setVariables:[[variables copy]autorelease]];
  [clone setPageCache:[[pageCache copy]autorelease]];
*/
  return clone;
};

+(NSString*)createSessionID
{
  // The idea is to have uniq sessionID generated.
  // Parts are:
  // o a modified TimeStamp (modified because we don't want to give 
  //  information on server exact time which can be always a security 
  // problem), so we can remember this sessionID for long time without conflict
  // o a md5 sum of various elements

  // The generated session ID is a sizeof(time_t)+16 bytes string
  
  NSString* sessionID=nil;
  NSMutableData* data=nil;
  NSMutableData* md5Data=nil;
  NSData* md5Sum=nil;
  void* pMd5Data=NULL;
  time_t ts=time(NULL);
  int sizeToFill=64;

  md5Data=[NSMutableData dataWithLength:64];
  pMd5Data=[md5Data mutableBytes];

  // initialize random generator 
  // We xor time stamp with a pointer so 2 sessions created at the same 
  // time won't have the same random generator initializer
  srand(((unsigned long int)ts) ^ ((unsigned long int)md5Data)); 
  
  // We randomize on 60s
  ts=ts+(int)(60*rand()/(RAND_MAX+1.0));
  
  data=[NSMutableData dataWithBytes:&ts
                      length:sizeof(ts)];

  // Now, use some system related chnaging info (
#if __linux__
  {
    struct sysinfo info;
    if ((sysinfo(&info)) == 0)
      {
        unsigned int rnd;

        // >0 test is to ignore not changing elements

        if (sizeToFill>=sizeof(unsigned int) && info.uptime>0)
          {
            rnd=(unsigned)(((float)UINT_MAX)*rand()/(RAND_MAX+1.0));
            NSDebugMLog(@"UPTIME %ld",(long)info.uptime);
            *((unsigned int*)pMd5Data)=(((unsigned int)(info.uptime)) ^ rnd);
            sizeToFill-=sizeof(unsigned int);
            pMd5Data+=sizeof(unsigned int);
          };

        if (sizeToFill>=sizeof(unsigned int) && info.loads[0]>0)
          {
            rnd=(unsigned)(((float)UINT_MAX)*rand()/(RAND_MAX+1.0));
            NSDebugMLog(@"loads[0] %ld",(long)info.loads[0]);
            *((unsigned int*)pMd5Data)=(((unsigned int)(info.loads[0] >> 4)) ^ rnd);
            sizeToFill-=sizeof(unsigned int);
            pMd5Data+=sizeof(unsigned int);
          };

        if (sizeToFill>=sizeof(unsigned int) && info.loads[1]>0)
          {
            rnd=(unsigned)(((float)UINT_MAX)*rand()/(RAND_MAX+1.0));
            NSDebugMLog(@"loads[1] %ld",(long)info.loads[1]);
            *((unsigned int*)pMd5Data)=(((unsigned int)(info.loads[1] >> 4)) ^ rnd);
            sizeToFill-=sizeof(unsigned int);
            pMd5Data+=sizeof(unsigned int);
          };

        if (sizeToFill>=sizeof(unsigned int) && info.loads[2]>0)
          {
            rnd=(unsigned)(((float)UINT_MAX)*rand()/(RAND_MAX+1.0));
            NSDebugMLog(@"loads[2] %ld",(long)info.loads[2]);
            *((unsigned int*)pMd5Data)=(((unsigned int)(info.loads[2] >> 4)) ^ rnd);
            sizeToFill-=sizeof(unsigned int);
            pMd5Data+=sizeof(unsigned int);
          };

        if (sizeToFill>=sizeof(unsigned int) && info.freeram>0)
          {
            NSDebugMLog(@"freeram %ld",(unsigned long)info.freeram);
            rnd=(unsigned)(((float)UINT_MAX)*rand()/(RAND_MAX+1.0));
            *((unsigned int*)pMd5Data)=(((unsigned int)(info.freeram >> 4)) ^ rnd); // Drop 4 minor bits
            sizeToFill-=sizeof(unsigned int);
            pMd5Data+=sizeof(unsigned int);
          };
        
        if (sizeToFill>=sizeof(unsigned int) && info.sharedram>0)
          {
            NSDebugMLog(@"sharedram %ld",(unsigned long)info.sharedram);
            rnd=(unsigned)(((float)UINT_MAX)*rand()/(RAND_MAX+1.0));
            *((unsigned int*)pMd5Data)=(((unsigned int)(info.sharedram >> 4)) ^ rnd); // Drop 4 minor bits
            sizeToFill-=sizeof(unsigned int);
            pMd5Data+=sizeof(unsigned int);
          };
        
        if (sizeToFill>=sizeof(unsigned int) && info.freeswap>0)
          {
            NSDebugMLog(@"freeswap %ld",(unsigned long)info.freeswap);
            rnd=(unsigned)(((float)UINT_MAX)*rand()/(RAND_MAX+1.0));
            *((unsigned int*)pMd5Data)=(((unsigned int)(info.freeswap >> 4)) ^ rnd); // Drop 4 minor bits
            sizeToFill-=sizeof(unsigned int);
            pMd5Data+=sizeof(unsigned int);
          };
        
        if (sizeToFill>=sizeof(unsigned int) && info.bufferram>0)
          {
            NSDebugMLog(@"bufferram %ld",(unsigned long)info.bufferram);
            rnd=(unsigned)(((float)UINT_MAX)*rand()/(RAND_MAX+1.0));
            *((unsigned int*)pMd5Data)=(((unsigned int)(info.bufferram >> 4)) ^ rnd); // Drop 4 minor bits
            sizeToFill-=sizeof(unsigned int);
            pMd5Data+=sizeof(unsigned int);                            
          };
      };
  };
#endif
  NSDebugMLog(@"sizeToFill %d",sizeToFill);
  while(sizeToFill>0)
    {
      *((unsigned char*)pMd5Data)=(unsigned char)(256.0*rand()/(RAND_MAX+1.0));
      sizeToFill--;
      pMd5Data++;
    };
  //Now do md5 on bytes after sizeof(ts)
  md5Sum=[md5Data md5Digest];
  [data appendData:md5Sum];
  sessionID=[data hexadecimalRepresentation];
  return sessionID;
};
//--------------------------------------------------------------------
-(void)encodeWithCoder:(NSCoder*)coder
{
  LOGObjectFnNotImplemented();	//TODOFN
  /*
  [coder_ encodeObject:sessionID];
  [coder_ encodeObject:languages];
  [coder_ encodeValueOfObjCType: @encode(NSTimeInterval) at: &timeOut];
  [coder_ encodeObject:variables];
  [coder_ encodeObject:pageCache];
*/
}

//--------------------------------------------------------------------
-(id)initWithCoder: (NSCoder*)coder
{
  LOGObjectFnNotImplemented();	//TODOFN
  /*
  [coder_ decodeValueOfObjCType: @encode(id) at:&sessionID];
  [coder_ decodeValueOfObjCType: @encode(id) at:&languages];
  [coder_ decodeValueOfObjCType: @encode(NSTimeInterval) at: &timeOut];
  [coder_ decodeValueOfObjCType: @encode(id) at:&variables];
  [coder_ decodeValueOfObjCType: @encode(id) at:&pageCache];
*/
  return self;
}

//--------------------------------------------------------------------
-(void)dealloc
{
  GSWLogAssertGood(self);
  NSDebugFLog(@"Dealloc GSWSession %p. ThreadID=%p",(void*)self,(void*)objc_thread_id());
  NSDebugFLog0(@"Dealloc GSWSession: sessionID");
  DESTROY(_sessionID);
  NSDebugFLog0(@"Dealloc GSWSession:autoreleasePool ");
  GSWLogMemCF("Destroy NSAutoreleasePool: %p. ThreadID=%p",_autoreleasePool,(void*)objc_thread_id());
  DESTROY(_autoreleasePool);
  NSDebugFLog0(@"Dealloc GSWSession: contextArrayStack");
  DESTROY(_contextArrayStack);
  NSDebugFLog0(@"Dealloc GSWSession: contextRecords");
  DESTROY(_contextRecords);
  NSDebugFLog0(@"Dealloc GSWSession: editingContext");
  DESTROY(_editingContext);
  NSDebugFLog0(@"Dealloc GSWSession: languages");
  DESTROY(_languages);
  NSDebugFLog0(@"Dealloc GSWSession: componentState");
  DESTROY(_componentState);
  NSDebugFLog0(@"Dealloc GSWSession: birthDate");
  DESTROY(_birthDate);
  NSDebugFLog0(@"Dealloc GSWSession: statistics");
  DESTROY(_statistics);
  NSDebugFLog0(@"Dealloc GSWSession: formattedStatistics");
  DESTROY(_formattedStatistics);
  NSDebugFLog0(@"Dealloc GSWSession: currentContext (set to nil)");
  _currentContext=nil;
  NSDebugFLog0(@"Dealloc GSWSession: permanentPageCache");
  DESTROY(_permanentPageCache);
  NSDebugFLog0(@"Dealloc GSWSession: permanentContextIDArray");
  DESTROY(_permanentContextIDArray);
  NSDebugFLog0(@"Dealloc GSWSession Super");
  [super dealloc];
  NSDebugFLog0(@"End Dealloc GSWSession");
}

//--------------------------------------------------------------------
-(NSString*)description
{
  NSString* dscr=nil;
  GSWLogAssertGood(self);
  /*
  NSDebugMLLog(@"sessions",@"selfCount=%u",(unsigned int)[self retainCount]);
  NSDebugMLLog(@"sessions",@"sessionIDCount=%u",(unsigned int)[sessionID retainCount]);
  */
  dscr=[NSString stringWithFormat:@"<%s %p>",
				 object_get_class_name(self),
				 (void*)self];
  /*
  dscr=[NSString stringWithFormat:@"<%s %p - sessionID=%@ autoreleasePool=%p timeOut=%f contextArrayStack=%@",
				 object_get_class_name(self),
				 (void*)self,
				 sessionID,
				 (void*)autoreleasePool,
				 timeOut,
				 contextArrayStack];
  dscr=[dscr stringByAppendingFormat:@" contextRecords=%@ editingContext=%p languages=%@ componentState=%@ birthDate=%@",
			 contextRecords,
			 (void*)editingContext,
			 languages,
			 componentState,
			 birthDate];
  dscr=[dscr stringByAppendingFormat:@" statistics=%@ formattedStatistics=%@ currentContext=%p permanentPageCache=%@",
				   statistics,
				   formattedStatistics,
				   (void*)currentContext,
				   permanentPageCache];
  dscr=[dscr stringByAppendingFormat:@" permanentContextIDArray=%@ contextCounter=%d requestCounter=%d isAllowedToViewStatistics=%s", 
			 permanentContextIDArray,
			 contextCounter,
			 requestCounter,
			 isAllowedToViewStatistics ? "YES" : "NO"];

  dscr=[dscr stringByAppendingFormat:@" isTerminating=%s isDistributionEnabled=%s storesIDsInCookies=%s storesIDsInURLs=%s hasSessionLockedEditingContext=%s>",
				   isTerminating ? "YES" : "NO",
				   isDistributionEnabled ? "YES" : "NO",
				   storesIDsInCookies ? "YES" : "NO",
				   storesIDsInURLs ? "YES" : "NO",
				   hasSessionLockedEditingContext ? "YES" : "NO"];
  */
  return dscr;
};

//--------------------------------------------------------------------
//	sessionID

-(NSString*)sessionID
{
  return _sessionID;
};

//--------------------------------------------------------------------
//	sessionID

-(void)setSessionID:(NSString*)sessionID
{
  ASSIGN(_sessionID,sessionID);
};

//--------------------------------------------------------------------
-(NSString*)domainForIDCookies
{
  //OK
  NSString* domain=nil;
  GSWContext* context=nil;
  GSWRequest* request=nil;
  NSString* applicationName=nil;
  NSString* adaptorPrefix=nil;
  LOGObjectFnStart();
  [[GSWApplication application]lock];
  context=[self context];
  request=[context request];
  applicationName=[request applicationName];
  NSDebugMLLog(@"sessions",@"applicationName=%@",applicationName);
  adaptorPrefix=[request adaptorPrefix];
  NSDebugMLLog(@"sessions",@"adaptorPrefix=%@",adaptorPrefix);
  [[GSWApplication application]unlock];
  domain=[NSString stringWithFormat:@"%@/%@.%@",
                   adaptorPrefix,
                   applicationName,
                   GSWApplicationSuffix[GSWebNamingConv]];
  NSDebugMLLog(@"sessions",@"domain=%@",domain);
  LOGObjectFnStop();
  return domain;
};

//--------------------------------------------------------------------
-(BOOL)storesIDsInURLs
{
  //OK
  return _storesIDsInURLs;
};

//--------------------------------------------------------------------
-(void)setStoresIDsInURLs:(BOOL)flag
{
  //OK
  _storesIDsInURLs=flag;
};

//--------------------------------------------------------------------
-(NSDate*)expirationDateForIDCookies
{
  NSDate* expirationDateForIDCookies=nil;
  NSDebugMLLog(@"sessions",@"timeOut=%f",(double)_timeOut);
  expirationDateForIDCookies=[NSDate dateWithTimeIntervalSinceNow:_timeOut];
  NSDebugMLLog(@"sessions",@"expirationDateForIDCookies=%@ (HTML: %@)",
               expirationDateForIDCookies,
               [expirationDateForIDCookies htmlDescription]);
  return expirationDateForIDCookies;
};

//--------------------------------------------------------------------
-(BOOL)storesIDsInCookies
{
  //OK
  return _storesIDsInCookies;
};

//--------------------------------------------------------------------
-(void)setStoresIDsInCookies:(BOOL)flag
{
  //OK
  LOGObjectFnStart();
  NSDebugMLLog(@"sessions",@"newflag=%d",(int)flag);
  _storesIDsInCookies=flag;
  LOGObjectFnStop();
};

//--------------------------------------------------------------------
-(BOOL)isDistributionEnabled
{
  return _isDistributionEnabled;
};

//--------------------------------------------------------------------
-(void)setDistributionEnabled:(BOOL)flag
{
  LOGObjectFnStart();
  _isDistributionEnabled=flag;
  LOGObjectFnStop();
};

@end

//====================================================================

@implementation GSWSession (GSWSessionA)

//--------------------------------------------------------------------
-(id)_initWithSessionID:(NSString*)aSessionID
{
  //OK
  GSWApplication* application=nil;
  GSWStatisticsStore* statisticsStore=nil;
  LOGObjectFnStart();
  statisticsStore=[GSWApp statisticsStore];
  [statisticsStore _applicationCreatedSession:self];

  ASSIGNCOPY(_sessionID,aSessionID);
  NSDebugMLLog(@"sessions",@"sessionID=%u",aSessionID);
  NSDebugMLLog(@"sessions",@"_sessionID=%u",_sessionID);
  if (_sessionID)
    {
      NSDebugMLLog(@"sessions",@"sessionIDCount=%u",[_sessionID retainCount]);
    };
  application=[GSWApplication application];
  //applic statisticsStore
  //applic _activeSessionsCount
  ASSIGN(_birthDate,[NSDate date]);
  ASSIGN(_statistics,[NSMutableArray array]);
  _storesIDsInURLs=YES;
  [application _finishInitializingSession:self];
  LOGObjectFnStop();
  return self;
};

@end

//====================================================================

@implementation GSWSession (GSWTermination)

//--------------------------------------------------------------------
//	isTerminating

//--------------------------------------------------------------------
-(BOOL)isTerminating 
{
  return _isTerminating;
};

//--------------------------------------------------------------------
//	terminate
-(void)terminate 
{
  //OK
  NSString* sessionID=nil;
  LOGObjectFnStart();

  _isTerminating=YES;
  sessionID=[self sessionID];
  [self setTimeOut:(NSTimeInterval) 1];	// forces to call removeSessionWithID in GSWServerSessionStore to dealloc it
  [[NSNotificationCenter defaultCenter] postNotificationName:GSWNotification__SessionDidTimeOutNotification[GSWebNamingConv]
                                        object:sessionID];
  //TODO: VERIFY
  [self setTimeOut:(NSTimeInterval) 1];	// forces to call removeSessionWithID in GSWServerSessionStore to dealloc it
  //goto => GSWApp _sessionDidTimeOutNotification:
  //call GSWApp _discountTerminatedSession
  //call GSWApp statisticsStore
  //call statstore _sessionTerminating:self
  [[GSWApp statisticsStore] _sessionTerminating:self];
  LOGObjectFnStop();
};

-(void)_terminateByTimeout
{
  _wasTimedOut = YES;
  [self terminate];
}

// componentDefinition _notifyObserversForDyingComponent:Main component
//....

//--------------------------------------------------------------------
//	timeOut

-(NSTimeInterval)timeOut
{
  LOGObjectFnStart();
  NSDebugMLLog(@"sessions",@"timeOut=%ld",(long)_timeOut);
  LOGObjectFnStop();
  return _timeOut;
};

//--------------------------------------------------------------------
//	setTimeOut:

-(void)setTimeOut:(NSTimeInterval)timeOut
{
  NSDebugMLLog(@"sessions",@"timeOut=%ld",(long)timeOut);
  _timeOut=timeOut;
};

@end

//====================================================================
@implementation GSWSession (GSWSessionDebugging)

//--------------------------------------------------------------------
-(void)debugWithFormat:(NSString*)format,...
{
  LOGObjectFnNotImplemented();	//TODOFN
};

@end

//====================================================================
@implementation GSWSession (GSWSessionD)

//--------------------------------------------------------------------
-(void)_debugWithString:(NSString*)string
{
  LOGObjectFnNotImplemented();	//TODOFN
};

@end

//====================================================================

@implementation GSWSession (GSWPageManagement)

//--------------------------------------------------------------------
-(void)savePage:(GSWComponent*)page
{
  //OK
  GSWContext* context=nil;
  BOOL pageReplaced=NO;
  BOOL pageChanged=NO;
  LOGObjectFnStart();

  NSAssert(page,@"No Page");

  context=[self context];
  pageReplaced=[context _pageReplaced];

  if (!pageReplaced)
    pageChanged=[context _pageChanged];

  [self _savePage:page
        forChange:pageChanged || pageReplaced]; //??

/*
  NSData* data=[NSArchiver archivedDataWithRootObject:page];
  NSDebugMLLog(@"sessions",@"savePage data=%@",data);
  [pageCache setObject:data
  forKey:[[self context] contextID]//TODO
			 withDuration:60*60];//TODO
*/
  LOGObjectFnStop();
};

//--------------------------------------------------------------------
-(GSWComponent*)restorePageForContextID:(NSString*)aContextID
{
  //OK
  GSWComponent* page=nil;
  NSArray* contextArray=nil;
  GSWTransactionRecord* transactionRecord=nil;
  LOGObjectFnStart();
  GSWLogAssertGood(self);
  NSAssert(aContextID,@"No contextID");
  NSAssert([aContextID length]>0,@"contextID empty");
  NSDebugMLLog(@"sessions",@"aContextID=%@",aContextID);

  transactionRecord=[_contextRecords objectForKey:aContextID];
  NSDebugMLLog(@"sessions",@"transactionRecord=%@",transactionRecord);

  if (transactionRecord)
    {
      NSDebugMLLog(@"sessions",@"transactionRecord2=%@",transactionRecord);
      page=[transactionRecord responsePage];
      GSWLogAssertGood(page);
    };
  
  if (page) // will put it at the end of the stack
    {
      unsigned int stackIndex=0;
      unsigned int contextArrayIndex=0;

      NSDebugMLLog(@"sessions",@"transactionRecord3=%@",transactionRecord);
      NSDebugMLLog(@"sessions",@"page 1=%@",page);

      contextArray=[self _contextArrayForContextID:aContextID
                         stackIndex:&stackIndex
                         contextArrayIndex:&contextArrayIndex];

      NSDebugMLLog(@"sessions",@"page 2=%@",page);
      if (contextArray)
        {
          if (stackIndex!=([_contextArrayStack count]-1))
            {
              //NSLog(@"AA stackIndex=%d",stackIndex);
              //NSLog(@"AA _contextArrayStack class=%@",[_contextArrayStack class]);
              //NSLog(@"AA [_contextArrayStack count]=%d",[_contextArrayStack count]);
              [_contextArrayStack addObject:contextArray]; //add before removing to avoid release
              [_contextArrayStack removeObjectAtIndex:stackIndex];
            };
        };
    };

  if ([_permanentPageCache objectForKey:aContextID])
      page=[self _permanentPageWithContextID:aContextID];

  NSAssert(self,@"self");
  NSDebugMLLog(@"sessions",@"_currentContext=%@",_currentContext);
  NSDebugMLLog(@"sessions",@"page 3=%@",page);
  [page awakeInContext:_currentContext];
  NSDebugMLLog(@"sessions",@"page 4=%@",page);
  LOGObjectFnStop();
  return page;
};

//--------------------------------------------------------------------
//NDFN
-(uint)permanentPageCacheSize
{
  return [GSWApp permanentPageCacheSize];
};

//--------------------------------------------------------------------
-(void)savePageInPermanentCache:(GSWComponent*)page
{
  GSWContext* context=nil;
  NSMutableDictionary* permanentPageCache=nil;
  unsigned int permanentPageCacheSize=0;
  NSString* contextID=nil;
  LOGObjectFnStart();
  context=[self context];
  permanentPageCache=[self _permanentPageCache];
  permanentPageCacheSize=[self permanentPageCacheSize];
  while([_permanentContextIDArray count]>0 && [_permanentContextIDArray count]>=permanentPageCacheSize)
    {
      id deletePage=nil;
      NSString* deleteContextID=nil;
      [GSWApplication statusLogWithFormat:@"Deleting permanent cached Page"];
      deleteContextID=[_permanentContextIDArray objectAtIndex:0];
      GSWLogAssertGood(deleteContextID);
      RETAIN(deleteContextID); // We'll remove it from array
      [GSWApplication statusLogWithFormat:@"permanentContextIDArray=%@",
                      _permanentContextIDArray];
      [GSWApplication statusLogWithFormat:@"contextID=%@",deleteContextID];
      NSDebugMLLog(@"sessions",@"deleteContextID=%@",deleteContextID);
      NSDebugMLLog(@"sessions",@"[permanentContextIDArray objectAtIndex:0]=%@",
                   [_permanentContextIDArray objectAtIndex:0]);
      NSDebugMLLog(@"sessions",@"[permanentContextIDArray objectAtIndex:0] retainCount=%d",
                   (int)[[_permanentContextIDArray objectAtIndex:0] retainCount]);
      NSDebugMLLog(@"sessions",@"SESSION REMOVE: %p",[_permanentContextIDArray objectAtIndex:0]);
      [_permanentContextIDArray removeObjectAtIndex:0];
      deletePage=[_contextRecords objectForKey:deleteContextID];
      GSWLogAssertGood(deletePage);
      [GSWApplication statusLogWithFormat:@"delete page of class=%@",
                      [deletePage class]];
      NSDebugMLLog(@"sessions",@"SESSION REMOVE: %p",[permanentPageCache objectForKey:deleteContextID]);
      [permanentPageCache removeObjectForKey:deleteContextID];
      RELEASE(deleteContextID);
    };
  contextID=[context contextID];
  NSAssert(contextID,@"No contextID");

  if ([_permanentContextIDArray containsObject:contextID])
    {
      LOGSeriousError(@"page of class %@ contextID %@ already in permanent cache stack",
                      [page class],
                      contextID);
      NSDebugMLLog(@"sessions",@"SESSION REMOVE: %p",contextID);
      [_permanentContextIDArray removeObject:contextID];
      if (![permanentPageCache objectForKey:contextID])
        {
          LOGSeriousError0(@"but not present in cache");
        };
    }
  else if ([permanentPageCache objectForKey:contextID])
    {
      LOGSeriousError(@"page of class %@ contextID %@ in permanent cache but not in stack",
                      [page class],
                      contextID);
    };

  NSDebugMLLog(@"sessions",@"SESSION REPLACE: %p",[permanentPageCache objectForKey:contextID]);
  [permanentPageCache setObject:page
                      forKey:contextID];
  [_permanentContextIDArray addObject:contextID];
  //TODO
  {
    int i=0;
    id anObject=nil;
    id anotherContextID=nil;
    for(i=0;i<[_permanentContextIDArray count];i++)
      {
        anotherContextID=[_permanentContextIDArray objectAtIndex:i];
        anObject=[permanentPageCache objectForKey:anotherContextID];
        [GSWApplication statusLogWithFormat:@"%d contextID=%@ page class=%@",i,anotherContextID,[anObject class]];
      };
  };
  if ([_permanentContextIDArray count]!=[permanentPageCache count])
    {
      LOGSeriousError(@"[permanentContextIDArray count] %d != [permanentPageCache count] %d",
                      (int)[_permanentContextIDArray count],
                      (int)[permanentPageCache count]);
    };
  LOGObjectFnStop();
};

@end

//====================================================================
@implementation GSWSession (GSWSessionF)

//--------------------------------------------------------------------
-(void)clearCookieFromResponse:(GSWResponse*)aResponse
{
  NSString* domainForIDCookies=nil;
  NSString* sessionID=nil;
  NSDate* anExpireDate=nil;
  LOGObjectFnStart();
  domainForIDCookies=[self domainForIDCookies];
  sessionID=[self sessionID];
  anExpireDate=[NSDate date]; // Expire now
  [aResponse addCookie:[GSWCookie cookieWithName:GSWKey_SessionID[GSWebNamingConv]
                                  value:sessionID
                                  path:domainForIDCookies
                                  domain:nil
                                  expires:anExpireDate
                                  isSecure:NO]];
  [aResponse addCookie:[GSWCookie cookieWithName:GSWKey_InstanceID[GSWebNamingConv]
                                  value:@"-1"
                                  path:domainForIDCookies
                                  domain:nil
                                  expires:anExpireDate
                                  isSecure:NO]];

  LOGObjectFnStop();
};

//--------------------------------------------------------------------
-(void)appendCookieToResponse:(GSWResponse*)aResponse
{
  //OK
  LOGObjectFnStart();
  if ([self storesIDsInCookies])
    {
      //TODO VERIFY
      NSString* domainForIDCookies=[self domainForIDCookies];
      NSString* sessionID=[self sessionID];
      int instance=-1;
      NSDate* anExpireDate=[self expirationDateForIDCookies];

      // SessionID cookie
      [aResponse addCookie:[GSWCookie cookieWithName:GSWKey_SessionID[GSWebNamingConv]
                                      value:sessionID
                                      path:domainForIDCookies
                                      domain:nil
                                      expires:anExpireDate
                                      isSecure:NO]];

      // Instance Cookie
      // No Instance if distribution enabled or this session is terminating
      if ([self isDistributionEnabled] || [self isTerminating])
        {
          instance=-1;
          anExpireDate=[NSDate date]; //expire now !
        }
      else
        {
          GSWRequest* request = [_currentContext request];
          if (request)
            instance=[request applicationNumber]; // use the request instance number
          else
          instance=-1;
        };
      [aResponse addCookie:[GSWCookie cookieWithName:GSWKey_InstanceID[GSWebNamingConv]
                                      value:[NSString stringWithFormat:@"%d",instance]
                                      path:domainForIDCookies
                                      domain:nil
                                      expires:anExpireDate
                                      isSecure:NO]];

    };
  LOGObjectFnStop();
};

@end

//====================================================================
@implementation GSWSession (GSWSessionG)
extern id gcObjectsToBeVisited;
//--------------------------------------------------------------------
-(void)_releaseAutoreleasePool
{
  //OK
  LOGObjectFnStart();
  printf("session %p _releaseAutoreleasePool START\n",self);
  fprintf(stderr,"session %p _releaseAutoreleasePool START\n",self);
//TODO-NOW remettre  [GarbageCollector collectGarbages];
  printf("session %p _releaseAutoreleasePool after garbage",self);
fprintf(stderr,"session %p _releaseAutoreleasePool after garbage\n",self);
  DESTROY(_autoreleasePool);
  printf("session %p _releaseAutoreleasePool STOP\n",self);
fprintf(stderr,"session %p _releaseAutoreleasePool STOP\n",self);
  LOGObjectFnStop();
};

//--------------------------------------------------------------------
-(void)_createAutoreleasePool
{
  //OK
  LOGObjectFnStart();
  if (!_autoreleasePool)
    {
      _autoreleasePool=[NSAutoreleasePool new];
      GSWLogMemCF("New NSAutoreleasePool: %p",_autoreleasePool);
    }
  LOGObjectFnStop();
};

//--------------------------------------------------------------------
-(GSWComponent*)_permanentPageWithContextID:(NSString*)aContextID
{
  //OK
  GSWComponent* page=nil;
  LOGObjectFnStart();
  page=[_permanentPageCache objectForKey:aContextID];
  LOGObjectFnStop();
  return page;
};

//--------------------------------------------------------------------
-(NSMutableDictionary*)_permanentPageCache
{
  //OK
  LOGObjectFnStart();
  if (!_permanentPageCache)
    _permanentPageCache=[NSMutableDictionary new];
  if (!_permanentContextIDArray)
    _permanentContextIDArray=[NSMutableArray new];
  LOGObjectFnStop();
  return _permanentPageCache;
};

//--------------------------------------------------------------------
-(NSString*)_contextIDMatchingContextID:(NSString*)aContextID
                        requestSenderID:(NSString*)aSenderID
{
  NSAssert(NO,@"Deprecated. use _contextIDMatchingIDsInContext:");
  return nil;
};

//--------------------------------------------------------------------
-(NSString*)_contextIDMatchingIDsInContext:(GSWContext*)aContext
{
  NSString* contextID=nil;
  NSString* requestContextID=nil;

  LOGObjectFnStart();
  NSDebugMLog(@"aContext=%@",aContext);
  requestContextID=[aContext _requestContextID];
  NSDebugMLog(@"requestContextID=%@",requestContextID);
  if (_contextRecords &&  requestContextID)
    {
      NSArray* contextIDs = [_contextRecords allKeys];
      int count = [contextIDs count];
      int i=0;
      for(i=0;!contextID && i<count;i++)
        {
          NSString* aContextID=[contextIDs objectAtIndex:i];
          GSWTransactionRecord* aTransactionRecord=[_contextRecords objectForKey:aContextID];
          if ([aTransactionRecord isMatchingIDsInContext:aContext])
            contextID=aContextID;
        };      
    }

  LOGObjectFnStop();

  return contextID;
}

//--------------------------------------------------------------------
-(void)_rearrangeContextArrayStackForContextID:(NSString*)contextID
{
  LOGObjectFnStart();

  if (_contextRecords)
    {
      unsigned int stackIndex=0;
      unsigned int contextArrayIndex=0;
      NSMutableArray* contextArray = [self _contextArrayForContextID:contextID
                                           stackIndex:&stackIndex
                                           contextArrayIndex:&contextArrayIndex];
      int stackCount=[_contextArrayStack count];
      if (contextArray  // Found
          && (stackIndex!=stackCount-1 // not already the last one
              || contextArrayIndex!=[contextArray count]-1)
          )
        {
          // Put it at the stack end
          [_contextArrayStack addObject:contextArray]; //add before removing to avoid release
          //NSLog(@"AA _contextArrayStack class=%@",[_contextArrayStack class]);
          //NSLog(@"BB stackIndex=%d",stackIndex);
          //NSLog(@"BB [_contextArrayStack count]=%d",[_contextArrayStack count]);
          [_contextArrayStack removeObjectAtIndex:stackIndex];              
        };
    }
  LOGObjectFnStop();
};

//--------------------------------------------------------------------
-(NSMutableArray*)_contextArrayForContextID:(NSString*)aContextID
                                 stackIndex:(unsigned int*)pStackIndex
                          contextArrayIndex:(unsigned int*)pContextArrayIndex
{
  NSMutableArray* contextArray=nil;
  int stackCount=[_contextArrayStack count];
  unsigned int i=0;
  for(i=0;!contextArray && i<stackCount;i++)
    {
      NSMutableArray* aContextArray=[_contextArrayStack objectAtIndex:i];
      unsigned int contextArrayIndex=[aContextArray indexOfObject:aContextID];
      if (contextArrayIndex!=NSNotFound)
        {
          contextArray=aContextArray;
          if (pStackIndex)
            *pStackIndex=i;
          if (pContextArrayIndex)
            *pContextArrayIndex=contextArrayIndex;
        };
    };
  if (!contextArray)
    {
      if (pStackIndex)
        *pStackIndex=NSNotFound;
      if (pContextArrayIndex)
        *pContextArrayIndex=NSNotFound;
    };
  return contextArray;
};

//--------------------------------------------------------------------
-(void)_replacePage:(GSWComponent*)page
{
  LOGObjectFnNotImplemented();	//TODOFN
};

//--------------------------------------------------------------------
//NDFN
-(uint)pageCacheSize
{
  return [GSWApp pageCacheSize];
};

//--------------------------------------------------------------------
-(void)_savePage:(GSWComponent*)page
       forChange:(BOOL)forChange
{
  //OK
  GSWResponse* response=nil;
  GSWTransactionRecord* transactionRecord=nil;
  int pageCacheSize=0;
  NSString* contextID=nil;
  int pagesCount=0;
  int contextsCount=0;
  NSMutableArray* contextArray=nil;
  BOOL createNewContextArrayFlag=NO;
  LOGObjectFnStart();

  NSAssert(page,@"No Page");

  // Retrieve Page contextID
  contextID=[[page context]contextID];
  NSDebugMLLog(@"sessions",@"_contextID=%@",contextID);
  NSAssert(contextID,@"No contextID");

  if ([_contextArrayStack count]>0) // && _forChange!=NO ??
    {
      [self _rearrangeContextArrayStackForContextID:contextID];
      contextArray=[_contextArrayStack lastObject]; //??
    };

  if(forChange || !contextArray)
    createNewContextArrayFlag=YES;
  else if ([contextArray count]>0)
    {
      NSString* lastContextID=[contextArray lastObject];
      GSWTransactionRecord* transRecord = (GSWTransactionRecord*)[_contextRecords objectForKey:lastContextID];
      GSWComponent* transRecordResponsePage = [transRecord responsePage];
      createNewContextArrayFlag = (page!=transRecordResponsePage);
    }
  
  if (createNewContextArrayFlag)
    {
      contextArray = [NSMutableArray array];
      [_contextArrayStack addObject:contextArray];
    }

  // Create contextArrayStack and contextRecords if not already created
  if (!_contextArrayStack)
    _contextArrayStack=[NSMutableArray new];

  if (!_contextRecords)
    _contextRecords=[NSMutableDictionary new];

  NSDebugMLLog(@"sessions",@"contextArrayStack=%@",_contextArrayStack);
  NSDebugMLLog(@"sessions",@"contextRecords=%@",_contextRecords);

  // Get the response
  response=[_currentContext response];
  NSDebugMLLog(@"sessions",@"response=%@",response);

  // Create a new transaction record
  if (response && [response _isClientCachingDisabled])
    transactionRecord = [GSWTransactionRecord transactionRecordWithResponsePage:page
                                              context:_currentContext];
  else
    transactionRecord = [GSWTransactionRecord transactionRecordWithResponsePage:page
                                              context:NULL];

  NSDebugMLLog(@"sessions",@"transactionRecord=%@",transactionRecord);

  // Add it to contextRecords...
  [_contextRecords setObject:transactionRecord
                   forKey:contextID];
  [contextArray addObject:contextID];

  // Retrieve the pageCacheSize
  pageCacheSize=[self pageCacheSize];
  NSDebugMLLog(@"sessions",@"pageCacheSize=%d",pageCacheSize);
  NSAssert1(pageCacheSize>=0,@"bad pageCacheSize %d",pageCacheSize);

  // Remove contextArray pages if page number greater than page cache size
  pagesCount=[contextArray count];
  while(pagesCount>=pageCacheSize)
    {
      NSString* deleteContextID=[contextArray objectAtIndex:0];

      RETAIN(deleteContextID);
      GSWLogAssertGood(deleteContextID);

      [GSWApplication statusLogWithFormat:@"Deleting cached Page"];

      //NSLog(@"DD contextArray class=%@",[contextArray class]);
      //NSLog(@"CC contextArray count=%d",[contextArray count]);
      [contextArray removeObjectAtIndex:0];
      [_contextRecords removeObjectForKey:deleteContextID];
      RELEASE(deleteContextID);
      pagesCount--;
    };

  // If empty, remove it
  //NSLog(@"DD _contextArrayStack class=%@",[_contextArrayStack class]);
  //NSLog(@"DD _contextArrayStack count=%d",[_contextArrayStack count]);
  if(pagesCount==0)
    [_contextArrayStack removeLastObject];

  contextsCount=[_contextArrayStack count];
  //NSLog(@"zz1 contextsCount=%d",contextsCount);
  //NSLog(@"zz1 pageCacheSize=%d",pageCacheSize);
  while(contextsCount>=pageCacheSize)
    {
      NSMutableArray* aContextArray=[_contextArrayStack objectAtIndex:0];
      //NSLog(@"zz2 contextsCount=%d",contextsCount);
      pagesCount=[aContextArray count];
      while(pagesCount)
        {
          NSString* deleteContextID=[aContextArray objectAtIndex:0];
          RETAIN(deleteContextID);
          GSWLogAssertGood(deleteContextID);

          [GSWApplication statusLogWithFormat:@"Deleting cached Page"];

          //NSLog(@"EE aContextArray class=%@",[aContextArray class]);
          //NSLog(@"EE aContextArray count=%d",[aContextArray count]);
          [aContextArray removeObjectAtIndex:0];
          [_contextRecords removeObjectForKey:deleteContextID];
          RELEASE(deleteContextID);
          pagesCount--;
        };
      contextsCount--;
    };
  //NSLog(@"FF _contextArrayStack class=%@",[_contextArrayStack class]);
  //NSLog(@"FF _contextArrayStack count=%d",[_contextArrayStack count]);

  LOGObjectFnStop();
};

//--------------------------------------------------------------------
-(void)_saveCurrentPage
{
  //OK
  LOGObjectFnStart();
  if (_currentContext)
    {
      GSWComponent* component=[_currentContext _pageComponent];
      if ([component _isPage])
        {
          GSWComponent* testComponent=[self _permanentPageWithContextID:[_currentContext contextID]];
          if (testComponent!=component)
            {
              testComponent=[self _permanentPageWithContextID:[_currentContext _requestContextID]];
              if (testComponent && [self permanentPageCacheSize]>0)
                {
                  [self savePageInPermanentCache:component];
                }
              else
                {
                  if ([self pageCacheSize]>0)
                    [self savePage:component];
                };
            };
        };
    };
  LOGObjectFnStop();
};

//--------------------------------------------------------------------
-(int)_requestCounter
{
  //OK
  return _requestCounter;
};

//--------------------------------------------------------------------
-(void)_contextDidIncrementContextID
{
  _contextCounter++;
};

//--------------------------------------------------------------------
-(int)_contextCounter
{
  //OK
  return _contextCounter;
};

//--------------------------------------------------------------------
-(void)_setContext:(GSWContext*)aContext
{
  //OK
  LOGObjectFnStart();
  NSDebugMLLog(@"sessions",@"aContext=%p",(void*)aContext);
  _currentContext=aContext;
  LOGObjectFnStop();
};

//--------------------------------------------------------------------
-(void)sleepInContext:(GSWContext*)aContext
{
  //OK
  LOGObjectFnStart();
  [self sleep];
  [self _setContext:nil];
  LOGObjectFnStop();
};

//--------------------------------------------------------------------
-(void)awakeInContext:(GSWContext*)aContext
{
  //OK
  LOGObjectFnStart();
  [self _setContext:aContext];
  NSDebugMLLog(@"sessions",@"contextCounter=%i",_contextCounter);
  if (aContext)
    {
      if ([[self class] __counterIncrementingEnabledFlag]) //??
        {
          _contextCounter++;
          _requestCounter++;
        };
    };
  NSDebugMLLog(@"sessions",@"contextCounter=%i",_contextCounter);
  [self awake];
  LOGObjectFnStop();
};

@end

//====================================================================
@implementation GSWSession (GSWLocalization)

//--------------------------------------------------------------------
-(void)setLanguages:(NSArray*)someLanguages
{
  //OK
  if (!someLanguages)
    {
      LOGError0(@"No languages");
    };
  ASSIGN(_languages,someLanguages);
};

//--------------------------------------------------------------------
-(NSArray*)languages
{
  //OK
  if (!_languages)
    {
      GSWContext* aContext=[self context];
      GSWRequest* request=[aContext request];
      NSArray* languages=[request browserLanguages];
      [self setLanguages:languages];
    };
  return _languages;
};

@end

//====================================================================
@implementation GSWSession (GSWComponentStateManagement)

//--------------------------------------------------------------------
//	objectForKey:
-(id)objectForKey:(NSString*)key
{
  id object=nil;
  LOGObjectFnStart();
  object=[_componentState objectForKey:key];
  NSDebugMLLog(@"sessions",@"key=%@ object=%@",key,object);
  LOGObjectFnStop();
  return object;
};

//--------------------------------------------------------------------
//	setObject:forKey:
-(void)setObject:(id)object
          forKey:(NSString*)key
{
  LOGObjectFnStart();
  if (!_componentState)
    _componentState=[NSMutableDictionary new];
  NSDebugMLLog(@"sessions",@"key=%@ object=%@",key,object);
  [_componentState setObject:object
                   forKey:key];
  LOGObjectFnStop();
};

//--------------------------------------------------------------------
-(void)removeObjectForKey:(NSString*)key
{
  LOGObjectFnStart();
  NSDebugMLLog(@"sessions",@"key=%@",key);
  [_componentState removeObjectForKey:key];
  LOGObjectFnStop();
};

//--------------------------------------------------------------------
//NDFN
-(NSMutableDictionary*)componentState
{
  return _componentState;
};
@end

//====================================================================
@implementation GSWSession (GSWEnterpriseObjects)

//--------------------------------------------------------------------
-(EOEditingContext*)defaultEditingContext
{
#if GDL2
  if(!_editingContext)
    {
      ASSIGN(_editingContext,[[[EOEditingContext alloc] init] autorelease]);
    }
#endif

  return _editingContext;
};

//--------------------------------------------------------------------
-(void)setDefaultEditingContext:(EOEditingContext*)editingContext
{
  ASSIGN(_editingContext,editingContext);
};

@end

//====================================================================
@implementation GSWSession (GSWRequestHandling)

//--------------------------------------------------------------------
-(GSWContext*)context
{
  return _currentContext;
};

//--------------------------------------------------------------------
//	awake
-(void)awake 
{
  //ok
  //Does Nothing
};

//--------------------------------------------------------------------
//	sleep

-(void)sleep 
{
  //Does Nothing
};

//--------------------------------------------------------------------
//	takeValuesFromRequest:inContext:
-(void)takeValuesFromRequest:(GSWRequest*)aRequest
                   inContext:(GSWContext*)aContext 
{
  //OK
  GSWElement* pageElement=nil;
  GSWComponent* pageComponent=nil;
  LOGObjectFnStart();
  pageElement=[aContext _pageElement];
  pageComponent=[aContext _pageComponent];
#ifndef NDEBUG
  [aContext addDocStructureStep:@"Take Values From Request"];
#endif
  [aContext _setCurrentComponent:pageComponent]; //_pageElement ??
  [pageComponent takeValuesFromRequest:aRequest
                 inContext:aContext]; //_pageComponent ??
  [aContext _setCurrentComponent:nil];
  LOGObjectFnStop();
};

//--------------------------------------------------------------------
//	invokeActionForRequest:inContext:
-(GSWElement*)invokeActionForRequest:(GSWRequest*)aRequest
                           inContext:(GSWContext*)aContext 
{
  GSWElement* element=nil;
  GSWElement* pageElement=nil;
  GSWComponent* pageComponent=nil;
  LOGObjectFnStart();
  NS_DURING
    {
      pageElement=[aContext _pageElement];
      pageComponent=[aContext _pageComponent];
#ifndef NDEBUG
      [aContext addDocStructureStep:@"Invoke Action For Request"];
#endif
      [aContext _setCurrentComponent:pageComponent]; //_pageElement ??
      element=[pageComponent invokeActionForRequest:aRequest
                             inContext:aContext]; //_pageComponent
      [aContext _setCurrentComponent:nil];
      if (!element)
        element=[aContext page]; //??
    }
  NS_HANDLER
    {
      LOGException0(@"exception in GSWSession invokeActionForRequest:inContext");
      LOGException(@"exception=%@",localException);
      localException=ExceptionByAddingUserInfoObjectFrameInfo(localException,
                                                              @"In GSWSession invokeActionForRequest:inContext");
      LOGException(@"exception=%@",localException);
      [localException raise];
    }
  NS_ENDHANDLER;
  LOGObjectFnStop();
  return element;
};

//--------------------------------------------------------------------
//	appendToResponse:inContext:
-(void)appendToResponse:(GSWResponse*)aResponse
			  inContext:(GSWContext*)aContext 
{
  //OK
  GSWStatisticsStore* statisticsStore=nil;
  NSString* logFile=nil;
  GSWSession* session=nil;
  GSWElement* pageElement=nil;
  GSWComponent* pageComponent=nil;
  LOGObjectFnStart();
  statisticsStore=[[GSWApplication application] statisticsStore];
  pageElement=[aContext _pageElement];
  pageComponent=[aContext _pageComponent];
#ifndef NDEBUG
  [aContext addDocStructureStep:@"Append To Response"];
#endif
  [aContext _setCurrentComponent:pageComponent]; //_pageElement ??
  NS_DURING
    {
      [pageComponent appendToResponse:aResponse
                     inContext:aContext]; //_pageComponent??
    }
  NS_HANDLER
    {
      LOGException(@"exception in %@ appendToResponse:inContext",
                   [self class]);
      LOGException(@"exception=%@",localException);
      localException=ExceptionByAddingUserInfoObjectFrameInfo(localException,
                                                              @"In %@ appendToResponse:inContext",
                                                              [self class]);
      LOGException(@"exception=%@",localException);
      [localException raise];
    }
  NS_ENDHANDLER;
  [aContext _setCurrentComponent:nil];
  session=[aContext existingSession];
  [session appendCookieToResponse:aResponse];
  [statisticsStore recordStatisticsForResponse:aResponse
                   inContext:aContext];
  [statisticsStore descriptionForResponse:aResponse
                    inContext:aContext];
  logFile=[statisticsStore logFile];
  if (logFile)
    {
      //TODO
    };
  LOGObjectFnStop();
};


@end

//====================================================================
@implementation GSWSession (GSWStatistics)

//--------------------------------------------------------------------
-(NSArray*)statistics
{
  //return (Main, DisksList, DisksList, DisksList) (page dans l'ordre des context)
  LOGObjectFnNotImplemented();	//TODOFN
  return nil;
};

@end

//====================================================================
@implementation GSWSession (GSWSessionM)

//--------------------------------------------------------------------
-(BOOL)_allowedToViewStatistics
{
  return _isAllowedToViewStatistics;
};

//--------------------------------------------------------------------
-(void)_allowToViewStatistics
{
  _isAllowedToViewStatistics=YES;
};

//--------------------------------------------------------------------
-(id)_formattedStatistics
{
  LOGObjectFnNotImplemented();	//TODOFN
  return nil;
};

//--------------------------------------------------------------------
-(NSDate*)_birthDate
{
  return _birthDate;
};

@end

//====================================================================
@implementation GSWSession (GSWSessionN)

//--------------------------------------------------------------------
-(GSWApplication*)application
{
  return [GSWApplication application];
};

@end

//====================================================================
@implementation GSWSession (GSWSessionO)

//--------------------------------------------------------------------
-(void)_validateAPI
{
  LOGObjectFnNotImplemented();	//TODOFN
};

@end

//====================================================================
@implementation GSWSession (GSWSessionClassA)

//--------------------------------------------------------------------
+(void)__setContextCounterIncrementingEnabled:(BOOL)flag
{
  LOGClassFnNotImplemented();  //TODOFN
};

//--------------------------------------------------------------------
+(int)__counterIncrementingEnabledFlag
{
  LOGClassFnNotImplemented();  //TODOFN
  return 1;
};

@end
