/** \file
 * \brief Calendar Control
 *
 * See Copyright Notice in "iup.h"
 */


#include <stdio.h>
#include <string.h>

#include "iup.h"

#include "iup_object.h"
#include "iup_attrib.h"
#include "iup_str.h"

#include "iupcocoa_drv.h"


static const void* IUP_COCOA_CALENDAR_DELEGATE_OBJ_KEY = "IUP_COCOA_CALENDAR_DELEGATE_OBJ_KEY";

@interface IupCocoaCalendarDelegate : NSObject
@end

@implementation IupCocoaCalendarDelegate

- (IBAction)myDatePickerAction:(id)the_sender
{
  Ihandle* ih = (Ihandle*)objc_getAssociatedObject(the_sender, IHANDLE_ASSOCIATED_OBJ_KEY);
  if (!ih || !iupObjectCheck(ih))
    return;
  iupBaseCallValueChangedCb(ih);
}

@end

static int cocoaCalendarSetValueAttrib(Ihandle* ih, const char* value)
{
  NSDatePicker* date_picker = (NSDatePicker*)ih->handle;

  if (iupStrEqualNoCase(value, "TODAY"))
  {
    [date_picker setDateValue:[NSDate date]];
  }
  else if (value)
  {
    int year, month, day;
    if (sscanf(value, "%d/%d/%d", &year, &month, &day) == 3)
    {
      if (month < 1) month = 1;
      if (month > 12) month = 12;
      if (day < 1) day = 1;
      if (day > 31) day = 31;

      NSDateComponents* components = [[NSDateComponents alloc] init];
      [components setYear:year];
      [components setMonth:month];
      [components setDay:day];

      NSCalendar* calendar = [NSCalendar currentCalendar];
      NSDate* parsed_date = [calendar dateFromComponents:components];
      [components release];

      if (parsed_date)
      {
        [date_picker setDateValue:parsed_date];
      }
    }
  }

  return 0;
}

static char* cocoaCalendarGetIupStrFromDate(NSDate* the_date)
{
  NSDateComponents* components = [[NSCalendar currentCalendar] components:NSCalendarUnitYear | NSCalendarUnitMonth | NSCalendarUnitDay
                                                                 fromDate:the_date];

  return iupStrReturnStrf("%ld/%ld/%ld",
      (long)[components year],
      (long)[components month],
      (long)[components day]);
}

static char* cocoaCalendarGetValueAttrib(Ihandle* ih)
{
  NSDatePicker* date_picker = (NSDatePicker*)ih->handle;
  NSDate* the_date = [date_picker dateValue];
  return cocoaCalendarGetIupStrFromDate(the_date);
}

static char* cocoaCalendarGetTodayAttrib(Ihandle* ih)
{
  (void)ih;
  NSDate* today_date = [NSDate date];
  return cocoaCalendarGetIupStrFromDate(today_date);
}

static void cocoaCalendarLayoutUpdateMethod(Ihandle* ih)
{
  NSDatePicker* date_picker = (NSDatePicker*)ih->handle;
  if (!date_picker) return;

  NSView* parent_view = [date_picker superview];
  if (!parent_view) return;

  NSRect parent_bounds = [parent_view bounds];
  NSSize intrinsic_size = [date_picker intrinsicContentSize];
  NSRect child_rect;

  /* Check if parent is a popover - if so, center the calendar */
  Ihandle* ih_parent = ih->parent;
  int is_in_popover = (ih_parent && ih_parent->iclass &&
                       ih_parent->iclass->name &&
                       strcmp(ih_parent->iclass->name, "popover") == 0);

  if (is_in_popover)
  {
    /* Center the date picker within the popover */
    CGFloat x = (parent_bounds.size.width - intrinsic_size.width) / 2;
    CGFloat y = (parent_bounds.size.height - intrinsic_size.height) / 2;
    child_rect = NSMakeRect(x, y, intrinsic_size.width, intrinsic_size.height);
    [date_picker setFrame:child_rect];
    [date_picker setBoundsSize:intrinsic_size];
  }
  else
  {
    /* Normal layout, use IUP computed position and size */
    if ([parent_view isFlipped])
    {
      child_rect = NSMakeRect(ih->x, ih->y, ih->currentwidth, ih->currentheight);
    }
    else
    {
      child_rect = NSMakeRect(ih->x, parent_bounds.size.height - ih->y - ih->currentheight, ih->currentwidth, ih->currentheight);
    }

    [date_picker setFrame:child_rect];

    /* If frame is larger than intrinsic size, scale content */
    if (child_rect.size.width > intrinsic_size.width || child_rect.size.height > intrinsic_size.height)
    {
      [date_picker setBoundsSize:intrinsic_size];
    }
    else
    {
      [date_picker setBoundsSize:child_rect.size];
    }
  }
}

static void cocoaCalendarComputeNaturalSizeMethod(Ihandle* ih, int *w, int *h, int *children_expand)
{
  (void)children_expand;

  if (ih->handle)
  {
    NSDatePicker* date_picker = (NSDatePicker*)ih->handle;
    NSSize intrinsic_size = [date_picker intrinsicContentSize];
    *w = iupROUND(intrinsic_size.width);
    *h = iupROUND(intrinsic_size.height);
  }
  else
  {
    static int calendar_w = -1;
    static int calendar_h = -1;

    if (calendar_w < 0)
    {
      NSDatePicker* temp_picker = [[NSDatePicker alloc] initWithFrame:NSZeroRect];
      [temp_picker setDatePickerStyle:NSDatePickerStyleClockAndCalendar];
      [temp_picker setDatePickerElements:NSDatePickerElementFlagYearMonthDay];
      [temp_picker setBezeled:YES];

      NSSize intrinsic_size = [temp_picker intrinsicContentSize];
      calendar_w = iupROUND(intrinsic_size.width);
      calendar_h = iupROUND(intrinsic_size.height);

      [temp_picker release];
    }

    *w = calendar_w;
    *h = calendar_h;
  }
}

static int cocoaCalendarMapMethod(Ihandle* ih)
{
  NSDatePicker* date_picker = [[NSDatePicker alloc] initWithFrame:NSZeroRect];

  [date_picker setDatePickerStyle:NSDatePickerStyleClockAndCalendar];

  [date_picker setDatePickerElements:NSDatePickerElementFlagYearMonthDay];
  [date_picker setDateValue:[NSDate date]];
  [date_picker setBezeled:YES];
  [date_picker setBordered:YES];

  IupCocoaCalendarDelegate* calendar_delegate = [[IupCocoaCalendarDelegate alloc] init];
  [date_picker setTarget:calendar_delegate];
  [date_picker setAction:@selector(myDatePickerAction:)];

  objc_setAssociatedObject(date_picker, IHANDLE_ASSOCIATED_OBJ_KEY, (id)ih, OBJC_ASSOCIATION_ASSIGN);
  objc_setAssociatedObject(date_picker, IUP_COCOA_CALENDAR_DELEGATE_OBJ_KEY, calendar_delegate, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
  [calendar_delegate release];

  [date_picker sizeToFit];

  ih->handle = date_picker;
  iupcocoaSetAssociatedViews(ih, date_picker, date_picker);

  iupcocoaAddToParent(ih);

  if (!iupAttribGetBoolean(ih, "CANFOCUS"))
  {
    [date_picker setRefusesFirstResponder:YES];
    iupcocoaSetCanFocus(ih, 0);
  }
  else
  {
    iupcocoaSetCanFocus(ih, 1);
  }

  return IUP_NOERROR;
}

static void cocoaCalendarUnMapMethod(Ihandle* ih)
{
  if (!ih->handle)
    return;

  id date_picker = ih->handle;

  [date_picker setTarget:nil];
  objc_setAssociatedObject(date_picker, IUP_COCOA_CALENDAR_DELEGATE_OBJ_KEY, nil, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
  objc_setAssociatedObject(date_picker, IHANDLE_ASSOCIATED_OBJ_KEY, nil, OBJC_ASSOCIATION_ASSIGN);

  iupdrvBaseUnMapMethod(ih);
}

Iclass* iupCalendarNewClass(void)
{
  Iclass* ic = iupClassNew(NULL);

  ic->name = "calendar";
  ic->format = NULL;
  ic->nativetype = IUP_TYPECONTROL;
  ic->childtype = IUP_CHILDNONE;
  ic->is_interactive = 1;

  ic->New = iupCalendarNewClass;
  ic->Map = cocoaCalendarMapMethod;
  ic->UnMap = cocoaCalendarUnMapMethod;
  ic->ComputeNaturalSize = cocoaCalendarComputeNaturalSizeMethod;
  ic->LayoutUpdate = cocoaCalendarLayoutUpdateMethod;

  iupClassRegisterCallback(ic, "VALUECHANGED_CB", "");

  iupBaseRegisterCommonCallbacks(ic);
  iupBaseRegisterCommonAttrib(ic);
  iupBaseRegisterVisualAttrib(ic);

  iupClassRegisterAttribute(ic, "VALUE", cocoaCalendarGetValueAttrib, cocoaCalendarSetValueAttrib, NULL, "TODAY", IUPAF_NO_DEFAULTVALUE | IUPAF_NO_INHERIT);
  iupClassRegisterAttribute(ic, "WEEKNUMBERS", NULL, NULL, NULL, NULL, IUPAF_NOT_SUPPORTED | IUPAF_NO_INHERIT);
  iupClassRegisterAttribute(ic, "TODAY", cocoaCalendarGetTodayAttrib, NULL, NULL, NULL, IUPAF_NOT_MAPPED | IUPAF_READONLY | IUPAF_NO_DEFAULTVALUE | IUPAF_NO_INHERIT);

  return ic;
}

Ihandle* IupCalendar(void)
{
  return IupCreate("calendar");
}
