/*
  Copyright (C) 2000-2005 SKYRIX Software AG

  This file is part of SOPE.

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

  SOPE 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 Lesser General Public
  License for more details.

  You should have received a copy of the GNU Lesser General Public
  License along with SOPE; see the file COPYING.  If not, write to the
  Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
  02111-1307, USA.
*/

#include "iCalDateHolder.h"
#include "iCalObject.h"
#include "common.h"

@interface NSTimeZone(iCalTimeZone)

+ (NSTimeZone *)timeZoneWithICalId:(NSString *)_tz;

@end

@implementation iCalDateHolder

static NSTimeZone *gmt = nil;

+ (void)initialize {
  if (gmt == nil)
    gmt = [[NSTimeZone timeZoneWithName:@"GMT"] retain];
}

- (void)dealloc {
  [self->tzid   release];
  [self->string release];
  [self->tag    release];
  [super dealloc];
}

/* accessors */

- (void)setString:(NSString *)_value {
  ASSIGNCOPY(self->string, _value);
}
- (NSString *)string {
  return self->string;
}

- (void)setTag:(NSString *)_value {
  ASSIGNCOPY(self->tag, _value);
}
- (NSString *)tag {
  return self->tag;
}

- (void)setTzid:(NSString *)_value {
  ASSIGNCOPY(self->tzid, _value);
}
- (NSString *)tzid {
  return self->tzid;
}

/* mapping to Foundation */

- (NSTimeZone *)timeZone {
  // TODO: lookup tzid in iCalCalendar !
  NSString *s;

  s = [self tzid];
  
  /* a hack */
  if ([s hasPrefix:@"/softwarestudio.org"]) {
    NSRange r;
    
    r = [s rangeOfString:@"Europe/"];
    if (r.length > 0)
      s = [s substringFromIndex:r.location];
  }
  return [NSTimeZone timeZoneWithICalId:s];
}

/* decoding */

- (id)awakeAfterUsingSaxDecoder:(id)_decoder {
  NSCalendarDate *date = nil;
  NSString   *s;
  NSTimeZone *tz;
  
  s = self->string;
  if ([s length] < 5) {
    [self logWithFormat:@"tag %@: got an weird date string '%@' ?!", 
	    self->tag, s];
    return s;
  }
  
  /* calculate timezone */
  
  if ([self->string hasSuffix:@"Z"]) {
    /* zulu time, eg 20021009T094500Z */
    tz = gmt;
    s = [s substringToIndex:([s length] - 1)];
  }
  else
    tz = [self timeZone];
  
  /* 
     012345678901234
     20021009T094500 - 15 chars 
     20021009T0945   - 13 chars 
     991009T0945     - 11 chars
     
     20031111        - 8 chars
  */
  if ([s rangeOfString:@"T"].length == 0 && [s length] == 8) {
    /* hm, maybe a date without a time? like an allday event! */
    int year, month, day;
    char buf[16];
    [s getCString:&(buf[0])];
    
    buf[9] = '\0';
    day    = atoi(&(buf[6]));  buf[6] = '\0';
    month  = atoi(&(buf[4]));  buf[4] = '\0';
    year   = atoi(&(buf[0]));
    
    date = [NSCalendarDate dateWithYear:year month:month day:day
                           hour:0 minute:0 second:0
                           timeZone:tz];
  }
  else if ([s length] == 15) {
    int year, month, day, hour, minute, second;
    char buf[24];
    [s getCString:&(buf[0])];
      
    second = atoi(&(buf[13])); buf[13] = '\0';
    minute = atoi(&(buf[11])); buf[11] = '\0';
    hour   = atoi(&(buf[9]));  buf[9] = '\0';
    day    = atoi(&(buf[6]));  buf[6] = '\0';
    month  = atoi(&(buf[4]));  buf[4] = '\0';
    year   = atoi(&(buf[0]));
      
    date = [NSCalendarDate dateWithYear:year month:month day:day
                           hour:hour minute:minute second:second
                           timeZone:tz];
  }
  else
    NSLog(@"%s: unknown date format (%@) ???", __PRETTY_FUNCTION__, s);
    
  if (date == nil)
    NSLog(@"couldn't convert string '%@' to date (format '%@') ..", s);

  return date;
}

/* description */

- (void)appendAttributesToDescription:(NSMutableString *)ms {
  if (self->tag)    [ms appendFormat:@" %@",  self->tag];
  if (self->string) [ms appendFormat:@" '%@'",  self->string];
  if (self->tzid)   [ms appendFormat:@" tz=%@", self->tzid];
}

- (NSString *)description {
  NSMutableString *ms;

  ms = [NSMutableString stringWithCapacity:128];
  [ms appendFormat:@"<0x%08X[%@]:", self, NSStringFromClass([self class])];
  [self appendAttributesToDescription:ms];
  [ms appendString:@">"];
  return ms;
}

@end /* iCalDateHolder */

@implementation NSTimeZone(iCalTimeZone)

static NSMutableDictionary *idToTz = nil; // THREAD

+ (NSTimeZone *)timeZoneWithICalId:(NSString *)_tzid {
  static NSString *iCalDefaultTZ = nil;
  NSTimeZone *tz;
  
  if (idToTz == nil)
    idToTz = [[NSMutableDictionary alloc] initWithCapacity:16];
  
  if ([_tzid length] == 0) {
    
    tz = [iCalObject iCalDefaultTimeZone];
    if (tz != nil) return tz;

    if (iCalDefaultTZ == nil) {
      NSString *defTz;
      NSUserDefaults *ud;
      // TODO: take a default timeZone
      ud = [NSUserDefaults standardUserDefaults];
      defTz = [ud stringForKey:@"iCalTimeZoneName"];
      if ([defTz length] == 0)
        defTz = [ud stringForKey:@"TimeZoneName"];
      if ([defTz length] == 0)
        defTz = [ud stringForKey:@"TimeZone"];
      if ([defTz length] == 0)
        defTz = @"GMT";
      iCalDefaultTZ = [defTz retain];
    }
    
    _tzid = iCalDefaultTZ;
    
  }
  
  if ([_tzid length] == 0)
    _tzid = @"GMT";
  
  tz = [idToTz objectForKey:_tzid];
  if (tz == nil) tz = [NSTimeZone timeZoneWithName:_tzid];
  if (tz == nil) tz = [NSTimeZone timeZoneWithAbbreviation:_tzid];
  
  if (tz == nil) {
    NSLog(@"couldn't map timezone id %@", _tzid);
  }
  
  if (tz) [idToTz setObject:tz forKey:_tzid];
  return tz;
}

@end /* NSTimeZone(iCalTimeZone) */
