/*
**  GeneralContainer.m
**
**  Copyright (c) 2004
**
**  Author: Yen-Ju Chen <yjchenx@hotmail.com>
**
**  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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/

#include <Foundation/Foundation.h>
#include "GeneralContainer.h"
#include "GNUstep.h"
#include "Constants.h"

void makeBackup (NSString *path)
{
  BOOL isDir;
  NSFileManager *fm = [NSFileManager defaultManager];
  NSString *backup = [path stringByAppendingString: @"~"];

  if ([fm fileExistsAtPath: backup isDirectory: &isDir])
    {
      if (isDir == YES)
        {
          /* Warning will show up later
           * because it fails to copy */
        }
      else
        {
          /* Remove backup */
          if ([fm removeFileAtPath: backup handler: nil] == NO)
            {
              NSRunAlertPanel(sFileErrorRemove, [NSString stringWithFormat: sCannotRemoveBackup__, backup, sAppName], sOK, nil, nil, nil);
            }
        }
    }

  /* Really make a backup */
  if ([fm copyPath: path toPath: backup handler: nil] == NO)
    {
      NSRunAlertPanel(sFileErrorCopy, [NSString stringWithFormat: sNotMakeBackup__, backup, sAppName], sOK, nil, nil, nil);
    }
}

@interface NSDictionary (TitleComparison)
- (NSComparisonResult) ascendingCompareTitle: (NSDictionary *) dictionary;
- (NSComparisonResult) descendingCompareTitle: (NSDictionary *) dictionary;
@end

@implementation NSDictionary (TitleComparison)
- (NSComparisonResult) ascendingCompareTitle: (NSDictionary *) dictionary
{
  return [(NSString *)[self objectForKey: TitleKey] caseInsensitiveCompare: [dictionary objectForKey: TitleKey]];
}

- (NSComparisonResult) descendingCompareTitle: (NSDictionary *) dictionary
{
  if ([self ascendingCompareTitle: dictionary] == NSOrderedAscending)
    return NSOrderedDescending;
  else
    return NSOrderedAscending;
}
@end

@implementation GeneralContainer

- (unsigned int) uniqueNumber
{ 
  unsigned int i, count = [self count];
  unsigned int uid, acc = 0;
  NSMutableIndexSet *indexSet = [NSMutableIndexSet indexSet];
  /* Find the largest number */
  for(i = 0; i < count; i++)
    {  
      uid = [[self objectAtIndex: i forKey: UniqueNumberKey] unsignedIntValue]; 
      if (uid == NSNotFound) continue;
      [indexSet addIndex: uid];
    }

  while([indexSet containsIndex: acc])
    { 
       acc++;
    }
  return acc;
}


- (void) sortTitle: (NSComparisonResult) order
{
  if (order == NSOrderedAscending)
    [container sortUsingSelector: @selector(ascendingCompareTitle:)];
  else
    [container sortUsingSelector: @selector(descendingCompareTitle:)];
}

/* low-level method */
- (BOOL) isDuplicatedTitle: (NSString *) title skipIndex: (unsigned int) index
{
  unsigned int i, count = [container count];
  NSDictionary *object;
  for(i = 0; i < count; i++)
    {
      if (i == index) continue;

      object = [container objectAtIndex: i];
      //NSLog(@"<%@> and (%@)", [object objectForKey: TitleKey], title);
      if ([[object objectForKey: TitleKey] isEqualToString: title] == YES)
        {
           return YES;
        }
    }
  return NO;
}

- (BOOL) isDuplicatedTitle: (NSString *) title
{
  [self isDuplicatedTitle: title skipIndex: NSNotFound];
}

- (unsigned int) addObject: (id) object forKey: (id) key
{
  if ((object == nil) || (key == nil)) return NSNotFound;
  NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithObject: 
	                                     AUTORELEASE([object copy])
	                                           forKey: 
					     AUTORELEASE([key copy])];
  [container addObject: dict];
  return [container count]-1;
}

- (unsigned int) addObject: (id) object atIndex: (unsigned int) index
                                forKey: (id) key
{
  if ((object == nil) || (key == nil) || (index == NSNotFound)) return NSNotFound;

  if (index >= [self count])
    return [self addObject: object forKey: TitleKey];

  NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithObject: 
	                                     AUTORELEASE([object copy])
                                      forKey: AUTORELEASE([key copy])];
  [container insertObject: dict atIndex: index];
  return index;
}

/* for reset value, not new item */
- (void) setObject: (id) object atIndex: (unsigned int) index
                                 forKey: (id) key
{
  if ((object == nil) || (index == NSNotFound) || 
      (key == nil) || (index >= [container count])) return;

  [(NSMutableDictionary *)[container objectAtIndex: index] 
                               setObject: AUTORELEASE([object copy])
	                          forKey: AUTORELEASE([key copy])];
}

- (id) objectAtIndex: (unsigned int) index forKey: (id) key
{
  if ((index == NSNotFound) || 
      (key == nil) || (index >= [container count])) return nil;

  return AUTORELEASE([[(NSDictionary *)[container objectAtIndex: index] objectForKey: key] copy]);
}

- (void) removeObjectAtIndex: (unsigned int) index
{
  if ((index == NSNotFound) || (index >= [self count])) return;
  [container removeObjectAtIndex: index];
}

- (void) removeObjectForKey: (id) key atIndex: (unsigned int) index
{
  if ((key == nil) || (index == NSNotFound) || (index >= [self count])) return;
  [(NSMutableDictionary *)[container objectAtIndex: index] removeObjectForKey: key];
}

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

/* Unique number */
- (void) setUniqueNumber: (unsigned int) uid
                 atIndex: (unsigned int) index
{
  [self setObject: [NSNumber numberWithUnsignedInt: uid]
	  atIndex: index forKey: UniqueNumberKey];
}

- (unsigned int) uniqueNumberAtIndex: (unsigned int) index
{
  if (index == NSNotFound) return NSNotFound;
  NSNumber *n = [self objectAtIndex: index forKey: UniqueNumberKey];
  if (n == nil) return NSNotFound;
  return [n unsignedIntValue];
}

- (unsigned int) indexOfUniqueNumber: (unsigned int) uid
{
  if (uid == NSNotFound) return NSNotFound;
  unsigned int i, count = [self count];
  unsigned int u;
  for(i = 0; i < count; i++)
    {
      u = [self uniqueNumberAtIndex: i];
      if (u == uid) return i;
    }
  return NSNotFound;
}

/* write accessory */
- (unsigned int) newTitle: (NSString *) title
{
  unsigned int index = [self addObject: title forKey: TitleKey];
  [self setObject: [NSNumber numberWithUnsignedInt: [self uniqueNumber]]
	  atIndex: index forKey: UniqueNumberKey];
  return index;
}

- (unsigned int) newTitle: (NSString *) title 
                  atIndex: (unsigned int) row
{
  unsigned int index =  [self addObject: title atIndex: row forKey: TitleKey];
  [self setObject: [NSNumber numberWithUnsignedInt: [self uniqueNumber]]
	  atIndex: index forKey: UniqueNumberKey];
  return index;
}

- (void) setTitle: (NSString *) title atIndex: (unsigned int) index
{
  [self setObject: title atIndex: index forKey: TitleKey];
}

/* read accessory */
- (NSString *) titleAtIndex: (unsigned int) index
{
  return [self objectAtIndex: index forKey: TitleKey];
}

- (unsigned int) indexOfTitle: (NSString *) title
{
  NSDictionary *object;
  NSEnumerator *e = [container objectEnumerator];
  unsigned int count = 0;
  while ((object = [e nextObject]))
    {
      if ([title isEqualToString: [object objectForKey: TitleKey]] == YES)
        {
           return count;
        }
      count++;
   }
 return NSNotFound;
}

/* read from files*/
- (BOOL) readFromFile: (NSString *) absolutePath
{
  NSData *data = [NSData dataWithContentsOfFile: absolutePath];
  if (data == nil)
    return NO;

  NSString *err = nil;
  id propertyList = [NSPropertyListSerialization propertyListFromData: data
	                     mutabilityOption: NSPropertyListMutableContainers
		             format: NULL
			     errorDescription: &err];
  if (err)
    {
      NSLog(@"General container: Read Error \"%@\"", err);
      RELEASE(err);
      return NO;
    }
  if (propertyList)
    {
      [container setArray: propertyList];
      return YES;
    }
  else
    return NO;
}

- (BOOL) loadSourceAtPath: (NSString *) absolutePath
{
  ASSIGN(containerPath, AUTORELEASE([absolutePath copy]));
  return YES;
}
  /* used for unload source or export source */
- (BOOL) writeToFile: (NSString *) absolutePath
{
  NSString *err = nil;
  NSData *data = [NSPropertyListSerialization dataFromPropertyList: container
                             format: NSPropertyListXMLFormat_v1_0
			     errorDescription: &err];
  if (err)
    {
      NSLog(@"General container: Write Error \"%@\"", err);
      RELEASE(err);
      return NO;
    }

  return [data writeToFile: absolutePath atomically: YES];
}

  /* will call unloadSourceAtPath */
- (BOOL) unloadSourceAtPath: (NSString *) absolutePath
{
  if (absolutePath == nil)
    return [self writeToFile: containerPath];
  else
    return [self writeToFile: absolutePath];
}

- (NSString *) path
{
  return containerPath;
}

/* override */
- (id) copyWithZone: (NSZone *) zone
{
  return RETAIN(self);
}

- (id) init
{
  self = [super init];
  container = [[NSMutableArray alloc] init];
  return self;
}

- (void) dealloc
{
  RELEASE(container);
  RELEASE(containerPath);
  [super dealloc];
}

@end

