/*------------------------------------------------------
 *
 *  	wmCalendar (c)2003 Matthias Laabs
 *
 *       mattlaabs@users.sourceforge.net
 *
 *  		a calendar dockapp
 -----------------------------------------------------*/

#include "wmCalendar.h"

/*------------------------------------------------------
 *   main
 -----------------------------------------------------*/
int main(int argc, char *argv[])
{
    int n = 0;
    getSettings();
    ParseCMDLine(argc, argv);
    if(get_debug())printf("debugging mode:\nstarting wmCalendar version %s\n", getVersion());
    if(get_debug())printf("using libical version %s\n", ICAL_VERSION);
    dockapp_open_window("", "wmCalendar", 64, 64, argc, argv);
    initValues();
    gtk_init(&argc, &argv);
    checkicalversion();

    /*  Loop until we die */
    while(1) {
	if(n == 0){ /* do updates only every COUNTERth time */
	        getTime();
		calendar();
		draw();

	    n = COUNTER;
	}
	/* check for events every time */
	n--;
	if(processXEvents())
	    n = 0;
    }
}




/*------------------------------------------------------
 *  draw
 -----------------------------------------------------*/
void draw()
{

blankScreen();
    drawButtons();
    drawDays();
    drawMonthYear();
}



/*------------------------------------------------------
 *  initValues
 -----------------------------------------------------*/
void initValues(){
    XClassHint  class_hints;
    XpmColorSymbol colors[2];
    int i, j;
    monthOffset = 0;
    class_hints.res_name="wmCalendar";
    class_hints.res_class="wmCalendar";
    /* Compute widths of months and digits */
    for(i = 0; i < 12; ++i)
	for( j = 0; j < 6; ++j)
	    xdMonth[j][i] = xeMonth[j][i] - xsMonth[j][i] + 1;
    for(i = 0; i < 12; ++i)
	for( j = 0; j < 2; ++j)
	    xdYear[j][i] = xeYear[j][i] - xsYear[j][i] + 1;
    for(i = 0; i < MAXBUTTON; ++i)
	xdButton[i] = xeButton[i] - xsButton[i] + 1;

    dockapp_set_eventmask();
    dockapp_xpm2pixmap( wmCalendar_master2_xpm, &bg[1], &mask, colors, 0);
    dockapp_xpm2pixmap( wmCalendar_master_xpm, &bg[0], &mask, colors, 0);
    pixmap = dockapp_XCreatePixmap(64, 64);
    dockapp_setshape(mask, 0, 0);
    if(mask)
	XFreePixmap(display, mask);
    dockapp_set_background(pixmap);
    dockapp_show();
}



/*------------------------------------------------------
 *  read_stream
 -----------------------------------------------------*/
char* read_stream(char *s, size_t size, void *d){
  char *c = fgets(s, size, (FILE*)d);
  return c;
}


/*------------------------------------------------------
 *   getClickedDay
 -----------------------------------------------------*/
int getClickedDay(int bx, int by)
{
    int dayofweek, week, day;
    dayofweek = bx / 9 + 1;
    week = (by - 20) / 7;
    tgr = get_civil(t, calendartype);
    day = dayofweek + 7 * week - ((day_of_week(tgr) - t.day + 37 + get_start_of_week()) % 7);
    if(day <= days_in_month(t.month, t.year, calendartype) && day > 0){
	tgr.day = day;
	tgr.month = t.month;
	tgr.year = t.year;
	tgr = get_civil(tgr, calendartype);
	return 1;
    }
    return 0;
}



/*------------------------------------------------------
 *   getClickedButton
 -----------------------------------------------------*/
int getClickedButton(int bx, int by)
{
    if(bx < 12 && by < 12) /* arrow left : month back*/
	return BT_BACK;
    else if(bx > 50 && by < 12) /* arrow right : month forward*/
	return BT_FORWARD;
    else if(bx > 52 && by > 56) /* show/hide buttons */
	return BT_OPENCLOSE;
    else if(showbuttons){
	if(bx < 46 && bx > 37 && by > 55) /* toggle gregorian/persian/... */
	    return BT_MOON ;
	else if(bx < 52 && bx > 46 && by > 55) /* open settings dialog */
	    return BT_SETTINGS;
	else if(bx < 37 && bx > 28 && by > 55) /* toggle moonphase on/off */
	    return BT_CALTYPE;
	else if(bx < 28 && bx > 19 && by > 55)  /* start calendar application */
	    return BT_APP;
    }
    return 0;
}



/*------------------------------------------------------
 *   ButtonPressEvent
 -----------------------------------------------------*/
void buttonPress(int btype, int bx, int by, long etime){
    char* applaunch;
    if(get_debug() > 1) printf("push button %d\n", btype);

    switch(btype){
    case 1: /* leftmouse - button or mark */
	switch ( getClickedButton(bx, by)){
	case BT_BACK: /* arrow left : month back*/
	    monthOffset--;
	    break;

	case BT_FORWARD: /* arrow right : month forward*/
	    monthOffset++;
	    break;

	case BT_OPENCLOSE: /* show/hide buttons */
	    showbuttons = 1 - showbuttons;
	    break;

	case BT_CALTYPE: /* toggle gregorian/persian/... */
	    calendartype = (calendartype + 1) % CALTYPES;
	    break;

	case BT_MOON:/* toggle moonphase on/off */
	    showmoon = 1 - showmoon ;
	    break;

	case BT_SETTINGS: /* open settings dialog */
	    openSettings();
	    break;

	case BT_APP: /* start calendar application */
	    if(appDoubleClick && (etime - appClickTime < DBLCLKTIME)){
		applaunch = malloc(250);
		strcpy(applaunch, (const char*)get_application());
		strcat(applaunch, " &");
		system(applaunch);
		appDoubleClick = 0;
		free(applaunch);
	    }
	    else{
		appDoubleClick = 1;
		appClickTime = etime;
		}
	    break;

	default: /* no button clicked check for marking days*/
	    if(getClickedDay(bx, by)){
		if(!icaltime_is_null_time(mark))
		    mark = icaltime_null_time();
		else
		    mark = tgr;
	    }
	}
	break;

    case 4: /* mousewheel up : month back*/
	monthOffset--;
	break;

    case 5: /* mousewheel down : month forward*/
	monthOffset++;
	break;

    case 2: /* Middlemouse click : go to actual month*/
	monthOffset = 0;
	break;

    case 3: /* rightmouse click : show day entries*/
	if(getClickedDay(bx, by))
	    showDay(tgr);
	break;
    }

    told.month = 0; /* invalid month -> forces clearScreen at next draw*/
}



/*------------------------------------------------------
 *   ParseCMDLine
 -----------------------------------------------------*/
void ParseCMDLine(int argc, char *argv[]){
  int  i;

  for (i = 1; i < argc; i++){
    if (!strcmp(argv[i], "--version") || !strcmp(argv[i], "-v")){
      printf("wmCalendar %s\n", getVersion());
      exit(1);
    }
    else if (!strcmp(argv[i], "--help") || !strcmp(argv[i], "-h")){
      print_usage();
      exit(1);
    }
    else if (!strcmp(argv[i], "--farsi") || !strcmp(argv[i], "-f"))
	set_lang(1);
    else if (!strcmp(argv[i], "--persian") || !strcmp(argv[i], "-p"))
	calendartype = 1;
    else if (!strcmp(argv[i], "--debug") || !strcmp(argv[i], "-d"))
	set_debug( 1);
    else{
      print_usage();
      exit(1);
    }
  }
}



/*------------------------------------------------------
 *   print_usage
 -----------------------------------------------------*/
void print_usage()
{
  printf("wmCalendar %s (c) 2003 Matthias Laabs (mattlaabs@users.sourceforge.net)\n", getVersion());
  printf("This is free software under GPL!\n");
  printf("\nOptions:");
  printf("\n -h  --help\n   Show summary of options.");
  printf("\n -v  --version\n   Show version of program.");
  printf("\n -d  --debug\n   Show debugging info.");
  printf("\n -f  --farsi\n   Show months and numbers in farsi.");
  printf("\n -p  --persian\n   Changes to persian calendar.");
  printf("\n\nUsage: \nLeft and right arrow or mousewheel change month.\n");
  printf("Middle mouseclick goes back to current month.\n");
  printf("Right mouseclick opens dayview.\nClick on Moon to toggle moonphase-view on/off\n");
  printf("Click on screwdriver to open settings menu\nClick on 'G' to toggle between Gregorian, Persian and Islamic calendar\n");
  printf("Doubleclick evolution/mozilla icon to start application\nClick on blue arrow to show/hide buttons\n");
  printf("Leftclick a day to highlight for converting between calendars\n");
}



/*------------------------------------------------------
 *   getTime
 -----------------------------------------------------*/
void getTime(){
  struct tm	*Time;
  long	        CurrentLocalTime;

  /* get time */
  CurrentLocalTime = time(CurrentTime);
  Time = localtime(&CurrentLocalTime);
  t.day = Time->tm_mday;
  t.month = Time->tm_mon + 1;
  t.year = Time->tm_year + 1900;
  today = t;

  /* change calendar*/
  if(calendartype == 1)
      t = civil_persian(t);
  else if(calendartype == 2)
      t = civil_islamic(t);
  /* set t to currently shown month and year */
  t.month += monthOffset;
  while(t.month > 12){
    t.month -= 12;
    t.year += 1;
  }
  while(t.month < 1){
    t.month += 12;
    t.year -= 1;
  }
}



/*------------------------------------------------------
 *   drawMonthYear
 -----------------------------------------------------*/
void drawMonthYear(){
  int xoff, yoff;
  int Year1, Year2, Year3, Year4;
  int monthset;
  yoff = 1;
  monthset = calendartype + get_lang() * CALTYPES;
  /* calculate digits of the year */
  Year4 = t.year % 10;
  Year3 = ((t.year - Year4) / 10) % 10;
  Year2 = ((t.year - Year4 - 10 * Year3) / 100) % 10;
  Year1 = (t.year - Year4 - 10 * Year3 - 100 * Year2) / 1000;

  xoff = 30 - (xdMonth[monthset][t.month-1] + xdYear[get_lang()][Year3] + xdYear[get_lang()][Year4]) / 2;

  /* draw Month */
  dockapp_copyarea(bg[1], pixmap, xsMonth[monthset][t.month - 1], yMonth[monthset],
			   xdMonth[monthset][t.month - 1], ydMonth, xoff, yoff);
  xoff += xdMonth[monthset][t.month - 1] + 3;

  /* draw Year 3rd and 4th digit */
  dockapp_copyarea(bg[1], pixmap,xsYear[get_lang()][Year3], yYear, xdYear[get_lang()][Year3], ydYear, xoff, yoff);
  xoff += xdYear[get_lang()][Year3];
  dockapp_copyarea(bg[1], pixmap,xsYear[get_lang()][Year4], yYear, xdYear[get_lang()][Year4], ydYear, xoff, yoff);
  dockapp_copy2window(pixmap);
}



/*------------------------------------------------------
 *   drawButtons
 -----------------------------------------------------*/
void drawButtons(){
  int xoff, yoff;
  yoff = 56;
  xoff = 56;
  if(showbuttons){
      xoff = drawButton(ARROW_CLOSE, xoff, yoff);
      xoff = drawButton(SETTINGS, xoff, yoff);
      xoff = drawButton(MOON + showmoon, xoff, yoff);
      xoff = drawButton(CALENDAR + calendartype, xoff, yoff);
      xoff = drawButton(APPLAUNCH + getAppicon(), xoff, yoff);
  }
  else
      drawButton(ARROW_OPEN, xoff, yoff);

  dockapp_copy2window(pixmap);
}



/*------------------------------------------------------
 *   drawButton
 -----------------------------------------------------*/
int drawButton(int btype, int xoff, int yoff){
    xoff-=  xdButton[btype];
    dockapp_copyarea(bg[0], pixmap, xsButton[btype], yButton[btype], xdButton[btype],
		     ydButton, xoff, yoff);
    return --xoff;
}



/*------------------------------------------------------
 *   drawDays
 -----------------------------------------------------*/
void drawDays()
{
    int i, dayOfWeek;
    int amount, startday;
    int moonphase = 0;
    int yoff = 20;

    tgr = t;
    tgr.day = 1;

    tgr = get_civil(tgr, calendartype);
    amount = days_in_month(t.month, t.year, calendartype);
    startday = (day_of_week(tgr) + get_start_of_week()) % 7;
    for(i = 1; i <= amount; i++){
	dayOfWeek = (startday + i) % 7;
	if((dayOfWeek == 0) && (i != 1))
	    yoff += 7; /* increase y-offset on Monday except it is day #1*/

	tgr = t;
	tgr.day = i;
	tgr = get_civil(tgr, calendartype);

	if(showmoon)
	    moonphase = moon(tgr);

	if(daysEqual(tgr, mark))
	    drawNumber(i, yoff, dayOfWeek, 3, 0);
	else if(moonphase == 0 || !showmoon) /* draw number */
	    drawNumber(i, yoff, dayOfWeek, getDayType(tgr), daysEqual(tgr, today));
	else /* draw moonphase */
	    dockapp_copyarea(bg[0], pixmap, xsMoon[moonphase - 1], yMoon, xdMoon, ydMoon,
			     dayOfWeek * 9, yoff);
    }

    dockapp_copy2window(pixmap);
}



/*------------------------------------------------------
 *   drawNumber
 -----------------------------------------------------*/
void drawNumber(int number,int yoff, int dayOfWeek, int type, int today){
    int digit1, digit2;
    int offset;
    offset = yNumbers + 20 * type + 10 * today;
    if(number < 10){ /* draw single digit numbers*/
	dockapp_copyarea(bg[0], pixmap, xeNumbers[get_lang()][1] - 5, offset, 2, ydNumbers,
			 dayOfWeek * 9, yoff);
	dockapp_copyarea(bg[0], pixmap, xeNumbers[get_lang()][1] - 5, offset, 2, ydNumbers,
			 dayOfWeek * 9 + 7, yoff);
	dockapp_copyarea(bg[0], pixmap, xeNumbers[get_lang()][number], offset, xdNumbers, ydNumbers,
			 dayOfWeek * 9 + 2, yoff);
    }
    else{ /* draw double digit numbers*/
	digit2 = number % 10;
	digit1 = (number - digit2) / 10;
	dockapp_copyarea(bg[0], pixmap, xeNumbers[get_lang()][digit1], offset, xdNumbers, ydNumbers,
			 dayOfWeek * 9, yoff);
	dockapp_copyarea(bg[0], pixmap, xeNumbers[get_lang()][digit2], offset, xdNumbers, ydNumbers,
			 dayOfWeek * 9 + 4, yoff);
    }
}



/*------------------------------------------------------
 *   processXEvents
 -----------------------------------------------------*/
int processXEvents()
{
    if(dockapp_nextevent_or_timeout(&event, 150)) {
	/* Next Event */
	switch (event.type) {
	case ButtonPress:
	    buttonPress(event.xbutton.button,event.xbutton.x, event.xbutton.y, event.xbutton.time);
	    return 1;
	default: break;
	}
    }
    return 0;
}



/*------------------------------------------------------
 *   blankScreen
 -----------------------------------------------------*/
void blankScreen()
{
    if(daysEqual(t, told))
	return;
    /* only neccessary if day has changed*/
    dockapp_copyarea(bg[0], pixmap, 0, 0, 64, 64, 0, 0);
    dockapp_copyarea(bg[0], pixmap, 9 * (7 - get_start_of_week()),70 + get_lang() * 12, 63, 8, 0, 12);
    dockapp_copy2window(pixmap);
    calendar(); /* reread calendardata */
    told = t;
}