/* emacs buffer mode hint -*- objc -*- */

#import "AgendaStore.h"
#import "WeekView.h"
#import "ConfigManager.h"
#import "iCalTree.h"
#import "AppointmentView.h"
#import "SelectionManager.h"
#import "NSColor+SimpleAgenda.h"
#import "defines.h"

@interface AppWeekView : AppointmentView
{
}
@end

@implementation AppWeekView
#define TextRect(rect) NSMakeRect(rect.origin.x + 4, rect.origin.y, rect.size.width - 8, rect.size.height - 2)
#define CEC_BORDERSIZE 1
#define RADIUS 5
- (void)drawRect:(NSRect)rect
{
  NSPoint point;
  NSString *title;
  NSString *label;
  Date *start = [_apt startDate];
  NSColor *color = [[_apt store] eventColor];
  NSColor *darkColor = [color colorModifiedWithDeltaRed:-0.3 green:-0.3 blue:-0.3 alpha:-0.3];
  NSDictionary *textAttributes = [NSDictionary dictionaryWithObject:[[_apt store] textColor]
					                     forKey:NSForegroundColorAttributeName];

  if ([_apt allDay])
    title = [NSString stringWithFormat:_(@"All day : %@"), [_apt summary]];
  else
    title = [NSString stringWithFormat:@"%2dh%0.2d : %@", [start hourOfDay], [start minuteOfHour], [_apt summary]];
  if ([_apt text])
    label = [NSString stringWithFormat:@"%@\n\n%@", title, [[_apt text] string]];
  else
    label = [NSString stringWithString:title];

  PSnewpath();
  PSmoveto(RADIUS + CEC_BORDERSIZE, CEC_BORDERSIZE);
  PSrcurveto(-RADIUS, 0, -RADIUS, RADIUS, -RADIUS, RADIUS);
  PSrlineto(0, NSHeight(rect) + rect.origin.y - 2 * (RADIUS + CEC_BORDERSIZE));
  PSrcurveto( 0, RADIUS, RADIUS, RADIUS, RADIUS, RADIUS);
  PSrlineto(NSWidth(rect) - 2 * (RADIUS + CEC_BORDERSIZE),0);
  PSrcurveto( RADIUS, 0, RADIUS, -RADIUS, RADIUS, -RADIUS);
  PSrlineto(0, -NSHeight(rect) - rect.origin.y + 2 * (RADIUS + CEC_BORDERSIZE));
  PSrcurveto(0, -RADIUS, -RADIUS, -RADIUS, -RADIUS, -RADIUS);
  PSclosepath();
  PSgsave();
  [color set];
  PSsetalpha(0.7);
  PSfill();
  PSgrestore();
  if ([[[SelectionManager globalManager] selection] containsObject:_apt])
    [[NSColor whiteColor] set];
  else
    [darkColor set];
  PSsetalpha(0.7);
  PSsetlinewidth(CEC_BORDERSIZE);
  PSstroke();
  [label drawInRect:TextRect(rect) withAttributes:textAttributes];
  point = NSMakePoint(rect.size.width - 18, rect.size.height - 16);
  if ([_apt rrule]) {
    [[self repeatImage] compositeToPoint:NSMakePoint(rect.size.width - 18, rect.size.height - 18) operation:NSCompositeSourceOver];
    point = NSMakePoint(rect.size.width - 30, rect.size.height - 16);
  }
  if ([_apt hasAlarms])
    [[self alarmImage] compositeToPoint:point operation:NSCompositeSourceOver];
}

- (void)mouseDown:(NSEvent *)theEvent
{
  WeekView *parent = (WeekView *)[[self superview] superview];
  id delegate = [parent delegate];

  if ([theEvent clickCount] > 1) {
    if ([delegate respondsToSelector:@selector(viewEditEvent:)])
      [delegate viewEditEvent:_apt];
    return;
  }
  [self becomeFirstResponder];
  [parent selectAppointmentView:self];
}
@end

static struct {
  float mx;
  float my;
  float sx;
  float sy;
} wdcoord[7] = {{0, 2, 1, 1}, {0, 1, 1, 1}, {0, 0, 1, 1}, {1, 2, 1, 1}, {1, 1, 1, 1}, {1, 0.5, 1, 0.5}, {1, 0, 1, 0.5}};

@interface WeekDayView : NSView
{
  Date *date;
}
- (id)initWithFrame:(NSRect)frame forDay:(Date *)day;
- (void)clear;
- (void)addAppointment:(Event *)apt;
- (Date *)day;
@end

@implementation WeekDayView
+ (NSRect)rectForDay:(int)weekday frame:(NSRect)frame
{
  int dwidth = frame.size.width / 2;
  int dheight = frame.size.height / 3;
  return NSMakeRect(dwidth * wdcoord[weekday - 1].mx, dheight * wdcoord[weekday - 1].my, dwidth * wdcoord[weekday - 1].sx, dheight * wdcoord[weekday - 1].sy);
}

- (id)initWithFrame:(NSRect)frame forDay:(Date *)day
{
  self = [super initWithFrame:[WeekDayView rectForDay:[day weekday] frame:frame]];
  if (self)
    date = [day copy];
  return self;
}

- (void)dealloc
{
  [date release];
  [super dealloc];
}

- (void)drawRect:(NSRect)rect
{
  int dwidth = rect.size.width;
  int dheight = rect.size.height;
  NSString *sdate;
  NSSize size;

  [[NSColor grayColor] set];
  NSFrameRect(NSMakeRect(4, dheight - 5, dwidth, 1));
  NSFrameRect(NSMakeRect(dwidth / 4, dheight - 17, dwidth * 3 / 4, 1));
  NSFrameRect(NSMakeRect(dwidth - 1, 0, 1, dheight));
  sdate = [[date calendarDate] descriptionWithCalendarFormat:@"%A %d %B"];
  size = [sdate sizeWithAttributes:nil];
  [sdate drawInRect:NSMakeRect(dwidth - size.width - 4, dheight - 17, size.width, 14) withAttributes:nil];
}

- (void)resizeWithOldSuperviewSize:(NSSize)oldBoundsSize
{
  [self setFrame:[WeekDayView rectForDay:[date weekday] frame:[[self superview] frame]]];
}

- (void)clear
{
  NSEnumerator *enumerator;
  NSView *view;

  enumerator = [[self subviews] objectEnumerator];
  while ((view = [enumerator nextObject]))
    [view removeFromSuperviewWithoutNeedingDisplay];
}

- (NSRect)frameForNewAppointment:(Event *)apt
{
  return NSMakeRect(0, 0 + 20 * [[self subviews] count] , [self frame].size.width, 20);
}

- (void)addAppointment:(Event *)apt
{
  AppWeekView *awv;

  awv = [[AppWeekView alloc] initWithFrame:[self frameForNewAppointment:apt] appointment:apt];
  [awv setAutoresizingMask:NSViewWidthSizable];
  [self addSubview:AUTORELEASE(awv)];
}

- (Date *)day
{
  return date;
}

- (void)mouseDown:(NSEvent *)theEvent
{
  WeekView *parent = (WeekView *)[self superview];
  id delegate = [parent delegate];

  if ([delegate respondsToSelector:@selector(viewSelectDate:)])
    [delegate viewSelectDate:date];
}
@end

@implementation WeekView
- (void)setupSelectWeek
{
  NSRect frame = [self frame];
  NSEnumerator *enumerator;
  NSView *view;
  int nday;
  Date *date;

  if ([_date weekOfYear] != weekNumber || [_date year] != year) {
    weekNumber = [_date weekOfYear];
    year = [_date year];
    enumerator = [[self subviews] objectEnumerator];
    while ((view = [enumerator nextObject]))
      [view removeFromSuperviewWithoutNeedingDisplay];
    /* Start with monday */
    date = [_date copy];
    [date changeDayBy: 1 - [date weekday]];
    for (nday = 0; nday < 7; nday++) {
      [self addSubview:AUTORELEASE([[WeekDayView alloc] initWithFrame:frame forDay:date])];
      [date incrementDay];
    }
    [date release];
  }
}

- (void)dealloc
{
  [[NSNotificationCenter defaultCenter] removeObserver:self];
  RELEASE(_date);
  RELEASE(_dataSource);
  [super dealloc];
}

- (id)delegate
{
  return delegate;
}
- (void)setDelegate:(id)theDelegate
{
  delegate = theDelegate;
}

- (id)dataSource
{
  return _dataSource;
}

- (void)setDataSource:(id)dataSource
{
  if (_dataSource == nil)
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(dataChanged:) name:SADataChangedInStoreManager object:nil];
  ASSIGN(_dataSource, dataSource);
  [self reloadData];
}
- (void)dataChanged:(NSNotification *)not
{
  [self reloadData];
}

- (void)selectAppointmentView:(AppointmentView *)aptv

{
  if ([delegate respondsToSelector:@selector(viewSelectDate:)])
    [delegate viewSelectDate:[(WeekDayView *)[aptv superview] day]];
  [[SelectionManager globalManager] select:[aptv appointment]];
  if ([delegate respondsToSelector:@selector(viewSelectEvent:)])
    [delegate viewSelectEvent:[aptv appointment]];
  [self setNeedsDisplay:YES];
}

- (void)reloadData
{
  NSEnumerator *enumerator, *enm;
  WeekDayView *wdv;
  Event *apt;
  NSSet *events;

  enumerator = [[self subviews] objectEnumerator];
  while ((wdv = [enumerator nextObject])) {
    [wdv clear];
    events = [_dataSource visibleAppointmentsForDay:[wdv day]];
    enm = [events objectEnumerator];
    while ((apt = [enm nextObject]))
      [wdv addAppointment:apt];
  }
}

- (BOOL)acceptsFirstResponder
{
  return YES;
}

- (void)config:(ConfigManager *)config dataDidChangedForKey:(NSString *)key
{
  [self reloadData];
}

- (void)setDate:(Date *)date
{
  ASSIGNCOPY(_date, date);
  [self setupSelectWeek];
  [self reloadData];
}
@end
