/*
    ObjectGraph.m

    Implementation of the ObjectGraph class for the KeyArcher
    application.

    Copyright (C) 2006  Saso Kiselkov

    This program 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 program 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 General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
*/

#import "ObjectGraph.h"

#import <Foundation/NSArray.h>
#import <Foundation/NSDictionary.h>
#import <Foundation/NSNull.h>

#import "ArchivedObject.h"

#import <Foundation/NSException.h>
@implementation NSException (bla)

- (void) raise
{
  NSString * name = [self name], * reason = [self reason];
  abort ();
}

@end

@implementation ObjectGraph

- (void) dealloc
{
  TEST_RELEASE (objects);

  [super dealloc];
}

- initWithKeyedArchive: (NSDictionary *) archive
{
  if ((self = [self init]) != nil)
    {
      NSMutableArray * newObjects;
      NSArray * objs = [archive objectForKey: @"$objects"];
      NSEnumerator * e;
      id object;
      Class dictionaryClass = [NSDictionary class],
            stringClass = [NSString class];
      NSNull * null = [NSNull null];

      newObjects = [NSMutableArray arrayWithCapacity: [objs count]];
      e = [objs objectEnumerator];
      while ((object = [e nextObject]) != nil)
        {
          if ([object isKindOfClass: dictionaryClass])
            {
              [newObjects addObject: [[[ArchivedObject alloc]
                initWithDescription: object objectGraph: self]
                autorelease]];
            }
          else if ([object isKindOfClass: stringClass])
            {
              NSString * string = object;

              if ([string isEqualToString: @"$null"])
                {
                  [newObjects addObject: null];
                }
              else
                {
                  [newObjects addObject: string];
                }
            }
          else
            {
              [newObjects addObject: object];
            }
        }

      ASSIGNCOPY (objects, newObjects);

      rootObjectUID = [[[[archive objectForKey: @"$top"]
        objectForKey: @"root"] objectForKey: @"CF$UID"] intValue];

      e = [objects objectEnumerator];
      while ((object = [e nextObject]) != nil)
        {
          if ([object isKindOfClass: [ArchivedObject class]])
            {
              [object setupRelationships];
            }
        }
    }

  return self;
}

- (unsigned int) rootObjectUID
{
  return rootObjectUID;
}

- objectForUID: (unsigned int) UID
{
  return [objects objectAtIndex: UID];
}

- (unsigned int) numberOfObjects
{
  return [objects count];
}

- objectAtPath: (NSString *) path
{
  NSArray * pathComponents = [path pathComponents];
  NSEnumerator * e;
  NSString * pathComponent;
  id object = [objects objectAtIndex: rootObjectUID];

  e = [pathComponents objectEnumerator];
  while ((pathComponent = [e nextObject]) != nil)
    {
      // skip over '/' components
      if ([pathComponent isEqualToString: @"/"])
        {
          continue;
        }

      // can't decompose atomic objects anymore
      if (![object isKindOfClass: [ArchivedObject class]])
        {
          return nil;
        }
      else
        {
          // is there such a relationship in the object?
          if (![[object relationshipNames] containsObject: pathComponent])
            {
              return nil;
            }
          else
            {
              object = [objects objectAtIndex: [object
                destinationUIDOfRelationship: pathComponent]];
            }
        }
    }

  return object;
}

- (NSString *) classNameForUID: (unsigned int) UID
{
  return [[objects objectAtIndex: UID] valueOfAttribute: @"$classname"];
}

- (NSArray *) classInheritanceForUID: (unsigned int) UID
{
  return [[objects objectAtIndex: UID] valueOfAttribute: @"$classes"];
}

@end
