/*
	watch.c
*/

#include "watch.h"

#define DATE_X	2
#define DATE_Y	12
#define TIME_X	8
#define TIME_Y	14

#define SET_TITLE_X	2
#define SET_TITLE_Y	1
#define DATE_SET_X	2
#define DATE_SET_Y	4
#define TIME_SET_X	8
#define TIME_SET_Y	6

#define ON 1
#define OFF 0

enum {
	YEAR1 = 0,
	YEAR2,
	YEAR3,
	YEAR4,
	COMMA1,
	MONTH1,
	MONTH2,
	COMMA2,
	DATE1,
	DATE2,
	COMMA3,
	WEEK1,
};

enum {
	HOUR1 = 0,
	HOUR2,
	COMMA4,
	MINUTE1,
	MINUTE2,
	COMMA5,
	SECOND1,
	SECOND2,
};

static int yy;
static int tmp_year[4];
static int tmp_month;
static int tmp_date;
static int tmp_hour;
static int tmp_minute[2];
static int tmp_second[2];

/* タイマ割り込み時の処理関数 */
void far int_show_watch() {
	int c;
	c = font_get_color();
	show_watch();
	font_set_color(c);
}

/* 時計を表示する関数 */
void show_watch() {
	unsigned int year;
	int month, date, week;
	char buf[10];

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

	font_set_color(0x03);
	text_put_string(DATE_X, DATE_Y, "    /  /  ");
	text_put_numeric(DATE_X          , DATE_Y, 4, NUM_PADZERO | NUM_ALIGN_RIGHT, year);
	text_put_numeric(DATE_X + MONTH1 , DATE_Y, 2, NUM_PADZERO | NUM_ALIGN_RIGHT, month);
	text_put_numeric(DATE_X + DATE1  , DATE_Y, 2, NUM_PADZERO | NUM_ALIGN_RIGHT, date);
	get_daynames(year, month, date, (char far *)buf);
	if ( (week = get_week(year, month, date)) == 6 ) font_set_color(0x01);
	else if ( week == 0 ) font_set_color(0x02);
	else font_set_color(0x03); 
	text_put_string(DATE_X + WEEK1   , DATE_Y, buf);
	font_set_color(0x03);
	text_put_string(TIME_X, TIME_Y, "  :  .  ");
	text_put_numeric(TIME_X          , TIME_Y, 2, NUM_PADZERO | NUM_ALIGN_RIGHT, rtc_get_hour());
	text_put_numeric(TIME_X + MINUTE1, TIME_Y, 2, NUM_PADZERO | NUM_ALIGN_RIGHT, rtc_get_minute());
	text_put_numeric(TIME_X + SECOND1, TIME_Y, 2, NUM_PADZERO | NUM_ALIGN_RIGHT, rtc_get_second());
}

/* 時計の表示に関する初期化関数 */
void init_watch_display() {
	text_screen_init();
	init_color_text();
	font_set_color(0x03);
	text_put_string(0, 17, "quit: START set: Y3 cal: Y1 ");
}

/* RTCに時刻を設定する */
void set_watch() {
	unsigned int year;
	int month, date, hour, minute, second;

	yy = tmp_year[0] * 1000 + tmp_year[1] * 100;
	year = tmp_year[2] * 10 + tmp_year[3];
	month = tmp_month;
	date = tmp_date;
	hour = tmp_hour;
	minute = tmp_minute[0] * 10 + tmp_minute[1];
	second = tmp_second[0] * 10 + tmp_second[1];

	rtc_set_year(year);
	rtc_set_month(month);
	rtc_set_date(date);
	rtc_set_hour(hour);
	rtc_set_minute(minute);
	rtc_set_second(second);
}

/* カーソルを右へ動かす */
void move_right_cursor(int far *pos, unsigned char far *dort) {
	if ( !(*dort) ) {
		switch(*pos) {
		case YEAR1:
			cursor_set_location(DATE_SET_X + YEAR2, DATE_SET_Y, 1, 1);
			*pos = YEAR2;
			break;
		case YEAR2:
			cursor_set_location(DATE_SET_X + YEAR3, DATE_SET_Y, 1, 1);
			*pos = YEAR3;
			break;
		case YEAR3:
			cursor_set_location(DATE_SET_X + YEAR4, DATE_SET_Y, 1, 1);
			*pos = YEAR4;
			break;
		case YEAR4:
			cursor_set_location(DATE_SET_X + MONTH1, DATE_SET_Y, 2, 1);
			*pos = MONTH2;
			break;
		case MONTH2:
			cursor_set_location(DATE_SET_X + DATE1, DATE_SET_Y, 2, 1);
			*pos = DATE2;
			break;
		case DATE2:
			cursor_set_location(TIME_SET_X + HOUR1, TIME_SET_Y, 2, 1);
			*pos = HOUR2;
			*dort = 1;
			break;
		default:
			break;
		}
	} else {
		switch(*pos) {
		case HOUR2:
			cursor_set_location(TIME_SET_X + MINUTE1, TIME_SET_Y, 1, 1);
			*pos = MINUTE1;
			break;
		case MINUTE1:
			cursor_set_location(TIME_SET_X + MINUTE2, TIME_SET_Y, 1, 1);
			*pos = MINUTE2;
			break;
		case MINUTE2:
			cursor_set_location(TIME_SET_X + SECOND1, TIME_SET_Y, 1, 1);
			*pos = SECOND1;
			break;
		case SECOND1:
			cursor_set_location(TIME_SET_X + SECOND2, TIME_SET_Y, 1, 1);
			*pos = SECOND2;
			break;
		case SECOND2:
			cursor_set_location(DATE_SET_X + YEAR1, DATE_SET_Y, 1, 1);
			*pos = YEAR1;
			*dort = 0;
			break;
		default:
			break;
		}
	}
}

/* カーソルを左に動かす */
void move_left_cursor(int far *pos, unsigned char far *dort) {
	if ( !(*dort) ) {
		switch(*pos) {
		case YEAR1:
			cursor_set_location(TIME_SET_X + SECOND2, TIME_SET_Y, 1, 1);
			*pos = SECOND2;
			*dort = 1;
			break;
		case YEAR2:
			cursor_set_location(DATE_SET_X + YEAR1, DATE_SET_Y, 1, 1);
			*pos = YEAR1;
			break;
		case YEAR3:
			cursor_set_location(DATE_SET_X + YEAR2, DATE_SET_Y, 1, 1);
			*pos = YEAR2;
			break;
		case YEAR4:
			cursor_set_location(DATE_SET_X + YEAR3, DATE_SET_Y, 1, 1);
			*pos = YEAR3;
			break;
		case MONTH2:
			cursor_set_location(DATE_SET_X + YEAR4, DATE_SET_Y, 1, 1);
			*pos = YEAR4;
			break;
		case DATE2:
			cursor_set_location(DATE_SET_X + MONTH1, DATE_SET_Y, 2, 1);
			*pos = MONTH2;
			break;
		default:
			break;
		}
	} else {
		switch(*pos) {
		case HOUR2:
			cursor_set_location(DATE_SET_X + DATE1, DATE_SET_Y, 2, 1);
			*pos = DATE2;
			*dort = 0;
			break;
		case MINUTE1:
			cursor_set_location(TIME_SET_X + HOUR1, TIME_SET_Y, 2, 1);
			*pos = HOUR2;
			break;
		case MINUTE2:
			cursor_set_location(TIME_SET_X + MINUTE1, TIME_SET_Y, 1, 1);
			*pos = MINUTE1;
			break;
		case SECOND1:
			cursor_set_location(TIME_SET_X + MINUTE2, TIME_SET_Y, 1, 1);
			*pos = MINUTE2;
			break;
		case SECOND2:
			cursor_set_location(TIME_SET_X + SECOND1, TIME_SET_Y, 1, 1);
			*pos = SECOND1;
			break;
		default:
			break;
		}
	}
}

/* -1する。ただし、最小値を超える場合は最大値にする */
int dec_1_num(int n, int min, int max) {
	if ( n == min ) 
		return max;
	else
		return --n;
}

/* +1する。ただし、最大値を超える場合は最小値にする */
int inc_1_num(int n, int max, int min) {
	if ( n == max )
		return min;
	else
		return ++n;
}

/* 現在表示されている年月の最終日をチェックする */
/* 例えば、３１日が表示されている時に、月の設定値で２月を（ちょっとでも）表示させると、２８日に表示し直す */
void check_max_day() {
	unsigned int year;
	int max;

	year = tmp_year[0]*1000 + tmp_year[1]*100 + tmp_year[2]*10 + tmp_year[3];
	max = get_max_month_days(year, tmp_month);
	if ( max < tmp_date ) {
		font_set_color(0x03);
		text_put_numeric(DATE_SET_X + DATE1, DATE_SET_Y, 2, NUM_PADZERO | NUM_ALIGN_RIGHT, max);
	}
}

/* カーソルのある所の値を-1する */
void dec_num_oncursor(int pos, unsigned char dort) {
	unsigned int year;

	if ( !dort ) {
		switch(pos) {
		case YEAR1:
			tmp_year[0] = dec_1_num(tmp_year[0], 0, 9);
			text_put_numeric(DATE_SET_X + YEAR1, DATE_SET_Y, 1, NUM_PADZERO | NUM_ALIGN_RIGHT, tmp_year[0]);
			check_max_day();
			break;
		case YEAR2:
			tmp_year[1] = dec_1_num(tmp_year[1], 0, 9);
			text_put_numeric(DATE_SET_X + YEAR2, DATE_SET_Y, 1, NUM_PADZERO | NUM_ALIGN_RIGHT, tmp_year[1]);
			check_max_day();
			break;
		case YEAR3:
			tmp_year[2] = dec_1_num(tmp_year[2], 0, 9);
			text_put_numeric(DATE_SET_X + YEAR3, DATE_SET_Y, 1, NUM_PADZERO | NUM_ALIGN_RIGHT, tmp_year[2]);
			check_max_day();
			break;
		case YEAR4:
			tmp_year[3] = dec_1_num(tmp_year[3], 0, 9);
			text_put_numeric(DATE_SET_X + YEAR4, DATE_SET_Y, 1, NUM_PADZERO | NUM_ALIGN_RIGHT, tmp_year[3]);
			check_max_day();
			break;
		case MONTH2:
			tmp_month = dec_1_num(tmp_month, 1, 12);
			text_put_numeric(DATE_SET_X + MONTH1, DATE_SET_Y, 2, NUM_PADZERO | NUM_ALIGN_RIGHT, tmp_month);
			check_max_day();
			break;
		case DATE2:
			year = tmp_year[0]*1000 + tmp_year[1]*100 + tmp_year[2]*10 + tmp_year[3];
			tmp_date = dec_1_num(tmp_date, 1, get_max_month_days(year, tmp_month));
			text_put_numeric(DATE_SET_X + DATE1, DATE_SET_Y, 2, NUM_PADZERO | NUM_ALIGN_RIGHT, tmp_date);
			break;
		default:
			break;
		}
	} else {
		switch(pos) {
		case HOUR2:
			tmp_hour = dec_1_num(tmp_hour, 0, 23);
			text_put_numeric(TIME_SET_X + HOUR1, TIME_SET_Y, 2, NUM_PADZERO | NUM_ALIGN_RIGHT, tmp_hour);
			break;
		case MINUTE1:
			tmp_minute[0] = dec_1_num(tmp_minute[0], 0, 5);
			text_put_numeric(TIME_SET_X + MINUTE1, TIME_SET_Y, 1, NUM_PADZERO | NUM_ALIGN_RIGHT, tmp_minute[0]);
			break;
		case MINUTE2:
			tmp_minute[1] = dec_1_num(tmp_minute[1], 0, 9);
			text_put_numeric(TIME_SET_X + MINUTE2, TIME_SET_Y, 1, NUM_PADZERO | NUM_ALIGN_RIGHT, tmp_minute[1]);
			break;
		case SECOND1:
			tmp_second[0] = dec_1_num(tmp_second[0], 0, 5);
			text_put_numeric(TIME_SET_X + SECOND1, TIME_SET_Y, 1, NUM_PADZERO | NUM_ALIGN_RIGHT, tmp_second[0]);
			break;
		case SECOND2:
			tmp_second[1] = dec_1_num(tmp_second[1], 0, 9);
			text_put_numeric(TIME_SET_X + SECOND2, TIME_SET_Y, 1, NUM_PADZERO | NUM_ALIGN_RIGHT, tmp_second[1]);
			break;
		default:
			break;
		}
	}
}

/* カーソルのある所の値を+1する */
void inc_num_oncursor(int pos, unsigned char dort) {
	unsigned int year;

	if ( !dort ) {
		switch(pos) {
		case YEAR1:
			tmp_year[0] = inc_1_num(tmp_year[0], 9, 0);
			text_put_numeric(DATE_SET_X + YEAR1, DATE_SET_Y, 1, NUM_PADZERO | NUM_ALIGN_RIGHT, tmp_year[0]);
			check_max_day();
			break;
		case YEAR2:
			tmp_year[1] = inc_1_num(tmp_year[1], 9, 0);
			text_put_numeric(DATE_SET_X + YEAR2, DATE_SET_Y, 1, NUM_PADZERO | NUM_ALIGN_RIGHT, tmp_year[1]);
			check_max_day();
			break;
		case YEAR3:
			tmp_year[2] = inc_1_num(tmp_year[2], 9, 0);
			text_put_numeric(DATE_SET_X + YEAR3, DATE_SET_Y, 1, NUM_PADZERO | NUM_ALIGN_RIGHT, tmp_year[2]);
			check_max_day();
			break;
		case YEAR4:
			tmp_year[3] = inc_1_num(tmp_year[3], 9, 0);
			text_put_numeric(DATE_SET_X + YEAR4, DATE_SET_Y, 1, NUM_PADZERO | NUM_ALIGN_RIGHT, tmp_year[3]);
			check_max_day();
			break;
		case MONTH2:
			tmp_month = inc_1_num(tmp_month, 12, 1);
			text_put_numeric(DATE_SET_X + MONTH1, DATE_SET_Y, 2, NUM_PADZERO | NUM_ALIGN_RIGHT, tmp_month);
			check_max_day();
			break;
		case DATE2:
			year = tmp_year[0]*1000 + tmp_year[1]*100 + tmp_year[2]*10 + tmp_year[3];
			tmp_date = inc_1_num(tmp_date, get_max_month_days(year, tmp_month), 1);
			text_put_numeric(DATE_SET_X + DATE1, DATE_SET_Y, 2, NUM_PADZERO | NUM_ALIGN_RIGHT, tmp_date);
			break;
		default:
			break;
		}
	} else {
		switch(pos) {
		case HOUR2:
			tmp_hour = inc_1_num(tmp_hour, 23, 0);
			text_put_numeric(TIME_SET_X + HOUR1, TIME_SET_Y, 2, NUM_PADZERO | NUM_ALIGN_RIGHT, tmp_hour);
			break;
		case MINUTE1:
			tmp_minute[0] = inc_1_num(tmp_minute[0], 5, 0);
			text_put_numeric(TIME_SET_X + MINUTE1, TIME_SET_Y, 1, NUM_PADZERO | NUM_ALIGN_RIGHT, tmp_minute[0]);
			break;
		case MINUTE2:
			tmp_minute[1] = inc_1_num(tmp_minute[1], 9, 0);
			text_put_numeric(TIME_SET_X + MINUTE2, TIME_SET_Y, 1, NUM_PADZERO | NUM_ALIGN_RIGHT, tmp_minute[1]);
			break;
		case SECOND1:
			tmp_second[0] = inc_1_num(tmp_second[0], 5, 0);
			text_put_numeric(TIME_SET_X + SECOND1, TIME_SET_Y, 1, NUM_PADZERO | NUM_ALIGN_RIGHT, tmp_second[0]);
			break;
		case SECOND2:
			tmp_second[1] = inc_1_num(tmp_second[1], 9, 0);
			text_put_numeric(TIME_SET_X + SECOND2, TIME_SET_Y, 1, NUM_PADZERO | NUM_ALIGN_RIGHT, tmp_second[1]);
			break;
		default:
			break;
		}
	}
}

/* 時刻合わせのメイン関数 */
void set_watch_loop() {
	int pos = YEAR1;
	unsigned char dort = 0;	/* date/time = 0/1 */
	unsigned char loop = 1;

	while(loop) {
		switch(key_wait()) {
		case KEY_X1:
			/* -1 */
			dec_num_oncursor(pos, dort);
			break;
		case KEY_X2:
			/* 右へ */
			move_right_cursor((int far *)&pos, (unsigned char far *)&dort);
			break;
		case KEY_X3:
			/* +1 */
			inc_num_oncursor(pos, dort);
			break;
		case KEY_X4:
			/* 左へ */
			move_left_cursor((int far *)&pos, (unsigned char far *)&dort);
			break;
		case KEY_START:
			/* set */
			set_watch();
			/* 続いて後処理へ */
		case KEY_Y3:
			/* cancel */
			cursor_display(OFF);
			loop = 0;
		default:
			break;
		}
	}
}

/* 時刻合わせ機能の初期設定 */
void init_set_watch_display() {
	unsigned int year;
	int month, date, hour, minute, second;
	int mod;

	year = rtc_get_year() + yy;
	month = rtc_get_month();
	date = rtc_get_date();
	hour = rtc_get_hour();
	minute = rtc_get_minute();
	second = rtc_get_second();

	/* 画面設定 */
	font_set_color(0x03);
	text_put_string(SET_TITLE_X, SET_TITLE_Y, "時刻合わせ");
	text_put_string(DATE_SET_X, DATE_SET_Y, "    /  /  ");
	text_put_string(TIME_SET_X, TIME_SET_Y, "  :  .  ");
	text_put_string(0, 17, "set: START  cancel: Y3      ");

	text_put_numeric(DATE_SET_X          , DATE_SET_Y, 4, NUM_PADZERO | NUM_ALIGN_RIGHT, year);
	text_put_numeric(DATE_SET_X + MONTH1 , DATE_SET_Y, 2, NUM_PADZERO | NUM_ALIGN_RIGHT, month);
	text_put_numeric(DATE_SET_X + DATE1  , DATE_SET_Y, 2, NUM_PADZERO | NUM_ALIGN_RIGHT, date);
	text_put_numeric(TIME_SET_X          , TIME_SET_Y, 2, NUM_PADZERO | NUM_ALIGN_RIGHT, hour);
	text_put_numeric(TIME_SET_X + MINUTE1, TIME_SET_Y, 2, NUM_PADZERO | NUM_ALIGN_RIGHT, minute);
	text_put_numeric(TIME_SET_X + SECOND1, TIME_SET_Y, 2, NUM_PADZERO | NUM_ALIGN_RIGHT, second);

	/* カーソル設定 */
	cursor_set_location(DATE_SET_X, DATE_SET_Y, 1, 1);
	cursor_set_type(1, 30);
	cursor_display(ON);

	/* 時刻設定時の一時データ保存領域 */
	tmp_year[0] = (int)(year / 1000);
	mod = year % 1000;
	tmp_year[1] = (int)(mod / 100);
	mod = mod % 100;
	tmp_year[2] = (int)(mod / 10);
	tmp_year[3] = mod % 10;
	tmp_month = month;
	tmp_date = date;
	tmp_hour = hour;
	tmp_minute[0]  = (int)(minute / 10);
	tmp_minute[1] = minute % 10;
	tmp_second[0] = (int)(second / 10);
	tmp_second[1] = second % 10;
}

void main(int argc, char *argv[]) {
	char loop = 1;

	yy = 2000;
	init_watch_display();
	show_watch();

	/* タイマ割り込みの設定 */
	set_callback(SYS_INT_VBLANK_COUNTUP, int_show_watch);
	timer_enable(TIMER_VBLANK, TIMER_AUTOPRESET, 3);

	while(loop) {
		switch(key_wait()) {
		case KEY_Y1:
			/* カレンダー */
			calendar(yy);
			init_watch_display();
			break;
		case KEY_Y3:
			/* 時刻合わせ機能 */
			init_set_watch_display();
			set_watch_loop();
			init_watch_display();
			break;
		case KEY_START:
			loop = 0;
			break;
		default:
			break;
		}
	}
}
