#include <stdio.h>

#include "oswald.h"
#include "oswald_main.h"
#include "oswald_watch_faces.h"
#include "oswald_graphics.h"
#include "oswald_hal.h"

#include "oswald_screens.h"

#if defined(__GNUC__) && (__MSP430X__ > 0)
__attribute__((__far__))
#endif
#include "bitmaps/timesetup_icon.xbm"

#if defined(__GNUC__) && (__MSP430X__ > 0)
__attribute__((__far__))
#endif
#include "bitmaps/stopwatch_icon.xbm"

#if defined(__GNUC__) && (__MSP430X__ > 0)
__attribute__((__far__))
#endif
#include "bitmaps/alarm_icon.xbm"

#if defined(__GNUC__) && (__MSP430X__ > 0)
__attribute__((__far__))
#endif
#include "bitmaps/startstopbutton_icon.xbm"

#if defined(__GNUC__) && (__MSP430X__ > 0)
__attribute__((__far__))
#endif
#include "bitmaps/lapsebutton_icon.xbm"

#if defined(__GNUC__) && (__MSP430X__ > 0)
__attribute__((__far__))
#endif
#include "bitmaps/upbutton_icon.xbm"

#if defined(__GNUC__) && (__MSP430X__ > 0)
__attribute__((__far__))
#endif
#include "bitmaps/downbutton_icon.xbm"

#if defined(__GNUC__) && (__MSP430X__ > 0)
__attribute__((__far__))
#endif
#include "bitmaps/Bluetooth_icon.xbm"

#if defined(__GNUC__) && (__MSP430X__ > 0)
__attribute__((__far__))
#endif
#include "bitmaps/info_icon.xbm"

#if defined(__GNUC__) && (__MSP430X__ > 0)
__attribute__((__far__))
#endif
#include "bitmaps/acc_icon.xbm"



/*
 * Common event handler part of the watch faces
 */
typedef struct {
	void (*screendraw_func)(boolean show_seconds);
	boolean show_seconds;
	boolean analogue;
} idle_data_t;
static idle_data_t idle_screen = {
	DrawLcdDigitalClock,
	TRUE,
	FALSE,
};
 
event_ret_t idle_handle_user_buttons(watch_button button)
{
	switch (button) {
		case BUTTON_A:
			if (idle_screen.show_seconds)
				idle_screen.show_seconds = FALSE;
			else
				idle_screen.show_seconds = TRUE;
			break;
		case BUTTON_B:
			if (idle_screen.analogue == TRUE) {
				idle_screen.analogue = FALSE;
				idle_screen.screendraw_func = DrawLcdDigitalClock;
			} else {
				idle_screen.analogue = TRUE;
				idle_screen.screendraw_func = DrawLcdAnaClock;
			};
			break;
		case BUTTON_C:
			return EVENT_RET_UNHANDLED;
			break;
		case BUTTON_F:
			OswaldState.screen_id = DATETIME_SETTING_SCREEN;
			OswaldState.screen = &OswaldScreens[OswaldState.screen_id];
			OswaldState.screen->event_func(EVENT_SCREEN_VISIBLE, NULL);
			return EVENT_RET_HANDLED;
			break;
		default:
			return EVENT_RET_UNHANDLED;
			break;
	};

	idle_screen.screendraw_func(idle_screen.show_seconds);

	return EVENT_RET_HANDLED;
}

event_ret_t idle_handle_events(uint16_t event, void *data)
{
	switch (event) {
		case EVENT_ONE_SEC_TIMER:
		case EVENT_SCREEN_VISIBLE:
			idle_screen.screendraw_func(idle_screen.show_seconds);
			return EVENT_RET_HANDLED;
			break;
		case EVENT_USER_BUTTONS:
			dbg_out("button event %d\n", *(int *)data);
			return idle_handle_user_buttons(*(watch_button *)data);
			break;
		default:
			return EVENT_RET_UNHANDLED;
			break;
	};
	return EVENT_RET_UNHANDLED;
}


/*
 * Accelerometer and sensor display screen
 */
typedef struct {
	accel_data_t accdata;
} accelscreen_data_t;
static accelscreen_data_t accel_screen = {
	{ 0, 0, 0},
};

void draw_accel_screen(accel_data_t *accel_data)
{
	uint8_t x,y;

	hal_lcd_clear_display();

	oswald_draw_bitmap(36, 0, acc_icon_width, acc_icon_height, acc_icon_bits);

	oswald_write_string(1, 40, FONT_6x9, "X:");
	oswald_write_number(15, 40, FONT_6x9, accel_data->x);
	oswald_write_string(1, 52, FONT_6x9, "Y:");
	oswald_write_number(15, 52, FONT_6x9, accel_data->y);
	oswald_write_string(1, 64, FONT_6x9, "Z:");
	oswald_write_number(15, 64, FONT_6x9, accel_data->z);

	oswald_write_string(1, 85, FONT_6x9, "Light:");
	oswald_write_number(50, 85, FONT_6x9, 0);

	oswald_draw_line(40, 30, 92, 30);
	oswald_draw_line(92, 30, 92, 82);
	oswald_draw_line(40, 82, 92, 82);
	oswald_draw_line(40, 82, 40, 30);

	x = 41+25+((accel_data->x * 50) / (254));
	y = 31+25-((accel_data->y * 50) / (254));
	oswald_draw_pixel(x, y);
	oswald_draw_pixel(x+1, y);
	oswald_draw_pixel(x-1, y);
	oswald_draw_pixel(x, y+1);
	oswald_draw_pixel(x, y-1);

	hal_lcd_update_display();
}

event_ret_t accel_handle_events(uint16_t event, void *data)
{
	switch (event) {
		case EVENT_SCREEN_VISIBLE:
			draw_accel_screen(&accel_screen.accdata);
			hal_accelerometer_enable();
			return EVENT_RET_HANDLED;
			break;
		case EVENT_SCREEN_DESTROY:
			hal_accelerometer_disable();
			return EVENT_RET_HANDLED;
			break;
		case EVENT_ACCEL_UPDATE: {
			accel_data_t *accel_data = (accel_data_t *)data;
			accel_screen.accdata.x = accel_data->x;
			accel_screen.accdata.y = accel_data->y;
			accel_screen.accdata.z = accel_data->z;
			draw_accel_screen(&accel_screen.accdata);
			};
			return EVENT_RET_HANDLED;
			break;
		case EVENT_USER_BUTTONS:
			dbg_out("button event %d\n", *(int *)data);
			break;
		default:
			return EVENT_RET_UNHANDLED;
			break;
	};
	return EVENT_RET_UNHANDLED;
}


/*
 * Date / time setup screen
 */
typedef struct {
	uint8_t pos;
	boolean set_mode;
	boolean on;
} datetime_setup_data_t;
static datetime_setup_data_t dt_setup_screen = {
	0,
	FALSE,
	TRUE
};

void draw_datetime_setup_screen(datetime_setup_data_t *sdata)
{
	hal_lcd_clear_display();

	oswald_draw_bitmap(36, 0, timesetup_icon_width, timesetup_icon_height, timesetup_icon_bits);

	oswald_draw_bitmap(81, 6, upbutton_icon_width, upbutton_icon_height, upbutton_icon_bits);
	oswald_draw_bitmap(81, 38, downbutton_icon_width, downbutton_icon_height, downbutton_icon_bits);

	if ((sdata->pos == 0 && sdata->on) || sdata->pos != 0) {
		oswald_write_character(2, 30, FONT_LCD13x21, (OswaldClk.hour / 10));
		oswald_write_character(15, 30, FONT_LCD13x21, (OswaldClk.hour % 10));
	}
	oswald_write_character(25, 30, FONT_LCD13x21, 10);

	if ((sdata->pos == 1 && sdata->on) || sdata->pos != 1) {
		oswald_write_character(34, 30, FONT_LCD13x21, (OswaldClk.minute / 10));
		oswald_write_character(47, 30, FONT_LCD13x21, (OswaldClk.minute % 10));
	}

	if ((sdata->pos == 2 && sdata->on) || sdata->pos != 2) {
		oswald_write_character(61, 38, FONT_LCD8x13, (OswaldClk.second / 10));
		oswald_write_character(69, 38, FONT_LCD8x13, (OswaldClk.second % 10));
	}


	if ((sdata->pos == 3 && sdata->on) || sdata->pos != 3) {
		oswald_write_number(2, 55, FONT_DROID8x12, OswaldClk.day);
	}
	oswald_write_character(15, 55, FONT_DROID8x12, '.');
	if ((sdata->pos == 4 && sdata->on) || sdata->pos != 4) {
		oswald_write_number(21, 55, FONT_DROID8x12, OswaldClk.month);
	}
	oswald_write_character(36, 55, FONT_DROID8x12, '.');
	if ((sdata->pos == 5 && sdata->on) || sdata->pos != 5) {
		oswald_write_number(43, 55, FONT_DROID8x12, OswaldClk.year);
	}

	if ((sdata->pos == 6 && sdata->on) || sdata->pos != 6) {
		if (OswaldClk.clk24hr) {
			oswald_write_character(2, 76, FONT_6x9, 'x');
		} else {
			oswald_write_character(2, 76, FONT_6x9, '_');
		}
	}
	oswald_write_string(15, 73, FONT_DROID8x12, "24hr");

	if ((sdata->pos == 7 && sdata->on) || sdata->pos != 7) {
		if (OswaldClk.day_first) {
			oswald_write_character(2, 86, FONT_6x9, 'x');
		} else {
			oswald_write_character(2, 86, FONT_6x9, '_');
		}
	}
	oswald_write_string(15, 83, FONT_DROID8x12, "dd.mm.  mm/dd");

	hal_lcd_update_display();
}

void datetime_handle_updown(uint8_t pos, int8_t incr)
{
	switch (pos) {
		case 0: // hour
			if (OswaldClk.hour == 0 && incr == -1) {
				OswaldClk.hour = 23;
				break;
			};
			OswaldClk.hour += incr;
			if (OswaldClk.hour > 23)
				OswaldClk.hour = 0;
			break;
		case 1: // minute
			if (OswaldClk.minute == 0 && incr == -1) {
				OswaldClk.minute = 59;
				break;
			};
			OswaldClk.minute += incr;
			if (OswaldClk.minute > 59)
				OswaldClk.minute = 0;
			break;
		case 2: // second
			OswaldClk.second = 0;
			break;
		case 3: // day
			if (OswaldClk.day == 1 && incr == -1) {
				OswaldClk.day = 31;
				break;
			};
			OswaldClk.day += incr;
			if (OswaldClk.day > 31)
				OswaldClk.day = 1;
			break;
		case 4: // month
			if (OswaldClk.month == 1 && incr == -1) {
				OswaldClk.month = 12;
				break;
			};
			OswaldClk.month += incr;
			if (OswaldClk.month > 12)
				OswaldClk.month = 1;
			break;
		case 5: // year
			OswaldClk.year += incr;
			break;
		case 6: // 24hr / 12hr
			if (OswaldClk.clk24hr)
				OswaldClk.clk24hr = FALSE;
			else
				OswaldClk.clk24hr = TRUE;
			break;
		case 7: // dd.mm. / mm/dd
			if (OswaldClk.day_first)
				OswaldClk.day_first = FALSE;
			else
				OswaldClk.day_first = TRUE;
			break;
		default:
			break;
	};
	if (pos == 2)
		hal_set_rtc(&OswaldClk, TRUE);
	else
		hal_set_rtc(&OswaldClk, FALSE);
}

event_ret_t handle_setup_datetime_buttons(watch_button button, datetime_setup_data_t *sdata)
{
	switch (button) {
		case BUTTON_A:
			datetime_handle_updown(sdata->pos, 1);
			break;
		case BUTTON_B:
			datetime_handle_updown(sdata->pos, -1);
			break;
		case BUTTON_C:
			sdata->pos++;
			sdata->pos %= 8;
			break;
		case BUTTON_F:
			OswaldState.screen->event_func(EVENT_SCREEN_DESTROY, NULL);
			OswaldState.screen_id = IDLE_SCREEN;
			OswaldState.screen = &OswaldScreens[OswaldState.screen_id];
			OswaldState.screen->event_func(EVENT_SCREEN_VISIBLE, NULL);
			return EVENT_RET_HANDLED;
			break;
		default:
			return EVENT_RET_UNHANDLED;
			break;
	}
	draw_datetime_setup_screen(sdata);
	return EVENT_RET_HANDLED;
}

event_ret_t datetime_setup_events(uint16_t event, void *data)
{
	switch (event) {
		case EVENT_SCREEN_VISIBLE:
			dt_setup_screen.pos = 0;
			draw_datetime_setup_screen(&dt_setup_screen);
			hal_enable_halfsecond_timer();
			return EVENT_RET_HANDLED;
			break;
		case EVENT_SCREEN_DESTROY:
			hal_disable_halfsecond_timer();
			return EVENT_RET_HANDLED;
			break;
		case EVENT_USER_BUTTONS:
			dbg_out("button event %d\n", *(int *)data);
			return handle_setup_datetime_buttons(*(watch_button *)data, &dt_setup_screen);
			break;
		case EVENT_HALF_SEC_TIMER:
			if (dt_setup_screen.on)
				dt_setup_screen.on = FALSE;
			else
				dt_setup_screen.on = TRUE;
			draw_datetime_setup_screen(&dt_setup_screen);
			return EVENT_RET_HANDLED;
			break;
		default:
			return EVENT_RET_UNHANDLED;
			break;
	};
	return EVENT_RET_UNHANDLED;
}


/*
 * Alarm setup screen
 */
typedef struct {
	uint8_t pos;
	boolean set_mode;
	boolean on;
} alarm_setup_data_t;
static alarm_setup_data_t alarm_setup_screen = {
	0,
	FALSE,
	TRUE
};

void draw_alarm_setup_screen(alarm_setup_data_t *sdata)
{
	hal_lcd_clear_display();

	oswald_draw_bitmap(36, 0, alarm_icon_width, alarm_icon_height, alarm_icon_bits);

	oswald_draw_bitmap(81, 6, upbutton_icon_width, upbutton_icon_height, upbutton_icon_bits);
	oswald_draw_bitmap(81, 38, downbutton_icon_width, downbutton_icon_height, downbutton_icon_bits);

	if ((sdata->pos == 0 && sdata->on) || sdata->pos != 0) {
		oswald_write_character(18, 30, FONT_LCD13x21, (OswaldAlarm.hour / 10));
		oswald_write_character(32, 30, FONT_LCD13x21, (OswaldAlarm.hour % 10));
	}
	oswald_write_character(42, 30, FONT_LCD13x21, 10);

	if ((sdata->pos == 1 && sdata->on) || sdata->pos != 1) {
		oswald_write_character(53, 30, FONT_LCD13x21, (OswaldAlarm.minute / 10));
		oswald_write_character(67, 30, FONT_LCD13x21, (OswaldAlarm.minute % 10));
	}

	oswald_write_character(3, 55, FONT_6x9, 'S');
	oswald_write_character(15, 55, FONT_6x9, 'M');
	oswald_write_character(27, 55, FONT_6x9, 'T');
	oswald_write_character(39, 55, FONT_6x9, 'W');
	oswald_write_character(51, 55, FONT_6x9, 'T');
	oswald_write_character(63, 55, FONT_6x9, 'F');
	oswald_write_character(75, 55, FONT_6x9, 'S');

	if ((sdata->pos == 2 && sdata->on) || sdata->pos != 2)
		oswald_write_character(3, 65, FONT_6x9, (OswaldAlarm.wday & WDAY_SUNDAY) ? 'x' : '_');
	if ((sdata->pos == 3 && sdata->on) || sdata->pos != 3)
		oswald_write_character(15, 65, FONT_6x9, (OswaldAlarm.wday & WDAY_MONDAY) ? 'x' : '_');
	if ((sdata->pos == 4 && sdata->on) || sdata->pos != 4)
		oswald_write_character(27, 65, FONT_6x9, (OswaldAlarm.wday & WDAY_TUESDAY) ? 'x' : '_');
	if ((sdata->pos == 5 && sdata->on) || sdata->pos != 5)
		oswald_write_character(39, 65, FONT_6x9, (OswaldAlarm.wday & WDAY_WEDNESDAY) ? 'x' : '_');
	if ((sdata->pos == 6 && sdata->on) || sdata->pos != 6)
		oswald_write_character(51, 65, FONT_6x9, (OswaldAlarm.wday & WDAY_THURSDAY) ? 'x' : '_');
	if ((sdata->pos == 7 && sdata->on) || sdata->pos != 7)
		oswald_write_character(63, 65, FONT_6x9, (OswaldAlarm.wday & WDAY_FRIDAY) ? 'x' : '_');
	if ((sdata->pos == 8 && sdata->on) || sdata->pos != 8)
		oswald_write_character(75, 65, FONT_6x9, (OswaldAlarm.wday & WDAY_SATURDAY) ? 'x' : '_');

	hal_lcd_update_display();
}

void alarm_handle_updown(uint8_t pos, int8_t incr)
{
	switch (pos) {
		case 0: // hour
			if (OswaldAlarm.hour == 0 && incr == -1) {
				OswaldAlarm.hour = 23;
				break;
			};
			OswaldAlarm.hour += incr;
			if (OswaldAlarm.hour > 23)
				OswaldAlarm.hour = 0;
			break;
		case 1: // minute
			if (OswaldAlarm.minute == 0 && incr == -1) {
				OswaldAlarm.minute = 59;
				break;
			};
			OswaldAlarm.minute += incr;
			if (OswaldAlarm.minute > 59)
				OswaldAlarm.minute = 0;
			break;
		case 2: // sunday
			OswaldAlarm.wday ^= WDAY_SUNDAY;
			break;
		case 3: // monday
			OswaldAlarm.wday ^= WDAY_MONDAY;
			break;
		case 4: // tuesday
			OswaldAlarm.wday ^= WDAY_TUESDAY;
			break;
		case 5: // wednesday
			OswaldAlarm.wday ^= WDAY_WEDNESDAY;
			break;
		case 6: // thursday
			OswaldAlarm.wday ^= WDAY_THURSDAY;
			break;
		case 7: // friday
			OswaldAlarm.wday ^= WDAY_FRIDAY;
			break;
		case 8: // saturday
			OswaldAlarm.wday ^= WDAY_SATURDAY;
			break;
		default:
			break;
	};
}

event_ret_t handle_setup_alarm_buttons(watch_button button, alarm_setup_data_t *sdata)
{
	if (alarm_setup_screen.set_mode) {
		switch (button) {
			case BUTTON_A:
				alarm_handle_updown(sdata->pos, 1);
				break;
			case BUTTON_B:
				alarm_handle_updown(sdata->pos, -1);
				break;
			case BUTTON_C:
				sdata->pos++;
				sdata->pos %= 9;
				break;
			case BUTTON_F:
				alarm_setup_screen.set_mode = FALSE;
				break;
			default:
				return EVENT_RET_UNHANDLED;
				break;
		}
	} else {
		switch (button) {
			case BUTTON_F:
				alarm_setup_screen.set_mode = TRUE;
				break;
			default:
				return EVENT_RET_UNHANDLED;
				break;
		}
	}
	draw_alarm_setup_screen(sdata);

	return EVENT_RET_HANDLED;
}

event_ret_t alarm_setup_events(uint16_t event, void *data)
{
	switch (event) {
		case EVENT_SCREEN_VISIBLE:
			alarm_setup_screen.pos = 0;
			alarm_setup_screen.on = TRUE;
			alarm_setup_screen.set_mode = FALSE;
			draw_alarm_setup_screen(&alarm_setup_screen);
			hal_enable_halfsecond_timer();
			return EVENT_RET_HANDLED;
			break;
		case EVENT_SCREEN_DESTROY:
			hal_disable_halfsecond_timer();
			return EVENT_RET_HANDLED;
			break;
		case EVENT_USER_BUTTONS:
			dbg_out("button event %d\n", *(int *)data);
			return handle_setup_alarm_buttons(*(watch_button *)data, &alarm_setup_screen);
			break;
		case EVENT_HALF_SEC_TIMER:
			if (alarm_setup_screen.set_mode) {
				if (alarm_setup_screen.on)
					alarm_setup_screen.on = FALSE;
				else
					alarm_setup_screen.on = TRUE;
			} else
				alarm_setup_screen.on = TRUE;
			draw_alarm_setup_screen(&alarm_setup_screen);
			return EVENT_RET_HANDLED;
			break;
		default:
			return EVENT_RET_UNHANDLED;
			break;
	};
	return EVENT_RET_UNHANDLED;
}


/*
 * Test menu
 */
typedef struct {
	uint8_t menu_pos;
} test_menu_t;
static test_menu_t test_menu = { 0 };

void draw_menu_test_screen(void)
{
	hal_lcd_clear_display();
#if 0
	SetFont(MetaWatch16);
	WriteLcdString(2, 2, "Menu");
	SetFont(MetaWatch7);
	WriteLcdString(2, 20, "Item 1");
	WriteLcdString(2, 29, "Item 2");
	WriteLcdString(2, 38, "Item 3");
	WriteLcdString(2, 47, "Item 4");
	WriteLcdString(2, 56, "Item 5");

	WriteLcdString(50, 20+(9*test_menu.menu_pos), "*");
#endif
	oswald_write_string(2, 2, FONT_DROID11x14b, "Menu");

	oswald_write_string(2, 20, FONT_DROID8x12, "Item 1");
	oswald_write_string(2, 29, FONT_DROID8x12, "Item 2");
	oswald_write_string(2, 38, FONT_DROID8x12, "Item 3");
	oswald_write_string(2, 47, FONT_DROID8x12, "Item 4");
	oswald_write_string(2, 56, FONT_DROID8x12, "Item 5");

	oswald_write_character(50, 18+(9*test_menu.menu_pos), FONT_6x9, 0x11);

	hal_lcd_update_display();
}

event_ret_t handle_menu_user_buttons(watch_button button)
{
	switch (button) {
		case BUTTON_A:
			test_menu.menu_pos--;
			test_menu.menu_pos %= 5;
			break;
		case BUTTON_B:
			test_menu.menu_pos++;
			test_menu.menu_pos %= 5;
			break;
		default:
			return EVENT_RET_UNHANDLED;
			break;
	}
	draw_menu_test_screen();
	return EVENT_RET_HANDLED;
}

event_ret_t test_menu_handle_events(uint16_t event, void *data)
{
	switch (event) {
		case EVENT_USER_BUTTONS:
			dbg_out("button event %d\n", *(int *)data);
			return handle_menu_user_buttons(*(watch_button *)data);
			break;
		case EVENT_SCREEN_VISIBLE:
			test_menu.menu_pos = 0;
			draw_menu_test_screen();
			break;
		default:
			return EVENT_RET_UNHANDLED;
			break;
	};
	return EVENT_RET_HANDLED;
}


/*
 * Stop Watch
 */
typedef struct {
	uint8_t hr;
	uint8_t min;
	uint8_t sec;
	uint8_t csec;
	uint8_t lapse_hr;
	uint8_t lapse_min;
	uint8_t lapse_sec;
	uint8_t lapse_csec;
	boolean running;
} stopwatch_data_t;
static stopwatch_data_t stopwatch_screen = { 0, 0, 0, 0, 0, 0, 0, 0, FALSE };

#if 0
static void update_stop_watch_screen(stopwatch_data_t *sdata)
{
	//char tstr[16];
#if 0
	SetFont(MetaWatchMonospaced10);

	snprintf(tstr, 16, "%02d:%02d:%02d.%1d", sdata->hr, sdata->min, sdata->sec, sdata->csec / 10);
	WriteLcdString(5, 40, tstr);
	snprintf(tstr, 16, "%02d:%02d:%02d.%02d", sdata->lapse_hr, sdata->lapse_min, sdata->lapse_sec, sdata->lapse_csec);
	WriteLcdString(5, 60, tstr);
#endif
#if 0
	snprintf(tstr, 16, "%02d:%02d:%02d.%1d", sdata->hr, sdata->min, sdata->sec, sdata->csec / 10);
	oswald_write_string(5, 40, FONT_6x9, tstr);

	snprintf(tstr, 16, "%02d:%02d:%02d.%02d", sdata->lapse_hr, sdata->lapse_min, sdata->lapse_sec, sdata->lapse_csec);
	oswald_write_string(5, 60, FONT_6x9, tstr);
#endif

	hal_lcd_update_display();
}
#endif

static void draw_stop_watch_screen(stopwatch_data_t *sdata)
{
	int gRow = 1;
	int gColumn = 35;

	hal_lcd_clear_display();

	oswald_draw_bitmap(36, 0, stopwatch_icon_width, stopwatch_icon_height, stopwatch_icon_bits);
	oswald_draw_bitmap(81, 6, startstopbutton_icon_width, startstopbutton_icon_height, startstopbutton_icon_bits);
	oswald_draw_bitmap(81, 38, lapsebutton_icon_width, lapsebutton_icon_height, lapsebutton_icon_bits);

#if 0
	update_stop_watch_screen(sdata);
#else
	gRow += 3 + oswald_write_character(gRow, gColumn, FONT_LCD13x21, (sdata->hr % 10));
	gRow += oswald_write_character(gRow, gColumn, FONT_LCD13x21, (sdata->min / 10));
	gRow += 3 + oswald_write_character(gRow, gColumn, FONT_LCD13x21, (sdata->min % 10));
	gRow += oswald_write_character(gRow, gColumn, FONT_LCD13x21, (sdata->sec / 10));
	gRow += 3 + oswald_write_character(gRow, gColumn, FONT_LCD13x21, (sdata->sec % 10));
	gRow += oswald_write_character(gRow, gColumn, FONT_LCD8x13, (sdata->csec / 10));

	gRow = 6;
	gColumn = 62;
	gRow += 13 + oswald_write_character(gRow, gColumn, FONT_LCD8x13, (sdata->lapse_hr % 10));
	gRow += oswald_write_character(gRow, gColumn, FONT_LCD8x13, (sdata->lapse_min / 10));
	gRow += 13 + oswald_write_character(gRow, gColumn, FONT_LCD8x13, (sdata->lapse_min % 10));
	gRow += oswald_write_character(gRow, gColumn, FONT_LCD8x13, (sdata->lapse_sec / 10));
	gRow += 3 + oswald_write_character(gRow, gColumn, FONT_LCD8x13, (sdata->lapse_sec % 10));
	gRow += oswald_write_character(gRow, gColumn, FONT_LCD8x13, (sdata->lapse_csec / 10));
	gRow += oswald_write_character(gRow, gColumn, FONT_LCD8x13, (sdata->lapse_csec % 10));

	hal_lcd_update_display();
#endif
}

event_ret_t handle_stop_watch_buttons(watch_button button)
{
	switch (button) {
		case BUTTON_A: // start/stop
			if (stopwatch_screen.running) {
				hal_disable_centisecond_timer();
				stopwatch_screen.running = FALSE;
			} else {
				hal_enable_centisecond_timer();
				stopwatch_screen.running = TRUE;
			}
			return EVENT_RET_HANDLED;
			break;
		case BUTTON_B: // lapse
			stopwatch_screen.lapse_hr = stopwatch_screen.hr;
			stopwatch_screen.lapse_min = stopwatch_screen.min;
			stopwatch_screen.lapse_sec = stopwatch_screen.sec;
			stopwatch_screen.lapse_csec = stopwatch_screen.csec;
			return EVENT_RET_HANDLED;
			break;
		case BUTTON_F: // reset
			stopwatch_screen.hr = 0;
			stopwatch_screen.min = 0;
			stopwatch_screen.sec = 0;
			stopwatch_screen.csec = 0;
			stopwatch_screen.lapse_hr = 0;
			stopwatch_screen.lapse_min = 0;
			stopwatch_screen.lapse_sec = 0;
			stopwatch_screen.lapse_csec = 0;
			return EVENT_RET_HANDLED;
			break;
		default:
			return EVENT_RET_UNHANDLED;
			break;
	}
	return EVENT_RET_UNHANDLED;
}

event_ret_t stop_watch_handle_events(uint16_t event, void *data)
{
	switch (event) {
		case EVENT_USER_BUTTONS:
			dbg_out("button event %d\n", *(int *)data);
			return handle_stop_watch_buttons(*(watch_button *)data);
			//update_stop_watch_screen(&stopwatch_screen);
			draw_stop_watch_screen(&stopwatch_screen);
			break;
		case EVENT_SCREEN_VISIBLE:
			hal_lcd_clear_display();
			draw_stop_watch_screen(&stopwatch_screen);
			return EVENT_RET_HANDLED;
			break;
		case EVENT_SCREEN_DESTROY:
			hal_disable_centisecond_timer();
			stopwatch_screen.running = FALSE;
			return EVENT_RET_HANDLED;
			break;
		case EVENT_CS_TIMER:
			stopwatch_screen.csec++;
			if (stopwatch_screen.csec > 99) {
				stopwatch_screen.csec = 0;
				stopwatch_screen.sec++;
			};
			if (stopwatch_screen.sec > 59) {
				stopwatch_screen.sec = 0;
				stopwatch_screen.min++;
			};
			if (stopwatch_screen.min > 59) {
				stopwatch_screen.min = 0;
				stopwatch_screen.hr++;
			};
			if (stopwatch_screen.hr > 59) {
				stopwatch_screen.hr = 0;
			};
			if (stopwatch_screen.csec % 10 == 0)
				draw_stop_watch_screen(&stopwatch_screen);
				//update_stop_watch_screen(&stopwatch_screen);
			return EVENT_RET_HANDLED;
			break;
		default:
			return EVENT_RET_UNHANDLED;
			break;
	};
	return EVENT_RET_HANDLED;
}


/*
 * Alarm screen, shown when alarm is fired
 */
void draw_alarm_screen(void)
{
	hal_lcd_clear_display();

	oswald_draw_bitmap(36, 20, alarm_icon_width, alarm_icon_height, alarm_icon_bits);

	hal_lcd_update_display();
}

event_ret_t alarm_handle_events(uint16_t event, void *data)
{
	switch (event) {
		case EVENT_SCREEN_VISIBLE:
			draw_alarm_screen();
			hal_enable_halfsecond_timer();
			hal_vibration_set_state(TRUE);
			return EVENT_RET_HANDLED;
			break;
		case EVENT_SCREEN_DESTROY:
			hal_disable_halfsecond_timer();
			hal_lcd_set_backlight(FALSE);
			hal_vibration_set_state(FALSE);
			return EVENT_RET_HANDLED;
			break;
		case EVENT_USER_BUTTONS:
			dbg_out("button event %d\n", *(int *)data);
			return EVENT_RET_UNHANDLED;
			break;
		case EVENT_HALF_SEC_TIMER:
			hal_lcd_set_backlight(!hal_lcd_get_backlight());
			hal_vibration_set_state(!hal_vibration_get_state());
			dbg_out("timer\n");
			return EVENT_RET_HANDLED;
			break;
		default:
			return EVENT_RET_UNHANDLED;
			break;
	};
	return EVENT_RET_HANDLED;
}


/*
 * Bluetooth setup screen
 */
typedef struct {
	uint8_t pos;
	boolean bt_en;
	boolean set_mode;
	boolean on;
} bluetooth_data_t;
static bluetooth_data_t bluetooth_screen = {
	0,
	FALSE,
	FALSE,
	TRUE
};

void draw_bluetooth_screen(bluetooth_data_t *sdata)
{
	char bstr[20];
	uint8_t *bd_addr;

	hal_lcd_clear_display();

	oswald_draw_bitmap(36, 0, Bluetooth_icon_width, Bluetooth_icon_height, Bluetooth_icon_bits);

	oswald_draw_bitmap(81, 6, upbutton_icon_width, upbutton_icon_height, upbutton_icon_bits);
	oswald_draw_bitmap(81, 38, downbutton_icon_width, downbutton_icon_height, downbutton_icon_bits);

	oswald_write_string(1, 30, FONT_DROID8x12, "Enable:");
	if ((sdata->pos == 0 && sdata->on) || sdata->pos != 0) {
		oswald_write_character(53, 30, FONT_DROID8x12, bluetooth_screen.bt_en ? 'x' : '_');
	}
	oswald_write_string(1, 40, FONT_DROID8x12, "State:");
	switch (hal_bluetooth_get_state()) {
		case BLUETOOTH_OFF:
			oswald_write_string(53, 40, FONT_DROID8x12, "off");
			break;
		case BLUETOOTH_ON:
			oswald_write_string(53, 40, FONT_DROID8x12, "on");
			break;
		case BLUETOOTH_CONNECTED:
			oswald_write_string(53, 40, FONT_DROID8x12, "conn.");
			break;
		default:
			break;
	};
	oswald_write_string(1, 50, FONT_DROID8x12, "Visible:");
	if ((sdata->pos == 1 && sdata->on) || sdata->pos != 1) {
		oswald_write_character(53, 50, FONT_DROID8x12, hal_bluetooth_get_visible() ? 'x' : '_');
	}

	if (hal_bluetooth_get_state() >= BLUETOOTH_ON) {
		bd_addr = hal_bluetooth_get_local_bdaddr();
		snprintf(bstr, 20, "%02x:%02x:%02x:%02x:%02x:%02x", bd_addr[5], bd_addr[4], bd_addr[3], bd_addr[2], bd_addr[1], bd_addr[0]);
		oswald_write_string(2, 85, FONT_5x7, bstr);
	} else {
	}

	hal_lcd_update_display();
}

void bluetooth_handle_updown(uint8_t pos, int8_t incr)
{
	switch (pos) {
		case 0:
			if (hal_bluetooth_get_state() >= BLUETOOTH_ON) {
				hal_bluetooth_set_state(BLUETOOTH_OFF);
				bluetooth_screen.bt_en = FALSE;
			} else {
				hal_bluetooth_set_state(BLUETOOTH_ON);
				bluetooth_screen.bt_en = TRUE;
			}
			break;
		case 1:
			if (hal_bluetooth_get_state() >= BLUETOOTH_ON && !hal_bluetooth_get_visible()) {
				hal_bluetooth_set_visible(TRUE);
			} else {
				hal_bluetooth_set_visible(FALSE);
			}
			break;
		case 2:
			break;
		case 3:
			break;
		case 4:
			break;
		case 5:
			break;
		case 6:
			break;
		case 7:
			break;
		case 8:
			break;
		default:
			break;
	};
}

event_ret_t handle_bluetooth_buttons(watch_button button, bluetooth_data_t *sdata)
{
	if (bluetooth_screen.set_mode) {
		switch (button) {
			case BUTTON_A:
				bluetooth_handle_updown(sdata->pos, 1);
				break;
			case BUTTON_B:
				bluetooth_handle_updown(sdata->pos, -1);
				break;
			case BUTTON_C:
				sdata->pos++;
				sdata->pos %= 2;
				break;
			case BUTTON_F:
				bluetooth_screen.set_mode = FALSE;
				break;
			default:
				return EVENT_RET_UNHANDLED;
				break;
		}
	} else {
		switch (button) {
			case BUTTON_F:
				bluetooth_screen.set_mode = TRUE;
				break;
			default:
				return EVENT_RET_UNHANDLED;
				break;
		}
	}

	draw_bluetooth_screen(sdata);

	return EVENT_RET_HANDLED;
}

event_ret_t bluetooth_screen_events(uint16_t event, void *data)
{
	switch (event) {
		case EVENT_SCREEN_VISIBLE:
			bluetooth_screen.pos = 0;
			bluetooth_screen.bt_en = (hal_bluetooth_get_state() > 0);
			draw_bluetooth_screen(&bluetooth_screen);
			hal_enable_halfsecond_timer();
			break;
		case EVENT_SCREEN_DESTROY:
			hal_disable_halfsecond_timer();
			break;
		case EVENT_USER_BUTTONS:
			dbg_out("button event %d\n", *(int *)data);
			return handle_bluetooth_buttons(*(watch_button *)data, &bluetooth_screen);
			break;
		case EVENT_HALF_SEC_TIMER:
			if (bluetooth_screen.set_mode) {
				if (bluetooth_screen.on)
					bluetooth_screen.on = FALSE;
				else
					bluetooth_screen.on = TRUE;
			} else
				bluetooth_screen.on = TRUE;
			draw_bluetooth_screen(&bluetooth_screen);
			break;
		default:
			return EVENT_RET_UNHANDLED;
			break;
	};
	return EVENT_RET_HANDLED;
}


/*
 * Info Screen
 */
void draw_info_screen(accel_data_t *accel_data)
{
	hal_lcd_clear_display();

	oswald_draw_bitmap(36, 0, info_icon_width, info_icon_height, info_icon_bits);

	oswald_write_string(2, 29, FONT_DROID8x12, "Oswald");
	oswald_write_string(35, 29, FONT_DROID8x12, OSWALD_VERSION);
	oswald_write_string(2, 41, FONT_DROID8x12, "HAL");
	oswald_write_string(35, 41, FONT_DROID8x12, (char *)hal_get_version_string());
	oswald_write_string(2, 53, FONT_DROID8x12, "Build");
	oswald_write_string(35, 53, FONT_DROID8x12, (char *)hal_get_buildno_string());
	oswald_write_string(2, 65, FONT_DROID8x12, "Radio");
	oswald_write_string(35, 65, FONT_DROID8x12, (char *)hal_get_radio_version_string());

	hal_lcd_update_display();
}

event_ret_t info_screen_handle_events(uint16_t event, void *data)
{
	switch (event) {
		case EVENT_SCREEN_VISIBLE:
			draw_info_screen(&accel_screen.accdata);
			return EVENT_RET_HANDLED;
			break;
		case EVENT_USER_BUTTONS:
			dbg_out("button event %d\n", *(int *)data);
			break;
		default:
			return EVENT_RET_UNHANDLED;
			break;
	};
	return EVENT_RET_UNHANDLED;
}