Logo Search packages:      
Sourcecode: adun.app version File versions  Download package

AdunSystemNode.m

/*
   Project: Adun

   Copyright (C) 2005 Michael Johnston & Jordi Villa-Freixa

   Author: Michael Johnston

   This application is free software; you can redistribute it and/or
   modify it under the terms of the GNU General Public
   License as published by the Free Software Foundation; either
   version 2 of the License, or (at your option) any later version.

   This application 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 General Public
   License along with this library; if not, write to the Free
   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA.
*/
#include "AdunKernel/AdunSystemNode.h"

/**
Private category for handling relationships
*/
00027 @interface AdSystemNode (SystemRelationshipHandling)
- (void) initRelationshipVariables;
- (void) deallocRelationshipVariables;
- (BOOL) validateRelationship: (AdRelationship*) relationshipObject 
      forSystems: (NSArray*) systems 
      error: (NSError**) error;
- (BOOL) validateRelationship: (AdRelationship*) aRelationship error: (NSError**) error;
- (BOOL) validateRelationships: (NSArray*) anArray error: (NSError**) error;
- (id) _interactionSystemForRelationship: (AdRelationship*) relationshipObject;
- (id) _relationshipForInteractionSystem: (AdInteractionSystem*) system;
- (NSArray*) _relationshipsForSystemWithName: (NSString*) aName ofType: (NSString*) relationshipType;
- (NSArray*) _relationshipsForSystemWithName: (NSString*) aName;
- (void) _addRelationship: (AdRelationship*) aRelationship;
- (void) _removeRelationship: (AdRelationship*) aRelationship;
@end

/**
Private category for handling system status
*/
00046 @interface AdSystemNode (SystemStatusObservation)
- (void) initStatusVariables;
- (void) deallocStatusVariables;
- (void) removeSystemFromStatusObservation: (id) aSystem;
- (void) observeStatusOfSystem: (id) aSystem;
@end

00053 @implementation AdSystemNode

- (BOOL) _validateNamesOfSystems: (NSArray*) anArray error: (NSError**) error
{
      NSMutableArray* nameArray = [NSMutableArray array];
      NSEnumerator* arrayEnum, *subsystemNamesEnum;
      NSString* aString;
      id system, name;

      //first check all the systems in anArray have unique names
      
      arrayEnum = [anArray objectEnumerator];
      while(system = [arrayEnum nextObject])
            if([nameArray containsObject: [system systemName]])
            {
                  //create an error object
                  
                  aString = [NSString stringWithFormat: @"Name %@ invalid", 
                              [system systemName]];
                  *error = AdKnownExceptionError(10, aString, nil, nil);      
            
                  return NO;
            }     
            else
                  [nameArray addObject:[system systemName]];

      //now check against all systems already in the node

      subsystemNamesEnum = [systemNames keyEnumerator];
      while(name = [subsystemNamesEnum nextObject])
            if([nameArray containsObject: name])
            {
                  //create an error object
                  aString = [NSString stringWithFormat: @"Name %@ invalid", 
                              name];
                  *error = AdKnownExceptionError(10, aString, nil, nil);      
                  
                  return NO;
            }

      return YES;
}

/*******************

Object Creation and Maintainence

********************/

//Temporary method so interaction systems AdSystemNode creates can be initialised from the
//environment - wont be necessary after AdSystemNode itself can be inititalised from the environment
- (id) initWithSystems: (NSArray*) arrayOne relationships: (NSArray*) arrayTwo environment: (id) object
{
      environment = object;
      return [self initWithSystems: arrayOne relationships: arrayTwo];
}

//designated initialiser
//FIXME: Due to SCAAS still relying on solute solvent distinction 
//the solute system must be first in arrayOne at the moment

- (id) initWithSystems: (NSArray*) arrayOne relationships: (NSArray*) arrayTwo
{
      id subsystem, relationship, object;
      NSEnumerator* subsystemEnum, *relationshipEnum, *arrayOneEnum;
      NSError* error;
      NSException *exception;
      NSMutableDictionary* userInfo;

      //initialisation chain will change soon - this is a hack
      if((self = [super initWithEnvironment: environment observe: NO]))
      {           
            //check that the contents of arrayOne are AdSystems
            arrayOneEnum = [arrayOne objectEnumerator];
            while((object = [arrayOneEnum nextObject]))
                  if(![object isKindOfClass: [AdSystem class]])
                        [NSException raise: NSInvalidArgumentException
                              format: @"Incompatible object type for subsystem (%@).",
                              [object description]];
            error = nil;
            [self initRelationshipVariables];
            //check that each system has a unique name
            if([self _validateNamesOfSystems: arrayOne 
                  error: &error])
            {
                  systems = [arrayOne mutableCopy];
                  //get the system names
                  systemNames = [NSMutableDictionary new];
                  subsystemEnum = [systems objectEnumerator];
                  while(subsystem = [subsystemEnum nextObject])
                  {
                        [systemNames setObject: subsystem
                              forKey: [subsystem systemName]];
                        [systemRelationshipsDict setObject: [NSMutableArray array] 
                              forKey: [subsystem systemName]];
                   }          
            }
            else
            {
                  //autorelease ourself since no one will have a
                  //reference to us
                  [self autorelease];
                  if(error != nil)
                        userInfo = [NSDictionary dictionaryWithObject: error
                                    forKey: @"AdKnownExceptionError"];
                  else
                        userInfo = nil;
                        
                  exception = [NSException 
                              exceptionWithName: NSInternalInconsistencyException
                              reason: @"Detected system with non-unique name."
                              userInfo: userInfo];
                  [exception raise];
            }

            //we use validateRelationships:error as this will check the
            //relationships against the systems that were added above

            if([self validateRelationships: arrayTwo
                  error: &error])
            {           
                  //create interaction systems + insert contents into containers
                  //based on relationships
                  //Add contain relationships first to avoid having to keep
                  //recreating AdInteractionSystems
                  systemRelationships = [arrayTwo mutableCopy];
                  relationshipEnum = [systemRelationships objectEnumerator];
                  // _addRelationship: (private method) adds the relationship
                  //and peforms the necessary interaction system creation or insertion
                  //however it performs no status related actions or validation (unlike the
                  //public addRelationship: method. 
                  while(relationship = [relationshipEnum nextObject])
                        if([[relationship relationship] isEqual: @"Contains"])
                              [self _addRelationship: relationship];

                  relationshipEnum = [systemRelationships objectEnumerator];
                  while(relationship = [relationshipEnum nextObject])
                        if([[relationship relationship] isEqual: @"Interacts"])
                              [self _addRelationship: relationship];
            }
            else
            {
                  [self autorelease];
                  if(error != nil)
                        userInfo = [NSDictionary dictionaryWithObject: error
                                    forKey: @"AdKnownExceptionError"];
                  else
                        userInfo = nil;

                  exception = [NSException 
                              exceptionWithName: NSInternalInconsistencyException
                              reason: @"Invalid relationship supplied."
                              userInfo: userInfo];
                  [exception raise];
            }

            //add the names of created AdInteractionSystems to systemNames
            //and add the interaction systems themselves to systems
            [systems addObjectsFromArray: interactionSystems];
            subsystemEnum = [interactionSystems objectEnumerator];
            while(subsystem = [subsystemEnum nextObject])
                  [systemNames setObject: subsystem forKey: [subsystem systemName]];

            //set up status variables
            [self initStatusVariables];
            subsystemEnum = [systems objectEnumerator];
            while(subsystem = [subsystemEnum nextObject])
                  [self observeStatusOfSystem: subsystem];
      }

      return self;
}

- (id) init
{
      return [self initWithSystems: nil relationships: nil];
}

//environment initialisers

00233 - (id) initWithEnvironment: (id) object observe: (BOOL) value
{
      if(environment != nil)
      {
            environment = object;
            //retrieve init arguments from environment

      /*    options = [environment optionsForDomain: @"AdSystemNode"];
            [self registerWithEnvironment];
            options = [environment optionsForDomain: @"AdSystemNode"];
            return [self initWithSubsystems: [options valueForKey:@"Subsystems"]
                        relationships: [options valueForKey:@"Relationships"]];*/
      }
      else
            return [self init];
}

00250 - (id) initWithEnvironment: (id) object
{
      return [self initWithEnvironment: object observe: YES];
}

- (void) dealloc
{
      [self deallocStatusVariables];
      [self deallocRelationshipVariables];
      [systemRelationships release];
      [systemNames release];
      [systems release];
      [super dealloc];
}

//addition and removal of systems and relationships

00267 - (void) removeSystemWithName: (NSString*) aName
{
      id subsystem, relationship;
      NSArray* relationships;
      NSEnumerator* relationshipEnum;

      //remove a system and all relationships its involved in.
      //behaviour of containers is object dependant.
      //if it is an interaction system this has the effect of removing
      //the interaction relationship

      subsystem = [systemNames valueForKey: aName];
      if([subsystem isKindOfClass: [AdInteractionSystem class]])
      {
            //get the relationship that created this interaction
            //and use removeRelationship: instead

            relationship = [self _relationshipForInteractionSystem: subsystem];
            [self _removeRelationship: relationship];
      }
      else
      {
            relationships = [self relationshipsForSystemWithName: aName];
            relationshipEnum = [relationships objectEnumerator];
            while(relationship = [relationshipEnum nextObject])
                  [self removeRelationship: relationship];

            [self removeSystemFromStatusObservation: subsystem];
            [systemRelationshipsDict removeObjectForKey: [subsystem systemName]];
            [systemNames removeObjectForKey: aName];
            [systems removeObject: subsystem];
       }    
}

00301 - (void) addSystem: (AdSystem*) aSystem 
      withRelationships: (NSArray*) relationships
{
      NSError* error = nil;
      NSEnumerator* relationshipEnum;
      NSMutableDictionary* userInfo;
      NSException* exception;
      id relationship;

      if(aSystem == nil)
            return;

      if([self _validateNamesOfSystems: [NSArray arrayWithObject: aSystem]
            error: &error])
      {     
            [systems addObject: aSystem];
            [systemNames setObject: aSystem forKey: [aSystem systemName]];
      }
      else
      {
            userInfo = [NSDictionary dictionaryWithObject: error
                        forKey: @"AdKnownExceptionError"];
            exception = [NSException 
                        exceptionWithName: NSInternalInconsistencyException
                        reason: @"Cannot add system - non-unique name"
                        userInfo: nil];
            [exception raise];
      }
      
      [systemRelationshipsDict setObject: [NSMutableArray array] 
            forKey: [aSystem systemName]];

      if(relationships != nil)
      {
            if([self validateRelationships: relationships error: &error])
            {
                  relationshipEnum = [relationships objectEnumerator];
                  while(relationship = [relationshipEnum nextObject])
                        [self addRelationship: relationship];
            }           
            else
            {
                  //remove the system and raise exception
                  [systemRelationshipsDict removeObjectForKey: [aSystem systemName]];
                  [systemNames removeObjectForKey: [aSystem systemName]];
                  [systems removeObject: aSystem];
                  userInfo = [NSDictionary dictionaryWithObject: error
                              forKey: @"AdKnownExceptionError"];
                  exception = [NSException 
                              exceptionWithName: NSInternalInconsistencyException
                              reason: @"Cannot add system - invalid relationship supplied."
                              userInfo: nil];
                  [exception raise];
            }     
      }
      
      //add the system to the status observation mechanism
      [self observeStatusOfSystem: aSystem];
}

00361 - (void) addRelationship: (AdRelationship*) relationshipObject
{
      id system;

      [self _addRelationship: relationshipObject];
      if([[relationshipObject relationship] isEqual: @"Interacts"])
      {
            system = [self _interactionSystemForRelationship: relationshipObject];
            [systemNames setObject: system forKey: [system systemName]];
            [self observeStatusOfSystem: system];
      }     
}

00374 - (void) removeRelationship: (AdRelationship*) relationshipObject
{
      id system;

      if([[relationshipObject relationship] isEqual: @"Interacts"])
      {
            system = [self _interactionSystemForRelationship: relationshipObject];
            [systemNames removeObjectForKey: [system systemName]];
            [self removeSystemFromStatusObservation: system];
      }     

      [self _removeRelationship: relationshipObject];
}

- (void) updateSystemsRelatedWithSystem: (AdSystem*) object
{
      //If a system reloads its data we have to update
      //interaction systems and containers.

}

/**********************

Protocols Methods

***********************/

/*
 * Environment observation
 */

00405 - (void) updateForKey: (NSString*) key value: (id) value object: (id) object
{
      //no updates as of yet
}

00410 - (void) registerWithEnvironment
{
      //nothing to register
}

00415 - (void) deregisterWithEnvironment
{
      //nothing to deregister
}

00420 - (void) synchroniseWithEnvironment
{
      //nothing to retrieve
}

00425 - (void) setEnvironment: (id) object
{
      [self deregisterWithEnvironment];
      object = environment;
      [self registerWithEnvironment];
}

- (void) frameUpdate
{
      [systems makeObjectsPerformSelector: @selector(frameUpdate)];
}

00437 - (void) update
{
      [systems makeObjectsPerformSelector: @selector(update)];
}

/********************

Coding 

*********************/

- (void) encodeWithCoder: (NSCoder*) encoder
{
      [super encodeWithCoder: encoder];
      if([encoder allowsKeyedCoding])
      {
            NSDebugLLog(@"Encode", @"Encoding %@", [self description]);
            [encoder encodeObject: systemRelationships forKey: @"SystemRelationships"];
            [encoder encodeObject: systems forKey: @"Subsystems"];
      }
      else
            [NSException raise: NSInvalidArgumentException
                  format: @"%@ class does not support non keyed coding", [self class]];
}

- (id) initWithCoder: (NSCoder*) decoder
{
      NSEnumerator* subsystemEnum, *relationshipEnum;
      id subsystem, relationship;

      self = [super initWithCoder: decoder];
      if([decoder allowsKeyedCoding])
      {
            systems = [[decoder decodeObjectForKey: @"Subsystems"] retain];
            systemRelationships = [decoder decodeObjectForKey: @"SystemRelationships"];
            [systemRelationships retain];
            
            [self initRelationshipVariables];
            systemNames = [NSMutableDictionary new];
            subsystemEnum = [systems objectEnumerator];
            while(subsystem = [subsystemEnum nextObject])
            {
                  [systemNames setObject: subsystem
                        forKey: [subsystem systemName]];
                  [systemRelationshipsDict setObject: [NSMutableArray array] 
                        forKey: [subsystem systemName]];
            }           

            relationshipEnum = [systemRelationships objectEnumerator];
            while(relationship = [relationshipEnum nextObject])
                  if([[relationship relationship] isEqual: @"Contains"])
                        [self _addRelationship: relationship];

            relationshipEnum = [systemRelationships objectEnumerator];
            while(relationship = [relationshipEnum nextObject])
                  if([[relationship relationship] isEqual: @"Interacts"])
                        [self _addRelationship: relationship];

            //set up status variables
            [self initStatusVariables];
            subsystemEnum = [systems objectEnumerator];
            while(subsystem = [subsystemEnum nextObject])
                  [self observeStatusOfSystem: subsystem];

            environment = [AdEnvironment globalEnvironment];
            if(environment != nil)
            {
                  [self synchroniseWithEnvironment];
                  [self registerWithEnvironment];
            }
      }
      else
            [NSException raise: NSInvalidArgumentException
                  format: @"%@ class does not support non keyed coding", [self class]];

      return self;
}

/**
  Accessing systems and relationships.
  Forward these to the methods of the private SystemRelationshipHandling category
**/

00520 - (id) interactionSystemForRelationship: (AdRelationship*) relationshipObject
{
      return [self _interactionSystemForRelationship: relationshipObject];
}     

00525 - (id) relationshipForInteractionSystem: (AdInteractionSystem*) interactionSystem
{
      return [self _relationshipForInteractionSystem: interactionSystem];
}     

00530 - (NSArray*) relationshipsForSystemWithName: (NSString*) aName
{
      return [self _relationshipsForSystemWithName: aName];
}

00535 - (NSArray*) relationshipsForSystemWithName: (NSString*) aName ofType: (NSString*) relationshipType
{
      return [self _relationshipsForSystemWithName: aName ofType: relationshipType];
}

00540 - (id) systemWithName: (NSString*) name
{
      return [systemNames objectForKey: name];
}

00545 - (BOOL) containsRelationship: (AdRelationship*) relationshipObject
{
      return [systemRelationships containsObject: relationshipObject];
}

- (NSArray*) allRelationships
{
      return [systemRelationships copy];
}


/*******************

Accessors

********************/

00562 - (NSArray*) activeSystems
{
      return activeSystems;
}

00567 - (NSArray*) passiveSystems
{
      return passiveSystems;
}

00572 - (NSArray*) inactiveSystems
{
      return inactiveSystems;
}

00577 - (NSArray*) systemsOfType: (NSString*) type withStatus: (NSString*) status
{
      NSArray* selectedSystems;
      NSMutableArray* derivedArray;
      NSEnumerator* systemEnum;
      Class class;
      id system;

      selectedSystems = [statusDict objectForKey: status];
      if(selectedSystems == nil)
            [NSException raise: NSInvalidArgumentException 
                  format: @"Unknown status %@", status];
      
      class = nil;
      if([type isEqual: @"Interaction"])
            class = [AdInteractionSystem class];
      else if([type isEqual: @"Standard"])
            class = [AdSystem class];
      else  
            [NSException raise: NSInvalidArgumentException 
                  format: @"Unknown type %@", type];

      derivedArray = [NSMutableArray array];
      systemEnum = [selectedSystems objectEnumerator];
      while(system = [systemEnum nextObject])
            if([system isKindOfClass: class])
                  [derivedArray addObject: system];

      return derivedArray;
}

00608 - (id) allSystems
{
      return systems;
}

- (id) interactionSystems
{
      return interactionSystems;
}

//FIXME Again with the assumptions - this method is in the process of being deprecated
//\note we need this for SCAAS
- (id) soluteSystem
{
      return [systems objectAtIndex: 0];
}

//FIXME Again with the assumptions
- (id) solventSystem
{
      return [systems objectAtIndex: 1];
}

@end

/**
Category containing methods use to monitor the
status of systems
*/

@implementation AdSystemNode (SystemStatusObservation)

- (void) initStatusVariables
{           
      activeSystems = [NSMutableArray new];
      passiveSystems = [NSMutableArray new];
      inactiveSystems = [NSMutableArray new];
      activeAdSystems = [NSMutableArray new];

      statusDict = [NSMutableDictionary new];
      [statusDict setObject: activeSystems forKey: @"Active"];
      [statusDict setObject: passiveSystems forKey: @"Passive"];
      [statusDict setObject: inactiveSystems forKey: @"Inactive"];
}

- (void) deallocStatusVariables
{
      [activeAdSystems release];
      [statusDict release];
      [activeSystems release];
      [inactiveSystems release];
      [passiveSystems release];
}

- (void) _updateSubsystemStatus: (NSNotification*) aNotification
{
      id system, interaction, relationship;
      NSEnumerator* interactionEnum;
      NSString* previousStatus, *currentStatus;
      NSMutableDictionary* infoDict;
      NSEnumerator* relationshipEnum;

      system = [aNotification object];
      previousStatus = [[aNotification userInfo] objectForKey: @"PreviousStatus"];  
      currentStatus = [[aNotification userInfo] objectForKey: @"CurrentStatus"];    

      [[statusDict objectForKey: previousStatus] removeObject: system];
      [[statusDict objectForKey: currentStatus] addObject: system];

      //NB. To avoid receiving this notification multiple times while performing the
      //status changes on any systems we should remove ourselves from
      //receiving notifications from them.
      
      if([system isKindOfClass: [AdSystem class]])
      {
            if([currentStatus isEqual: @"Active"])
                  [activeAdSystems addObject: system];
            else
                  [activeAdSystems removeObject: system];

            if([currentStatus isEqual: @"Inactive"])
            {
                  //If an AdSystem is made inactive we must deactivate 
                  //all the interaction systems its involved in.
            
                  relationshipEnum = [[self relationshipsForSystemWithName: [system systemName]
                                                ofType: @"Interacts"] 
                                          objectEnumerator];
                  while(relationship = [relationshipEnum nextObject])
                  {
                        interaction = [self _interactionSystemForRelationship: relationship];
                        [notificationCenter removeObserver: self
                              name: @"AdSystemStatusDidChangeNotification"
                              object: interaction];
                        [interaction setStatus: @"Inactive"];
                        [activeSystems removeObject: interaction];
                        [inactiveSystems addObject: interaction];
                        [notificationCenter addObserver: self
                              selector: @selector(_updateSubsystemStatus:)
                              name: @"AdSystemStatusDidChangeNotification"
                              object: interaction];
                  }
            }
      }

      //Send an AdSystemStatusDidChangeNotification for the original system

      infoDict = [NSMutableDictionary dictionaryWithDictionary: [aNotification userInfo]];
      [infoDict setObject: system forKey: @"Subsystem"];

      [notificationCenter 
            postNotificationName: @"AdSystemStatusDidChangeNotification"
            object: self
            userInfo: infoDict];
}

- (void) observeStatusOfSystem: (id) aSystem
{
      NSString* status;

      [notificationCenter addObserver: self
            selector: @selector(_updateSubsystemStatus:)
            name: @"AdSystemStatusDidChangeNotification"
            object: aSystem]; 

      //add to the correct array
      
      if([aSystem isKindOfClass: [AdSystem class]])
            status = [(AdSystem*)aSystem status];
      else
            status = [(AdInteractionSystem*)aSystem status];
            
      [[statusDict objectForKey: status]
            addObject: aSystem];

      if([aSystem isKindOfClass: [AdSystem class]])
            if([status isEqual: @"Active"])
                  [activeAdSystems addObject: aSystem];
}

- (void) removeSystemFromStatusObservation: (id) aSystem
{
      id status;

      [notificationCenter removeObserver: self
            name: @"AdSystemStatusDidChangeNotification"
            object: self];
      
      if([aSystem isKindOfClass: [AdSystem class]])
            status = [(AdSystem*)aSystem status];
      else
            status = [(AdInteractionSystem*)aSystem status];

      [[statusDict objectForKey: status]
            removeObject: aSystem];
      
      if([activeAdSystems containsObject: aSystem])
            [activeAdSystems removeObject: aSystem];
}

@end

/**
Category containing basic methods for adding and removing relationships
*/

@implementation AdSystemNode (SystemRelationshipHandling)

- (void) initRelationshipVariables
{
      interactionSystems = [NSMutableArray new];
      interactionDataSources = [NSMutableArray new];
      systemRelationshipsDict = [NSMutableDictionary new];
      allowedRelationships = [[NSArray alloc] initWithObjects:
                              @"Interacts",
                              @"Contains",
                              nil];
      //holds derivedSystemName:Relationship pairs
      //i.e. the relationship that caused the system to be created
      derivedSystemsDict = [NSMutableDictionary new];
}

- (void) deallocRelationshipVariables
{
      [interactionSystems release];
      [interactionDataSources release];
      [systemRelationshipsDict release];
      [allowedRelationships release];
      [derivedSystemsDict release];
}

- (id) _interactionSystemForRelationship: (AdRelationship*) relationshipObject
{
      NSArray* systems;
      NSEnumerator* systemEnum;
      id array, system;

      if([[relationshipObject relationship] isEqual: @"Interacts"])
      {
            //each interacts relationship can only created one interaction
            //system. Therefore we can use allKeysForObject on the 
            //derivedSystemsDict which should return an array with one
            //entry which is the interaction system

            array = [derivedSystemsDict allKeysForObject: relationshipObject];
            if([array count] == 1)
                  return [systemNames objectForKey: [array objectAtIndex: 0]];
            else
                  return nil;
      
      }
      else 
            return nil;
}

- (id) _relationshipForInteractionSystem: (AdInteractionSystem*) interaction
{
      return [derivedSystemsDict objectForKey: [interaction systemName]];
}

- (void) _removeRelationship: (AdRelationship*) relationshipObject 
{
      id system;

      //remove an interact or contains relationship
      //if the relationship doesnt exist do nothing         

      if(![systemRelationships containsObject: relationshipObject])
            return;

      if([[relationshipObject relationship] isEqual: @"Interacts"])
      {
            system = [self _interactionSystemForRelationship: relationshipObject];        
            [interactionSystems removeObject: system];
            [interactionDataSources removeObject: [system dataSource]];
            [derivedSystemsDict removeObjectForKey: [system systemName]];
      }
      else
      {
            //Nothing to do for contains relationships at the moment
      }
      
      [[systemRelationshipsDict objectForKey: [relationshipObject objects]]
            removeObject: relationshipObject];
      [[systemRelationshipsDict objectForKey: [relationshipObject subjects]]
            removeObject: relationshipObject];
}

- (void) _addRelationship: (AdRelationship*) relationshipObject
{
      AdInteractionSystem* newSystem;
      NSString* systemOneName, *systemTwoName;
      NSArray* dataSource;
      AdSystem* container, *contained;

      if([[relationshipObject relationship] isEqual: @"Interacts"])
      {
            //create interaction system
            newSystem = [[AdInteractionSystem alloc] 
                        initWithEnvironment: environment];
            [newSystem autorelease];
            systemOneName = [relationshipObject objects];
            systemTwoName = [relationshipObject subjects];
            dataSource = [NSArray arrayWithObjects: 
                              [systemNames objectForKey: systemOneName],
                              [systemNames objectForKey: systemTwoName],
                              nil];
            [newSystem setDataSource: dataSource];
            [newSystem reloadData];
            //AdInteractionSystem objects automatically create their own name
            //based on their datasources.
            [interactionDataSources addObject: dataSource];
            [interactionSystems addObject: newSystem];
            [derivedSystemsDict setObject: relationshipObject 
                  forKey: [newSystem systemName]];
      }
      else
      {     
            systemOneName = [relationshipObject subjects];
            systemTwoName = [relationshipObject objects];

            if([systemOneName isEqual:systemTwoName])
                  [NSException raise: NSInternalInconsistencyException
                        format: @"Subject and Object of relationship %@ are the same.",
                        [relationshipObject description]];
            
            container = [systemNames objectForKey: systemOneName];
            contained = [systemNames objectForKey: systemTwoName];
            
            //insert one into the other

            [[container dataSource] setExclusionPoints: [[contained coordinates] pointerValue]
                  exclusionRadius: 3.0];
            [container reloadData];
      }

      [[systemRelationshipsDict objectForKey: [relationshipObject objects]]
            addObject: relationshipObject];
      [[systemRelationshipsDict objectForKey: [relationshipObject subjects]]
            addObject: relationshipObject];
}

- (BOOL) validateRelationships: (NSArray*) anArray error: (NSError**) error
{
      NSEnumerator* relationshipEnum;
      id relationship;
      
      relationshipEnum = [anArray objectEnumerator];
      while(relationship = [relationshipEnum nextObject])
            if(![self validateRelationship: relationship error: error])
                  return NO;

      return YES;       
}

/**
Checks that \e aRelationship is valid with respect to the systems currently in the node
*/
00926 - (BOOL) validateRelationship: (AdRelationship*) relationshipObject error: (NSError**) error
{
      NSString* relationship, *aString;
      id subject, object;
      AdSystem *subjectSystem, *objectSystem;

      //check relationship is of a valid type

      relationship = [relationshipObject relationship];
      if(![allowedRelationships containsObject: relationship])
      {
            //create error    
            aString = [NSString stringWithFormat: 
                        @"The relationship defined by the relationship object (%@) is not supported.", 
                        [relationshipObject description]];
            *error = AdKnownExceptionError(10, aString, nil, nil);
            return NO;
      }

      if(![[relationshipObject type] isEqual: @"AdOneToOneRelationship"])
      {
            aString = [NSString stringWithFormat: 
                        @"AdSystemNode only supports one to one relationships."];
            *error = AdKnownExceptionError(10, aString, nil, nil);
            return NO;
      }

      //check that the subject and object are among the current systems
      
      subject = [relationshipObject subjects];
      object = [relationshipObject objects];
      if((subjectSystem = [systemNames objectForKey: subject]) == nil)
      {
            aString = [NSString stringWithFormat: 
                        @"Subject (%@) not among the current systems",
                        subject];
            *error = AdKnownExceptionError(10, aString, nil, nil);
            return NO;
      }

      if((objectSystem = [systemNames objectForKey: object]) == nil)
      {
            aString = [NSString stringWithFormat: 
                        @"Object (%@) not among the current systems array",
                        subject];
            *error = AdKnownExceptionError(10, aString, nil, nil);
            return NO;
      }

      //finally check if that the referenced systems are AdSystems

      if(![objectSystem isKindOfClass: [AdSystem class]])
      {     
            aString = [NSString stringWithFormat: 
                        @"System referenced by Object (%@) is not an AdSystem ",
                        subject];
            *error = AdKnownExceptionError(10, aString, nil, nil);
            return NO;
      }

      if(![subjectSystem isKindOfClass: [AdSystem class]])
      {
            aString = [NSString stringWithFormat: 
                        @"System referenced by Subject (%@) is not an AdSystem ",
                        subject];
            *error = AdKnownExceptionError(10, aString, nil, nil);
            return NO;
      }
      
      return YES; 
}

/**
Checks that the relationship is valid with respect to the systems supplied
*/
01001 - (BOOL) validateRelationship: (AdRelationship*) relationshipObject
      forSystems: (NSArray*) systemArray 
      error: (NSError**) error
{
      NSString* relationship, *aString;
      id subject, object, system;
      NSMutableArray* names;
      NSEnumerator* systemEnum;

      //check relationship is of a valid type

      relationship = [relationshipObject relationship];
      if(![allowedRelationships containsObject: relationship])
      {
            //create error    
            
            aString = [NSString stringWithFormat: 
                        @"The relationship defined by the relationship object (%@) is not supported.", 
                        [relationshipObject description]];
            *error = AdKnownExceptionError(10, aString, nil, nil);
            return NO;
      }

      //we only support one to one relationships
      if(![[relationshipObject type] isEqual: @"AdOneToOneRelationship"])
      {
            aString = [NSString stringWithFormat: 
                        @"AdSystemNode only supports one to one relationships."];
            *error = AdKnownExceptionError(10, aString, nil, nil);
            return NO;
      }
      
      //check all the objects in the systems array are AdSystem instances

      systemEnum = [systemArray objectEnumerator];
      names = [NSMutableArray array];
      while(system = [systemEnum nextObject])
      {
            if(![system isKindOfClass: [AdSystem class]])
            {
                  aString = [NSString stringWithFormat: 
                              @"Non AdSystem instance present in system array (%@)",
                              NSStringFromClass([system class])];
                  *error = AdKnownExceptionError(10, aString, nil, nil);
                  return NO;
            }
            [names addObject: [system systemName]];
      }     
      
      //check both subject and object are in the systems array

      subject = [relationshipObject subjects];
      object = [relationshipObject objects];
      if(![names containsObject: subject])
      {
            aString = [NSString stringWithFormat: 
                        @"Subject (%@) not present in system array",
                        subject];
            *error = AdKnownExceptionError(10, aString, nil, nil);
            return NO;
      }

      if(![names containsObject: object])
      {
            aString = [NSString stringWithFormat: 
                        @"Object (%@) not present in system array",
                        subject];
            *error = AdKnownExceptionError(10, aString, nil, nil);
            return NO;
      }

      return YES;
}

- (NSArray*) _relationshipsForSystemWithName: (NSString*) aName
{
      return [systemRelationshipsDict objectForKey: aName];
}

- (NSArray*) _relationshipsForSystemWithName: (NSString*) aName ofType: (NSString*) relationshipType
{
      NSArray* relationships;
      NSMutableArray* array;
      NSEnumerator* relationshipEnum;
      AdRelationship* relationship;
      
      array = [NSMutableArray array];
      relationships = [self relationshipsForSystemWithName: aName];
      relationshipEnum = [relationships objectEnumerator];
      while(relationship = [relationshipEnum nextObject])
            if([[relationship relationship] isEqual: relationshipType])
                  [array addObject: relationship];

      return array;
}

@end

Generated by  Doxygen 1.6.0   Back to index