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

   Copyright (C) 1999-2004 Free Software Foundation, Inc.
   
   Written by:	Manuel Guesdon <mguesdon@orange-concept.com>
   Date: 	Jan 1999
   
   $Revision: 37929 $
   $Date: 2014-05-30 20:28:04 +0200 (Fri, 30 May 2014) $
   $Id: GSWComponent.m 37929 2014-05-30 18:28:04Z buzzdee $
   
   <abstract></abstract>

   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"

#include "GSWeb.h"

#include "GSWPrivate.h"
#include "WOKeyValueUnarchiver.h"
#include <GNUstepBase/NSObject+GNUstepBase.h>
#include <GNUstepBase/NSString+GNUstepBase.h>

//====================================================================
@implementation GSWComponent

/* Static variables */

static NSMutableDictionary * TheTemplateNameDictionary = nil;
static NSLock * TheTemplateNameDictionaryLock = nil;
static Class GSWHTMLBareStringClass = Nil;

//--------------------------------------------------------------------
+ (void) initialize
{
  if (self == [GSWComponent class])
    {
      TheTemplateNameDictionary = [NSMutableDictionary new];
      TheTemplateNameDictionaryLock = [[NSLock alloc] init];
      GSWHTMLBareStringClass = [GSWHTMLBareString class];
    }
}

//--------------------------------------------------------------------
// deprecated. use initWithContext:
-(id)init
{
//  NSLog(@"%s init: deprecated. use initWithContext", class_getName([self class]));
  return [self initWithContext:[GSWComponentDefinition TheTemporaryContext]];
}

//--------------------------------------------------------------------
- (id)initWithContext:(GSWContext *) aContext
{
  Class myClass = Nil;
  GSWComponentDefinition* aComponentDefinition = nil;
  
  if ((self=[super init]))
    {
      if (aContext == nil)
	{
	  [NSException raise:NSInvalidArgumentException
		       format:@"Attempt to init component without a context. In %s",
		       __PRETTY_FUNCTION__];
	}

    [self _setContext:aContext];

    myClass = [self class];
    if (myClass == [GSWComponent class])
      ASSIGN(_name, [aContext _componentName]);
    else
      ASSIGN(_name, NSStringFromClass([self class]));
    
    ASSIGN(_templateName,NSStringFromClass(myClass));
    _isPage = NO;
    _subComponents = nil;
    [self setCachingEnabled:[GSWApp isCachingEnabled]];

    ASSIGN(_componentDefinition, [aContext _tempComponentDefinition]);
    aComponentDefinition = [self _componentDefinition];
    [aComponentDefinition finishInitializingComponent:self];
    
    _isSynchronized = [self synchronizesVariablesWithBindings];
  }

  return self;
}

//--------------------------------------------------------------------
-(void)dealloc
{
  DESTROY(_keyAssociations);
  DESTROY(_childTemplate);
  DESTROY(_componentDefinition);
  DESTROY(_defaultAssociations);
  DESTROY(_name);
  DESTROY(_subComponents);
  DESTROY(_template);
  DESTROY(_templateName);
  DESTROY(_userAssociations);
  DESTROY(_userDictionary);
  DESTROY(_context); //_context=nil;
  _parent = nil;
  _session = nil;
  
  [super dealloc];
}

//--------------------------------------------------------------------
-(id)copyWithZone: (NSZone*)zone
{
  GSWComponent* clone = [[isa allocWithZone: zone] init];
  ASSIGNCOPY(clone->_name,_name);
  ASSIGNCOPY(clone->_subComponents,_subComponents);
  ASSIGNCOPY(clone->_templateName,_templateName);
  ASSIGN(clone->_template,_template);
  ASSIGN(clone->_componentDefinition,_componentDefinition);
  ASSIGN(clone->_parent,_parent);
  ASSIGNCOPY(clone->_keyAssociations, _keyAssociations);
  ASSIGNCOPY(clone->_childTemplate,_childTemplate);
  ASSIGNCOPY(clone->_context,_context);
  ASSIGNCOPY(clone->_session,_session);
  clone->_isPage=_isPage;
  clone->_isCachingEnabled=_isCachingEnabled;
//  clone->_isParentToComponentSynchronized=_isParentToComponentSynchronized;
//  clone->_isComponentToParentSynchronized=_isComponentToParentSynchronized;
  return clone;
}

//--------------------------------------------------------------------
//-(void)encodeWithCoder:(NSCoder*)aCoder
//{
//  //TODOV
//  [super encodeWithCoder:aCoder];
//  [aCoder encodeObject:_name];
//  [aCoder encodeObject:_subComponents];
//  [aCoder encodeObject:_templateName];
//  [aCoder encodeObject:_template];
//  [aCoder encodeObject:_componentDefinition];
//  [aCoder encodeObject:_parent];
//  [aCoder encodeObject:_keyAssociations];
//  [aCoder encodeObject:_childTemplate];
//  [aCoder encodeObject:_context];
//  [aCoder encodeObject:_session];
//  [aCoder encodeValueOfObjCType:@encode(BOOL)
//          at:&_isPage];
//  [aCoder encodeValueOfObjCType:@encode(BOOL)
//          at:&_isCachingEnabled];
////  [aCoder encodeValueOfObjCType:@encode(BOOL)
////          at:&_isParentToComponentSynchronized];
////  [aCoder encodeValueOfObjCType:@encode(BOOL)
////          at:&_isComponentToParentSynchronized];
//}
//
////--------------------------------------------------------------------
//-(id)initWithCoder:(NSCoder*)aCoder
//{
//  //TODOV
//  if ((self = [super initWithCoder:aCoder]))
//    {
//      [aCoder decodeValueOfObjCType:@encode(id)
//              at:&_name];
//      [aCoder decodeValueOfObjCType:@encode(id)
//              at:&_subComponents];
//      [aCoder decodeValueOfObjCType:@encode(id)
//              at:&_templateName];
//      [aCoder decodeValueOfObjCType:@encode(id)
//              at:&_template];
//      [aCoder decodeValueOfObjCType:@encode(id)
//              at:&_componentDefinition];
//      [aCoder decodeValueOfObjCType:@encode(id)
//              at:&_parent];
//      [aCoder decodeValueOfObjCType:@encode(id)
//              at:&_keyAssociations];
//      [aCoder decodeValueOfObjCType:@encode(id)
//              at:&_childTemplate];
//      [aCoder decodeValueOfObjCType:@encode(id)
//              at:&_context];
//      [aCoder decodeValueOfObjCType:@encode(id)
//              at:&_session];
//      [aCoder decodeValueOfObjCType:@encode(BOOL)
//              at:&_isPage];
//      [aCoder decodeValueOfObjCType:@encode(BOOL)
//              at:&_isCachingEnabled];
////      [aCoder decodeValueOfObjCType:@encode(BOOL)
////              at:&_isParentToComponentSynchronized];
////      [aCoder decodeValueOfObjCType:@encode(BOOL)
////              at:&_isComponentToParentSynchronized];
//	}
//  return self;
//}
//
//--------------------------------------------------------------------
//	frameworkName

-(NSString*)frameworkName 
{
  GSWComponentDefinition* aComponentDefinition=[self _componentDefinition];
  NSAssert(aComponentDefinition,@"No componentDefinition");

  return [aComponentDefinition frameworkName];
}

//--------------------------------------------------------------------
//	logString:
-(void)logString:(NSString*)aString
{
  [GSWApp logString:aString];
}

//--------------------------------------------------------------------
//	logWithFormat:
-(void)logWithFormat:(NSString*)aFormat,...
{
  va_list ap;
  va_start(ap,aFormat);
  [self logWithFormat:aFormat
        arguments:ap];
  va_end(ap);
}

//--------------------------------------------------------------------
//	logWithFormat:arguments:
-(void)logWithFormat:(NSString*)aFormat
           arguments:(va_list)arguments
{
  NSString* string=[NSString stringWithFormat:aFormat
                             arguments:arguments];
  [self logString:string];
}

//--------------------------------------------------------------------
//	name
-(NSString*)name 
{
  return _name;
}

//--------------------------------------------------------------------
//	path
-(NSString*)path 
{
  return [[self _componentDefinition] path];
}

//--------------------------------------------------------------------
//	baseURL
-(NSString*)baseURL 
{
  return [[self _componentDefinition] baseURL];
}


//--------------------------------------------------------------------
-(NSString*)description
{
  return [NSString stringWithFormat:@"<%s %p>",
		   object_getClassName(self),
		   (void*)self];
}

// GSWeb Additions {
//--------------------------------------------------------------------
-(NSDictionary*)userDictionary
{
  return _userDictionary;
}

//--------------------------------------------------------------------
-(void)setUserDictionary:(NSDictionary*)aUserDictionary
{
  ASSIGN(_userDictionary,aUserDictionary);
}

//--------------------------------------------------------------------
-(NSDictionary*)userAssociations
{
  return _userAssociations;
}

//--------------------------------------------------------------------
-(void)setUserAssociations:(NSDictionary*)userAssociations
{
  ASSIGN(_userAssociations,userAssociations);
}

//--------------------------------------------------------------------
-(GSWAssociation*)userAssociationForKey:(NSString*)key
{
  return [[self userAssociations]objectForKey:key];
}

//--------------------------------------------------------------------
-(NSDictionary*)defaultAssociations
{
  NSLog(@"WARNING: %s is not WebObjects API",__PRETTY_FUNCTION__);
  return _defaultAssociations;
}

//--------------------------------------------------------------------
-(void)setDefaultAssociations:(NSDictionary*)defaultAssociations
{
  NSLog(@"WARNING: %s is not WebObjects API",__PRETTY_FUNCTION__);
  ASSIGN(_defaultAssociations,defaultAssociations);
}

//--------------------------------------------------------------------
-(GSWAssociation*)defaultAssociationForKey:(NSString*)key
{
  NSLog(@"WARNING: %s is not WebObjects API",__PRETTY_FUNCTION__);

  return [[self defaultAssociations]objectForKey:key];
}

// }


//--------------------------------------------------------------------
//setCachingEnabled:
-(void)setCachingEnabled:(BOOL)caching
{
  _isCachingEnabled=caching;
}

//--------------------------------------------------------------------
//isCachingEnabled
-(BOOL)isCachingEnabled 
{
  return _isCachingEnabled;
}

//--------------------------------------------------------------------
-(void) _setParent:(GSWComponent*) parent
      associations:(NSMutableDictionary *) assocdict
          template:(GSWElement*) template
{
  if (parent != _parent)
    _parent = parent;
  
  if (assocdict != _keyAssociations)
    ASSIGN(_keyAssociations, assocdict);    
  
  if (template != _childTemplate)
    ASSIGN(_childTemplate,template);
}

//--------------------------------------------------------------------
-(void) _doPushValuesUp
{
  if (_isSynchronized && (_keyAssociations != nil))
    {
      NSEnumerator* enumer = [_keyAssociations keyEnumerator];
      NSString* aKey = nil;
      while ((aKey = [enumer nextObject]))
	{
	   GSWAssociation* assoc = [_keyAssociations objectForKey: aKey];
	  if ([assoc isValueSettableInComponent:self])
	    {
	      [assoc setValue:[self valueForKey: aKey]
		     inComponent:_parent];
	    }
	}
    }
}

-(void) pushValuesToParent
{
  GSWComponentDefinition * componentdefinition = nil;
  
  if (_isSynchronized)
    {
      [self _doPushValuesUp];
    }
  componentdefinition = [self _componentDefinition];
  if ([componentdefinition isStateless])
    {
      [self reset];
      _parent = nil;  // no retain? dw
      _session = nil;
      DESTROY(_context);
      [componentdefinition _checkInComponentInstance:self];
    }
}

-(void)synchronizeComponentToParent
{
  NSLog(@"WARNING: %s is deprecated. Use pushValuesToParent instead.", __PRETTY_FUNCTION__);
  [self pushValuesToParent];
}

//--------------------------------------------------------------------
-(void) pullValuesFromParent
{
  if (_isSynchronized
      && _keyAssociations != nil)
    {
      NSEnumerator* enumer = [_keyAssociations keyEnumerator];
      NSString* aKey = nil;
      while ((aKey = [enumer nextObject]))
	{
	  GSWAssociation* assoc = [_keyAssociations objectForKey: aKey];
	  id obj = [assoc valueInComponent:_parent];        
	  [self setValue: obj
		forKey: aKey];
	}
    }
}

-(void) synchronizeParentToComponent
{
//  NSLog(@"WARNING: %s is deprecated. Use pullValuesFromParent instead.", __PRETTY_FUNCTION__);
  [self pullValuesFromParent];
}

//--------------------------------------------------------------------
-(GSWElement*)_childTemplate
{
  return _childTemplate;
}

//--------------------------------------------------------------------
-(GSWElement*) template
{
  GSWElement* element = nil;
  if (_template != element)
    element = _template;
  else 
    {
      element = [self templateWithName:nil];
      if ([self isCachingEnabled])
        ASSIGN(_template, element);
    }
  return element;
}

//--------------------------------------------------------------------
-(GSWElement*)_template
{
  NSLog(@"WARNING: %s is deprecated. Use template instead.", __PRETTY_FUNCTION__);

  return [self template];
}

//--------------------------------------------------------------------
-(GSWComponentDefinition*)_componentDefinition
{
  GSWComponentDefinition* aComponentDefinition=nil;

  if (_componentDefinition)
    aComponentDefinition=_componentDefinition;
  else
    {
      NSArray* languages=[self languages];
      aComponentDefinition=[GSWApp _componentDefinitionWithName:_name
				   languages:languages];
      if ([self isCachingEnabled])
        ASSIGN(_componentDefinition,aComponentDefinition);      
    }
  return aComponentDefinition;
}

//--------------------------------------------------------------------
-(NSString*)_templateName
{
  return _templateName;
}

//--------------------------------------------------------------------
-(NSString*)declarationName
{
  return _templateName;
}

//--------------------------------------------------------------------
-(BOOL)_isPage
{
  return _isPage;
}

//--------------------------------------------------------------------
-(void)_setIsPage:(BOOL)isPage
{
  _isPage=isPage;
}

//--------------------------------------------------------------------
-(void)_setContext:(GSWContext*)aContext
{
  // Verified with WO 4.5. We DO retain!
  ASSIGN(_context, aContext);
}


//--------------------------------------------------------------------
//	templateWithName:

// templateWithName is deprecated but I do not know in which version of WO
// MGuesdon;: still exists in 5.0

-(GSWElement*)templateWithName:(NSString*)aName
{
  return [[self _componentDefinition] template];
}

//--------------------------------------------------------------------
-(GSWComponent*)subComponentForElementID:(NSString*)elementId
{
  return [_subComponents objectForKey:elementId];
}

//--------------------------------------------------------------------
-(void)_setSubcomponent:(GSWComponent*)component
           forElementID:(NSString*)elementId
{
  if (!_subComponents)
    _subComponents=[NSMutableDictionary new];
  [_subComponents setObject:component
                  forKey:elementId];
}

//--------------------------------------------------------------------
//NDFN
-(void)makeParentsPerformSelectorIfPossible:(SEL)aSelector
{
  [[self parents] makeObjectsPerformSelectorIfPossible:aSelector];
}

//--------------------------------------------------------------------
//NDFN
-(void)makeParentsPerformSelectorIfPossible:(SEL)aSelector
                                 withObject:(id)object
{
  [[self parents] makeObjectsPerformSelectorIfPossible:aSelector
		  withObject:object];
}

//--------------------------------------------------------------------
//NDFN
-(void)makeParentsPerformSelectorIfPossible:(SEL)aSelector
                                 withObject:(id)object1
                                 withObject:(id)object2
{
  [[self parents] makeObjectsPerformSelectorIfPossible:aSelector
		  withObject:object1
		  withObject:object2];

}

//--------------------------------------------------------------------
//NDFN
-(id)makeAParentPerformSelectorIfPossible:(SEL)aSelector
{
  id retValue=nil;
  GSWComponent* obj=[self parent];

  while(obj)
    {
      if ([obj respondsToSelector:aSelector])
	{
	  retValue=[obj performSelector:aSelector];
	  obj=nil;
	}
      else
	obj=[obj parent];
    }

  return retValue;
}

//--------------------------------------------------------------------
//NDFN
-(id)makeAParentPerformSelectorIfPossible:(SEL)aSelector
                               withObject:(id)object
{
  id retValue=nil;
  GSWComponent* obj=[self parent];

  while(obj)
    {
      if ([obj respondsToSelector:aSelector])
	{
	  retValue=[obj performSelector:aSelector
                        withObject:object];
	  obj=nil;
	}
      else
	obj=[obj parent];
    }

  return retValue;
}

//--------------------------------------------------------------------
//NDFN
-(id)makeAParentPerformSelectorIfPossible:(SEL)aSelector
                               withObject:(id)object1
                               withObject:(id)object2
{
  id retValue=nil;
  GSWComponent* obj=[self parent];

  while(obj)
    {
      if ([obj respondsToSelector:aSelector])
	{
	  retValue=[obj performSelector:aSelector
			 withObject:object1
			 withObject:object2];
	  obj=nil;
	}
      else
	obj=[obj parent];
    }

  return retValue;
}

//--------------------------------------------------------------------
//NDFN
-(void)makeSubComponentsPerformSelectorIfPossible:(SEL)aSelector
{
  NSEnumerator* enumerator=nil;
  GSWComponent* component=nil;

  enumerator= [_subComponents objectEnumerator];    
  while ((component=[enumerator nextObject]))
    {
      [component performSelectorIfPossible:aSelector];
      [component makeSubComponentsPerformSelectorIfPossible:aSelector];
    }
}

//--------------------------------------------------------------------
//NDFN
-(void)makeSubComponentsPerformSelectorIfPossible:(SEL)aSelector
                                       withObject:(id)object
{
  NSEnumerator* enumerator=[_subComponents objectEnumerator];    
  GSWComponent* component=nil;

  while ((component=[enumerator nextObject]))
    {
      [component performSelectorIfPossible:aSelector
                 withObject:object];
      [component makeSubComponentsPerformSelectorIfPossible:aSelector
                 withObject:object];
    }
}

//--------------------------------------------------------------------
//NDFN
-(void)makeSubComponentsPerformSelectorIfPossible:(SEL)aSelector
                                       withObject:(id)object1
                                       withObject:(id)object2
{
  NSEnumerator* enumerator=[_subComponents objectEnumerator];    
  GSWComponent* component=nil;

  while ((component=[enumerator nextObject]))
    {
      [component performSelectorIfPossible:aSelector
		 withObject:object1
		 withObject:object2];
      [component makeSubComponentsPerformSelectorIfPossible:aSelector
		 withObject:object1
		 withObject:object2];
    }
}


//PRIVATE
-(GSWComponent*) _subcomponentForElementWithID:(NSString*) str
{
  if (_subComponents != nil
      && str != nil)
    return [_subComponents objectForKey:str];
  else
    return nil;
}

//--------------------------------------------------------------------
-(GSWAssociation*)_associationWithName:(NSString*)aName
{
  return [_keyAssociations objectForKey: aName];
}


//--------------------------------------------------------------------
-(BOOL)hasBinding:(NSString*)parentBindingName
{
  BOOL hasBinding = NO;
  GSWAssociation * association = [self _associationWithName: parentBindingName];

  hasBinding = (association != nil);
  if (hasBinding)
    hasBinding = [association _hasBindingInParent:_parent];
  
  return hasBinding;
}

//--------------------------------------------------------------------
-(void)setValue:(id)value
     forBinding:(NSString*)parentBindingName
{
  if (_parent)
    {
      GSWAssociation* assoc=[self _associationWithName:parentBindingName];
      if(assoc)
	[assoc setValue:value
	       inComponent:_parent];
    }
}

//--------------------------------------------------------------------
-(id)valueForBinding:(NSString*)parentBindingName
{
  id aValue=nil;
  if (_parent)
    {
      GSWAssociation* assoc=[self _associationWithName:parentBindingName];
      if(assoc)
	aValue=[assoc valueInComponent:_parent];
    }
  
  return aValue; 
}

//--------------------------------------------------------------------
//NDFN
/** Do we need to synchronize parent to component **/
-(BOOL)synchronizesParentToComponentVariablesWithBindings
{
  //OK
  NSDictionary* userDictionary=nil;
  id synchronizesParentToComponentVariablesWithBindingsValue=nil;
  BOOL synchronizesParentToComponentVariablesWithBindings=YES;

  userDictionary=[self userDictionary];
  synchronizesParentToComponentVariablesWithBindingsValue=[userDictionary objectForKey:@"synchronizesParentToComponentVariablesWithBindings"];

  //NDFN
  if (synchronizesParentToComponentVariablesWithBindingsValue)
    {
      synchronizesParentToComponentVariablesWithBindings=[synchronizesParentToComponentVariablesWithBindingsValue boolValue];
    }
  else
    synchronizesParentToComponentVariablesWithBindings=[self synchronizesVariablesWithBindings];

  return synchronizesParentToComponentVariablesWithBindings;
}

//--------------------------------------------------------------------
-(BOOL)synchronizesVariablesWithBindings
{
   return (![self isStateless]);
}

//--------------------------------------------------------------------
-(BOOL) isStateless
{
  return NO;
}


//--------------------------------------------------------------------
//NDFN
-(NSDictionary*)bindingAssociations
{
  return _keyAssociations;
}


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

-(void)sleep 
{
  //Does Nothing
}

//--------------------------------------------------------------------
-(void)sleepInContext:(GSWContext*)aContext
{
  //OK
  GSWComponentDefinition* aComponentDefinition=nil;
  NS_DURING
    {      
      aComponentDefinition=[self _componentDefinition];
      [aComponentDefinition sleep];
      [self sleep];
      [self _setContext:nil];
      [_subComponents makeObjectsPerformSelector:@selector(sleepInContext:)
                     withObject:aContext];
    }
  NS_HANDLER
    {
      localException=ExceptionByAddingUserInfoObjectFrameInfo0(localException,@"In sleepInContext:");
      [localException raise];
    }
  NS_ENDHANDLER;
}

//--------------------------------------------------------------------
//	appendToResponse:inContext:

-(void)appendToResponse:(GSWResponse*)aResponse
              inContext:(GSWContext*)aContext 
{
  GSWElement * element    = nil;
  
  [aContext _setResponse: aResponse];
  element = [self template];
    
  if (element != nil) 
    {
      GSWComponent * component = nil;
      if ([self parent] == nil
	  && [aContext page] != self)
	{
	  component = [aContext component];
	  [aContext _setCurrentComponent:self];
	}
      [element appendToResponse: aResponse 
	       inContext: aContext];
      if (component != nil)
	{
	  [aContext _setCurrentComponent: component];
	}
    }
}


//--------------------------------------------------------------------
-(id <GSWActionResults>) invokeActionForRequest:(GSWRequest*)aRequest
                                      inContext:(GSWContext*)aContext
{
  id <GSWActionResults>   results = nil;
  
  NS_DURING
    {
      GSWElement* template = [self template];
      if (template != nil) 
	{
	  if ([template class] != GSWHTMLBareStringClass) 
	    {
	      results = [template invokeActionForRequest:aRequest
				  inContext:aContext];
	    }
	}
    }
  NS_HANDLER
    {
      localException=ExceptionByAddingUserInfoObjectFrameInfo(localException,
							      @"In %s", __PRETTY_FUNCTION__);
      [localException raise];
    }
  NS_ENDHANDLER;
    
  return results;
}


//--------------------------------------------------------------------
//	takeValuesFromRequest:inContext:

-(void)takeValuesFromRequest:(GSWRequest*)aRequest
                   inContext:(GSWContext*)aContext 
{
  //OK
  GSWElement* template=nil;
  GSWDeclareDebugElementIDsCount(aContext);
  GSWDeclareDebugElementID(aContext);

  GSWStartElement(aContext);
  GSWAssertCorrectElementID(aContext);

  template=[self template];

  [template takeValuesFromRequest:aRequest
			 inContext:aContext];

  GSWStopElement(aContext);
  GSWAssertDebugElementID(aContext);

  GSWAssertIsElementID(aContext);
  GSWAssertDebugElementIDsCount(aContext);
}

//--------------------------------------------------------------------
-(void) _awakeInContext:(GSWContext*)aContext
{
  GSWComponentDefinition* componentdefinition =nil;
  
  [self _setContext:aContext];

  componentdefinition = [self _componentDefinition];
  [componentdefinition setCachingEnabled:[self isCachingEnabled]];
  [componentdefinition awake];

  if (_subComponents)
    {
      [_subComponents makeObjectsPerformSelector:@selector(_awakeInContext:)
		      withObject:aContext];
    }

  _session = nil;
  [self awake];
}

/*
Makes sure that the receiver is awake in aContext. 
Call this method before using a component which was cached in a variable.
*/

-(void)ensureAwakeInContext:(GSWContext*)aContext
{
  if ([self context] != aContext)
    [self _awakeInContext:aContext];
}

//--------------------------------------------------------------------
-(void) reset
{
  //Does Nothing
}

-(void)awake 
{
  //Does Nothing
}

-(void)awakeInContext:(GSWContext*)aContext
{
  NSLog(@"WARNING: %s is deprecated. Use _awakeInContext: instead.", __PRETTY_FUNCTION__);
  [self _awakeInContext:aContext];
}


- (id<GSWActionResults>)performParentAction:(NSString *)attribute
{
  GSWContext       *context = nil;
  GSWComponent     *component = _parent;
  id<GSWActionResults> actionresults = nil;
  
  if (!_parent)
    return nil;
  
  [context _setCurrentComponent:_parent];  
  [self pushValuesToParent];
  _parent = component;            // get the _parent back.

  context = [self context];  // we do NOT use the iVar to enable fancy subclass magic.
  NS_DURING
    {
      actionresults = [_parent valueForKey: attribute];
    }
  NS_HANDLER
    {
      localException=[localException exceptionByAddingUserInfoFrameInfoFormat:@"In %s",
                                                                          __PRETTY_FUNCTION__];
      [localException raise];    
    }
  NS_ENDHANDLER;
  [self pullValuesFromParent];
  [context _setCurrentComponent:self];  

  return actionresults;
}

//--------------------------------------------------------------------
-(GSWComponent*)parent
{
  return _parent;
}

//--------------------------------------------------------------------
//NDFN
-(GSWComponent*)topParent
{
  GSWComponent* parent=[self parent];
  GSWComponent* topParent=parent;
  while (parent)
    {
      topParent=parent;
      parent=[parent parent];
    }
  return topParent;
}

//--------------------------------------------------------------------
//NDFN
-(NSArray*)parents
{
  NSMutableArray* parents=[NSMutableArray array];
  GSWComponent* parent=[self parent];
  while (parent)
    {
      [parents addObject:parent];
      parent=[parent parent];
    }
  return [NSArray arrayWithArray:parents];
}

//--------------------------------------------------------------------
//NDFN
-(NSArray*)parentsClasses
{
  NSMutableArray* parents=[NSMutableArray array];
  GSWComponent* parent=[self parent];
  while (parent)
    {
      [parents addObject:[parent class]];
      parent=[parent parent];
    }
  return [NSArray arrayWithArray:parents];
}

-(GSWComponent*)pageWithName:(NSString*)aName
{
  GSWComponent* page=nil;
  GSWContext* aContext=nil;

  aContext=[self context];
  page=[GSWApp pageWithName:aName
               inContext:aContext];

  return page;
}

//--------------------------------------------------------------------
//	session

-(GSWSession*)session 
{
  GSWSession* session=nil;
  if (_session)
    session=_session;
  else if (_context)
    session=[_context session];
  return session;
}

//--------------------------------------------------------------------
-(BOOL)hasSession
{
  return (_session!=nil);
}

//--------------------------------------------------------------------
//	application

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

//--------------------------------------------------------------------
//	context

-(GSWContext*)context 
{
  GSWContext * ctx = nil;

  if (_context == nil
      && _session != nil)
    {
      if ((ctx = [_session context]))
	{
	  [self _awakeInContext: ctx];
	  [_context _takeAwakeComponent:self];
	}
    }
  return _context;
}

//--------------------------------------------------------------------
//NDFN
-(NSArray*)languages
{
  return [[self context] languages];
}

//--------------------------------------------------------------------
//Called when an Enterprise Object or formatter failed validation during an
//assignment. 
//The default implementation ignores the error. Subclassers can override to
// record the error and possibly return a different page for the current action.

- (void) validationFailedWithException:(NSException *)exception
                                 value:(id)value
                               keyPath:(NSString *)keyPath
{
  // FIXME: check if that code is in WO4.x
  /*
  if ([self hasSession]) {
    [[self session] validationFailedWithException:exception
                                            value:value
                                          keyPath:keyPath
                                        component:self];
  } else {
   [GSWApp validationFailedWithException:exception
                                   value:value
                                 keyPath:keyPath
                               component:self
                                 session:null];
  }
  */
}

//--------------------------------------------------------------------
-(void)_debugWithString:(NSString*)string
{
  [self notImplemented: _cmd];	//TODOFN
/* Seems there's a problem with patches... Why this code is here ?
   if (![self context])
     {
       NSDebugMLLog(@"GSWComponent",@"component sleeps, we awake it = %@",self);
       [self awakeInContext:aContext];
     }
   else
     {
       if ([self context] != aContext)
         { 
           NSDebugMLLog(@"GSWComponent",@"component is already awaken, but has not the current context, we awake it twice with current context = %@",self);
           [self awakeInContext:aContext];
         }
     }
*/
}

//--------------------------------------------------------------------
-(void)debugWithFormat:(NSString*)aFormat,...
{
  [self notImplemented: _cmd];	//TODOFN
}

//--------------------------------------------------------------------
+(void)logWithFormat:(NSString*)aFormat,...
{
  va_list ap;
  va_start(ap,aFormat);
  [[GSWApplication application] logWithFormat:aFormat
                                arguments:ap];
  va_end(ap);
}

//--------------------------------------------------------------------
-(void)_appendPageToResponse:(GSWResponse*)response
                   inContext:(GSWContext*)aContext
{
  NSAssert(aContext,@"No context");
  NS_DURING
    {    
      GSWSession* session=nil;
      NSString* httpVersion=@"HTTP/1.0";
      GSWElement* pageElement=nil;
      BOOL pageChanged=NO;  
      GSWRequest* request=[aContext request];

      GSWContext_deleteAllElementIDComponents(aContext);

      if (request != nil)
        httpVersion = [request httpVersion];
      
      [response setHTTPVersion:httpVersion];
      [response setHeader:@"text/html"
                forKey:GSWHTTPHeader_ContentType];
      [aContext _setResponse:response];

      pageElement=[aContext _pageElement];

      pageChanged=(self!=(GSWComponent*)pageElement);
      [aContext _setPageChanged:pageChanged];

      if (pageChanged)
        [aContext _setPageElement:self];

      [aContext _setCurrentComponent:self];

      [self appendToResponse:response
            inContext:aContext];

      session=[aContext _session];

      if (session)
	{
          [session appendCookieToResponse:response];
          [session _saveCurrentPage];
	}

      [aContext _incrementContextID];
      GSWContext_deleteAllElementIDComponents(aContext);
      [aContext _setPageChanged:YES];
    }
  NS_HANDLER
    {
    NSLog(@"localException is %@", localException);                    

      localException=ExceptionByAddingUserInfoObjectFrameInfo0(localException,
                                                               @"in GSWComponent -_generateResponseInContext:");      
      [localException raise];
    }
  NS_ENDHANDLER;
  
}

//--------------------------------------------------------------------
-(GSWResponse*)_generateResponseInContext:(GSWContext*)aContext
{
  GSWResponse* response=nil;

  NSAssert(aContext,@"No context");
  
  response=[GSWApp createResponseInContext:aContext];
  
  [self _appendPageToResponse:response
                    inContext:aContext];
        
  return response;
}

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

// actually this is wrong. it should call the validateValue:forKey: of the default implementation
// as such it should call the validateXXX stuff like EOs do. dave@turbocat.de

-(NSException*)validateValue:(id*)valuePtr
                      forKey:(NSString*)key
{
  NSException* exception=nil;
/*
  // Should all default implementation (i.e. the one which call validateXX:
  exception=[super validateValue:valuePtr
                   forKey:key];
*/
  return exception;
}

/**
 * This method is called to validate and potentially coerce
 * VALUE for the receivers key path.  This method also assigns
 * the value if it is different from the current value.
 * This method will raise an EOValidationException
 * if validateValue:forKeyPath:error: returns an error.
 * This method returns new value.
 **/
- (id)validateTakeValue:(id)value
	     forKeyPath:(NSString *)path
{
  if (!path)
    {
      [NSException raise:NSInvalidArgumentException
		   format:@"keyPath must not be nil"];
    }
  else
    {    
      NSError   * outError = nil;
      NSString  * validatePath = path;
      id targetObject = self;
      
      NSRange dotRange = [path rangeOfString:@"."
			       options:NSBackwardsSearch];
    
      if (dotRange.location != NSNotFound)
	{
	  NSString * newPath = [path substringToIndex:dotRange.location];
      
	  targetObject = [self valueForKeyPath:newPath];
      
	  if (!targetObject)
	    {
	      // If there is no object to set a value, we cannot do any validation.
	      // There is nothing to set on a non-existing object, so just go.
	      return nil;
	    }
      
	  // 1 is the length of the "."
	  validatePath = [path substringFromIndex: dotRange.location+1];
	}
    
      if ([targetObject validateValue:&value 
			forKeyPath:validatePath 
			error:&outError])
	{
	  id oldValue=[self valueForKeyPath:path];
	  if (SBIsValueEqual(oldValue,value)==NO)
	    {
	      //Set it if it differ from previous value
	      [self setValue:value
		    forKeyPath:path];
	    }
	  return value;
	}
      else
	{
	  NSString  * errorStr = @"unknown reason";
	  NSException  * exception=nil;
	  NSDictionary * uInfo = nil;
      
	  uInfo = [NSDictionary dictionaryWithObjectsAndKeys:
				  (value ? value : (id)@"nil"), @"EOValidatedObjectUserInfoKey",
				path, @"EOValidatedPropertyUserInfoKey",
				nil];
	  
	  if (outError
	      && [outError userInfo])
	    {
	      errorStr = [[outError userInfo] valueForKey:NSLocalizedDescriptionKey];
	    }
      
	  exception=[NSException exceptionWithName:@"EOValidationException"
				 reason:errorStr
				 userInfo:uInfo];
      
	  [exception raise];
	}
    }
  
  return value;
}

//--------------------------------------------------------------------
//	urlForResourceNamed:ofType:

-(NSString*)urlForResourceNamed:(NSString*)aName
                         ofType:(NSString*)type
{
  NSString* url = nil;
    
  GSOnceMLog(@"%s is deprecated in WO 4.0. Use GSWResourceManager’s implementation of "
	     @"urlForResourceNamed:inFramework:languages:request: "
	     @"instead.",
	     __PRETTY_FUNCTION__);
  
  url=[[GSWApp resourceManager] urlForResourceNamed:aName
				inFramework:nil
				languages:[self languages]
				request:nil];
  
  return url;
}

//--------------------------------------------------------------------
-(NSString*)pathForResourceNamed:(NSString*)aName
                          ofType:(NSString*)type
{
  NSString* path=nil;
  
  GSOnceMLog(@"%s is deprecated in WO 4.0. Use GSWResourceManager’s implementation of "
             @"pathForResourceNamed:inFramework:languages: " 
             @"instead.",
             __PRETTY_FUNCTION__);

  path=[[GSWApp resourceManager] pathForResourceNamed:aName
                                          inFramework:nil
                                            languages:[self languages]];
  
  return path;
}


//--------------------------------------------------------------------
//	templateWithHTMLString:declarationString:languages

//--------------------------------------------------------------------
+(GSWElement*)templateWithHTMLString:(NSString*)htmlString
                   declarationString:(NSString*)pageDefString
                           languages:(NSArray*)languages
{
  return [GSWTemplateParser templateWithHTMLString:htmlString
			    declarationString:pageDefString
			    languages:languages];
}

//--------------------------------------------------------------------
//	templateWithHTMLString:declarationString:
+(GSWElement*)templateWithHTMLString:(NSString*)htmlString
                   declarationString:(NSString*)pageDefString
{
  GSOnceMLog(@"%s is deprecated in WO 4.0. Use "
             @"templateWithHTMLString:declarationString:languages:" 
             @"instead.",
             __PRETTY_FUNCTION__);
  
  return [self templateWithHTMLString:htmlString
               declarationString:pageDefString
               languages:nil];
}



//--------------------------------------------------------------------
-(GSWResponse*)generateResponse
{
  return [self _generateResponseInContext: [self context]];
}


//--------------------------------------------------------------------
//	descriptionForResponse:inContext:

-(NSString*)descriptionForResponse:(GSWResponse*)aResponse
                         inContext:(GSWContext*)aContext 
{
  return _name;
}

//--------------------------------------------------------------------
- (WOMarkupType) markupType
{
  return WOHTML401Markup;
}

//--------------------------------------------------------------------
+(void)_registerObserver:(id)observer
{
  [self notImplemented: _cmd];	//TODOFN
}

//--------------------------------------------------------------------
-(id)   unarchiver: (WOKeyValueUnarchiver*)archiver
objectForReference: (id)keyPath
{  
  if ([keyPath isKindOfClass:[NSString class]])
    {
      return [self valueForKeyPath:keyPath];
    }
  return nil;
}

@end

