/*
	calendar.c
*/

#include "calendar.h"

#define YEAR_X		15
#define YEAR_Y		 0
#define MONTH_X		 6
#define MONTH_Y		 0
#define DAYS_X		 0
#define DAYS_Y		 1
#define DATE_X		 0
#define DATE_Y		 2
#define COLUMNS_PER_DAY  4

#define ON 1
#define OFF 0

static unsigned char month_days[2][13] = {
    { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
    { 0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
};

static char * mnames[] = {
    "(dummy)", "January", "February", "March", "April", "May", "June",
    "July", "August", "September", "October", "November", "December"
};

static char * daynames[] = {
    "Sunday", "Monday", "Tuesday", "Wednesday",
    "Thursday", "Friday", "Saturday"
};

typedef struct {
	unsigned int year;
	int month;
	int date;
} date_t;

/* static char * daylabels = "Sun Mon Tue Wed Thu Fri Sat"; */
static char * daylabel1 = "Sun ";
static char * daylabel2 = "Mon Tue Wed Thu Fri ";
static char * daylabel3 = "Sat";

unsigned int year;
int month;
date_t today;

/* テキストをカラーで表示するための初期化関数 */
void init_color_text()
{
	if (wwc_get_hardarch() == HARDARCH_WSC) {
		wwc_set_color_mode(COLOR_MODE_4COLOR);
		wwc_palette_set_color(0, 0, 0x0fff);	/* white */
		wwc_palette_set_color(0, 1, 0x000f);	/* blue */
		wwc_palette_set_color(0, 2, 0x0f00);	/* red */
		wwc_palette_set_color(0, 3, 0x0000);	/* black */
		wwc_palette_set_color(1, 0, 0x0000);	/* white */
		wwc_palette_set_color(1, 1, 0x000f);	/* blue */
		wwc_palette_set_color(1, 2, 0x0f00);	/* red */
		wwc_palette_set_color(1, 3, 0x0fff);	/* black */
	} else {
		lcd_set_color(0x6420, 0xfca8);
		palette_set_color(0, 0x7530);
		palette_set_color(1, 0x0357);
	}
}

/* 閏年？ */
int isleap(unsigned int y) {
	return (y % 4 == 0) && ((y % 100 != 0) || (y % 400 == 0)) ? 1 : 0;
}

/* 曜日をint型で返す */
int get_week(unsigned int y, int m, int d) {
	int i, day, lastyear, total_shifts;

	/* calcurates total day shifts in week */
	/* add shifts by each year and leap years */
	lastyear = y - 1;
	total_shifts = (lastyear * (365 % 7)) % 7
		 + (lastyear / 4 - lastyear / 100 + lastyear / 400) % 7; 

	/* add shifts by each month for the year */
	for (i = 1; i < m; i++) {
		total_shifts += month_days[isleap(y)][i] % 7;
	}

	/* Jan 1, A.D.1 is Saturday,
	   drifted 11days by adoption to Gregorean calendar,
	   and changed leap year semantics on Sep. 1752.
	 */
	day = ((d -1) + total_shifts + (17 - 4) - 11 + 6) % 7;

	return day;
}

/* 曜日を返す */
void get_daynames(unsigned int y, int m, int d, char far *buf) {
	strcpy(buf, daynames[get_week(y, m, d)]);
}

/* 年月からその月の最終日を返す */
int get_max_month_days(unsigned int y, int m) {
	return month_days[isleap(y)][m];
}

/* カレンダーを表示する */
void show_calendar() {
	int leap, i, day, days, lastyear, total_shifts;

	leap = isleap(year);

	/* calcurates total day shifts in week */
	/* add shifts by each year and leap years */
	lastyear = year - 1;
	total_shifts = (lastyear * (365 % 7)) % 7
		 + (lastyear / 4 - lastyear / 100 + lastyear / 400) % 7;

	/* add shifts by each month for the year */
	for (i = 1; i < month; i++) {
		total_shifts += month_days[leap][i] % 7;
	}

	/* Jan 1, A.D.1 is Saturday,
	   drifted 11days by adoption to Gregorean calendar,
	   and changed leap year semantics on Sep. 1752.
	 */
	day = (total_shifts + (17 - 4) - 11 + 6) % 7;

	days = month_days[leap][month];

	/* print heading labels */
	font_set_color(0x03);
	text_put_numeric(YEAR_X,  YEAR_Y, 5, NUM_PADSPACE, year);
	text_put_string(MONTH_X, MONTH_Y, mnames[month]);
	font_set_color(0x02);
	text_put_string(DAYS_X   ,  DAYS_Y,  daylabel1);
	font_set_color(0x03);
	text_put_string(DAYS_X+4 ,  DAYS_Y,  daylabel2);
	font_set_color(0x01);
	text_put_string(DAYS_X+24,  DAYS_Y,  daylabel3);

	cursor_display(OFF);
	{
		/* print date table */
		int x, y = DATE_Y;
		int d;
		x = day * COLUMNS_PER_DAY;

		for (d = 1; d <= days; d++) {
			if (day == 6) {
				font_set_color(0x01);
			} else if (day == 0 ) {
				font_set_color(0x02);
			} else {
				font_set_color(0x03);
			}
			text_put_numeric(x, y, 2, NUM_PADSPACE, d);

			if( (year == today.year) && (month == today.month) && (d == today.date) ) {
				cursor_set_location(x, y, 2, 1);
				cursor_display(ON);
			}

			day++;
			if (day == 7) {
				day = 0;
				x = 0;
				y ++;
			} else {
				x += COLUMNS_PER_DAY;
			}
		}
	}
}

/* カレンダー機能のメイン関数 */
void calendar(int yy) {
	char loop = 1;

	year = rtc_get_year() + yy;
	month = rtc_get_month();
	today.year = year;
	today.month = month;
	today.date = rtc_get_date();


	/* convert BCD to integer
	year  = year % 16
	+   10 * ((year & 0x00F0) >> 4)
	+  100 * ((year & 0x0F00) >> 8)
	+ 1000 * ((year & 0xF000) >>12);
	month = month % 16 + 10 * (month / 16);
	date  = date % 16 + 10 * (date / 16);
	*/

	while (loop) {
		text_screen_init();
		init_color_text();
		font_set_color(0x03);
		text_put_string(0, 17, "calendar mode quit: START   ");
		cursor_set_type(1, 0);

		show_calendar();
		switch (key_wait()) {
		case KEY_UP1:
			year--;
			break;
		case KEY_DOWN1:
			year++;
			break;
		case KEY_RIGHT1:
			month++;
			if (month > 12) {
				month = 1;
				year++;
			}
			break;
		case KEY_LEFT1:
			month--;
			if (month < 1) {
			month = 12;
			year--;
			}
			break;
		case KEY_START:
			loop = 0;
			break;
		default:
			break;
		}
	}
	cursor_display(OFF);
}
