#include <stdio.h>
#include <stdint.h>

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

#include "dayslib.h"

#include "oswald_watch_faces.h"

#if defined(__GNUC__) && (__MSP430X__ > 0)
__attribute__((__far__))
#endif
#include "bitmaps/battery0_icon.xbm"
#if defined(__GNUC__) && (__MSP430X__ > 0)
__attribute__((__far__))
#endif
#include "bitmaps/battery25_icon.xbm"
#if defined(__GNUC__) && (__MSP430X__ > 0)
__attribute__((__far__))
#endif
#include "bitmaps/battery50_icon.xbm"
#if defined(__GNUC__) && (__MSP430X__ > 0)
__attribute__((__far__))
#endif
#include "bitmaps/battery75_icon.xbm"
#if defined(__GNUC__) && (__MSP430X__ > 0)
__attribute__((__far__))
#endif
#include "bitmaps/battery100_icon.xbm"
#if defined(__GNUC__) && (__MSP430X__ > 0)
__attribute__((__far__))
#endif
#include "bitmaps/charger_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/tinybluetooth_icon.xbm"
#if defined(__GNUC__) && (__MSP430X__ > 0)
__attribute__((__far__))
#endif
#include "bitmaps/bluetooth_con_icon.xbm"
#if defined(__GNUC__) && (__MSP430X__ > 0)
__attribute__((__far__))
#endif
#include "bitmaps/banner_img.xbm"


/* sine table, per degree, factor 100 */
#if defined(__GNUC__) && (__MSP430X__ > 0)
__attribute__((__far__))
#endif
int16_t sintab[]={
	    0,   2,   3,   5,   7,   9,  10,  12,  14,  16,
	   17,  19,  21,  22,  24,  26,  28,  29,  31,  33,
	   34,  36,  37,  39,  41,  42,  44,  45,  47,  48,
	   50,  52,  53,  54,  56,  57,  59,  60,  62,  63,
	   64,  66,  67,  68,  69,  71,  72,  73,  74,  75,
	   77,  78,  79,  80,  81,  82,  83,  84,  85,  86,
	   87,  87,  88,  89,  90,  91,  91,  92,  93,  93,
	   94,  95,  95,  96,  96,  97,  97,  97,  98,  98,
	   98,  99,  99,  99,  99, 100, 100, 100, 100, 100,
	  100, 100, 100, 100, 100, 100,  99,  99,  99,  99,
	   98,  98,  98,  97,  97,  97,  96,  96,  95,  95,
	   94,  93,  93,  92,  91,  91,  90,  89,  88,  87,
	   87,  86,  85,  84,  83,  82,  81,  80,  79,  78,
	   77,  75,  74,  73,  72,  71,  69,  68,  67,  66,
	   64,  63,  62,  60,  59,  57,  56,  54,  53,  52,
	   50,  48,  47,  45,  44,  42,  41,  39,  37,  36,
	   34,  33,  31,  29,  28,  26,  24,  22,  21,  19,
	   17,  16,  14,  12,  10,   9,   7,   5,   3,   2,
	    0,  -2,  -3,  -5,  -7,  -9, -10, -12, -14, -16,
	  -17, -19, -21, -22, -24, -26, -28, -29, -31, -33,
	  -34, -36, -37, -39, -41, -42, -44, -45, -47, -48,
	  -50, -52, -53, -54, -56, -57, -59, -60, -62, -63,
	  -64, -66, -67, -68, -69, -71, -72, -73, -74, -75,
	  -77, -78, -79, -80, -81, -82, -83, -84, -85, -86,
	  -87, -87, -88, -89, -90, -91, -91, -92, -93, -93,
	  -94, -95, -95, -96, -96, -97, -97, -97, -98, -98,
	  -98, -99, -99, -99, -99,-100,-100,-100,-100,-100,
	 -100,-100,-100,-100,-100,-100, -99, -99, -99, -99,
	  -98, -98, -98, -97, -97, -97, -96, -96, -95, -95,
	  -94, -93, -93, -92, -91, -91, -90, -89, -88, -87,
	  -87, -86, -85, -84, -83, -82, -81, -80, -79, -78,
	  -77, -75, -74, -73, -72, -71, -69, -68, -67, -66,
	  -64, -63, -62, -60, -59, -57, -56, -54, -53, -52,
	  -50, -48, -47, -45, -44, -42, -41, -39, -37, -36,
	  -34, -33, -31, -29, -28, -26, -24, -22, -21, -19,
	  -17, -16, -14, -12, -10,  -9,  -7,  -5,  -3,  -2
};

int16_t f_sin(int16_t v)
{
	v %= 360;
	return sintab[v];
}

int16_t f_cos(int16_t v)
{
	v += 90;
	v %= 360;
	return sintab[v];
}

void draw_status_icons(int x, int y, int fg)
{
	static uint8_t ci = 0;
	if(x==-1)
		x=81;
	if(y==-1)
		y=0;
	
	if (OswaldPowerState.source) {
		oswald_draw_bitmap(x, y, charger_icon_width, charger_icon_height, fg, charger_icon_bits);

		if (OswaldPowerState.charge_state != POWER_CHARGER_DONE) {
			if (ci==0) oswald_draw_bitmap(x, y, battery0_icon_width, battery0_icon_height, fg, battery0_icon_bits);
			else if (ci==1) oswald_draw_bitmap(x, y, battery25_icon_width, battery25_icon_height, fg, battery25_icon_bits);
			else if (ci==2) oswald_draw_bitmap(x, y, battery50_icon_width, battery50_icon_height, fg, battery50_icon_bits);
			else if (ci==3) oswald_draw_bitmap(x, y, battery75_icon_width, battery75_icon_height, fg, battery75_icon_bits);
			else if (ci==4) oswald_draw_bitmap(x, y, battery100_icon_width, battery100_icon_height, fg, battery100_icon_bits);
			ci++;
			ci %= 5;
		} else {
			oswald_draw_bitmap(x, y, battery100_icon_width, battery100_icon_height, fg, battery100_icon_bits);
		}
	} else {
		if (OswaldPowerState.percent > 75)
			oswald_draw_bitmap(x, y, battery100_icon_width, battery100_icon_height, fg, battery100_icon_bits);
		else if (OswaldPowerState.percent > 50)
			oswald_draw_bitmap(x, y, battery75_icon_width, battery75_icon_height, fg, battery75_icon_bits);
		else if (OswaldPowerState.percent > 25)
			oswald_draw_bitmap(x, y, battery50_icon_width, battery50_icon_height, fg, battery50_icon_bits);
		else if (OswaldPowerState.percent > 5)
			oswald_draw_bitmap(x, y, battery25_icon_width, battery25_icon_height, fg, battery25_icon_bits);
		else
			oswald_draw_bitmap(x, y, battery0_icon_width, battery0_icon_height, fg, battery0_icon_bits);
	}

	if (hal_bluetooth_get_state() == BLUETOOTH_ON)
		oswald_draw_bitmap(x, y, tinybluetooth_icon_width, tinybluetooth_icon_height, fg, tinybluetooth_icon_bits);
	else if (hal_bluetooth_get_state() == BLUETOOTH_CONNECTED)
		oswald_draw_bitmap(x, y, bluetooth_con_icon_width, bluetooth_con_icon_height, fg, bluetooth_con_icon_bits);
}

void DrawLcdAnaClock(boolean show_seconds)
{
	int16_t i, x, y, x2, y2;
	int16_t tmp;
	int8_t hour, minute, seconds;
	char tstr[16];

	hour = OswaldClk.hour;
	minute = OswaldClk.minute;
	seconds = OswaldClk.second;

	hour -= 3;
	if (hour < 0)
		hour += 12;
	// mf = (1. / 59.) * (double)minute;
	minute -= 15;
	if (minute < 0)
		minute += 60;
	seconds -= 15;
	if (seconds < 0)
		seconds += 60;

	hal_lcd_clear_display();
	oswald_draw_rect(0,0,95,95,1);

	tstr[num2str(OswaldClk.day,tstr,1,2)]='\0';
	oswald_write_string(70, 44, FONT_5x8, 1, tstr);

	// Marker
	// plot(R*cos(360° * i/N), R*sin(360° * i/N))
	for (i=0; i<12; i++) {
		x = 47 + ((43 * f_cos((360 / 12) * i)) / 100);
		y = 47 + ((43 * f_sin((360 / 12) * i)) / 100);
		x2 = 47 + ((47 * f_cos((360 / 12) * i)) / 100);
		y2 = 47 + ((47 * f_sin((360 / 12) * i)) / 100);
		oswald_draw_line_ww(x, y, x2, y2, 0, 2);
		// g_printerr("br %d,%d %d,%d\n", x,y,x2,y2);
	};

	// Hour
	tmp = 47 + (30 * f_cos(((360 / 12) * hour) + ((OswaldClk.minute * 360) /12 / 60)) / 100);
	x =  tmp;
	tmp = 47 + (30 * f_sin(((360 / 12) * hour) + ((OswaldClk.minute * 360) /12 / 60)) / 100);
	y =  tmp;
	oswald_draw_line_ww(47, 47, x, y, 0, 2);

	// Minute
	tmp = 47 + ((40 * f_cos((360 / 60) * minute)) / 100);
	x =  tmp;
	tmp = 47 + ((40 * f_sin((360 / 60) * minute)) / 100);
	y =  tmp;
	oswald_draw_line_ww(47, 47, x, y, 0, 2);

	if (show_seconds) {
		// Seconds
		tmp = 47 + ((40 * f_cos((360 / 60) * seconds)) / 100);
		x =  tmp;
		tmp = 47 + ((40 * f_sin((360 / 60) * seconds)) / 100);
		y =  tmp;
		oswald_draw_line(47, 47, x, y, 0);
	};

	hal_lcd_update_display();
}

static const char *daynames[7] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };

void DrawLcdDigitalClockGen(boolean show_seconds, int show_wday)
{
	static char *dnames[]={"SUN","MON","TUE","WED","THU","FRI","SAT"};
	int w,x,y,yf;
	unsigned char val;
	const char *t;
	hal_lcd_clear_display();
	oswald_draw_rect(0,0,95,95,1);
	if(show_wday) {
		for(x=24,y=6,t=daynames[OswaldClk.wday];*t!='\0';t++,x+=w+4) 
			oswald_draw_font58_scaled(x,y,*t,&w,0,1,3,2);
	}
	val = OswaldClk.hour;
	if (!OswaldClk.clk24hr)
		val=(val>12)?val-12:val;
	x=6;
	yf=10;
	y=(96/2)-(3*yf)+(show_wday?10:0);
	if(val>=10)
		oswald_draw_font58_scaled(x,y,(val / 10)+'0',&w,0,1,4,yf);
	oswald_draw_font58_scaled((x=x+16+2),y,(val % 10)+'0',&w,0,1,4,yf);
	x+=16+4;
	if(OswaldClk.second % 2)
		oswald_draw_rect(x,y+5*yf,x+4,y+6*yf-1,0);
	x+=8;
	val = OswaldClk.minute;
	oswald_draw_font58_scaled(x,y,(val / 10)+'0',&w,0,1,4,yf);
	oswald_draw_font58_scaled((x=x+16+2),y,(val % 10)+'0',&w,0,1,4,yf);
	// Commit display
	hal_lcd_update_display();
}

void 
DrawLcdDigitalClock(boolean show_seconds) {
	DrawLcdDigitalClockGen(show_seconds,0);
}

void 
DrawLcdDigitalClock2(boolean show_seconds) {
	DrawLcdDigitalClockGen(show_seconds,1);
}

void DrawCalendarClock(boolean show_seconds)
{
	int gRow = 1;
	int gColumn = 1;
	char tstr[16];
	int i,k,n,x,y,c;
	int w;
	unsigned char val;
	int sx,sy;
	int gw,gh;
	int wday,yday,month,year,day,rollup;
	const char *ptr;
	int off;

	hal_lcd_clear_display();
	gRow=4;
	gColumn=34;
	val = OswaldClk.hour;
	if (!OswaldClk.clk24hr)
		val=(val>12)?val-12:val;
	if(val>=10)
		oswald_draw_bigdigit(gRow,gColumn,(val / 10)+'0',&w,1,0);
	else
		w=14;
	gRow+=w+2;
	oswald_draw_bigdigit(gRow,gColumn,(val % 10)+'0',&w,1,0);
	gRow+=w+2;
	w=4;
	if(OswaldClk.second % 2)
		oswald_draw_rect(gRow,gColumn+26-w,gRow+w-1,gColumn+26-1,1);
	gRow+=w+2;
	oswald_draw_bigdigit(gRow,gColumn,(OswaldClk.minute / 10)+'0',&w,1,0);
	gRow+=w+2;
	oswald_draw_bigdigit(gRow,gColumn,(OswaldClk.minute % 10)+'0',&w,1,0);
	gRow+=w+2;

	sx=2,sy=2;
	gRow+=2;
	if (show_seconds) {
		oswald_draw_font58_scaled(gRow,gColumn+26-6*sy, (OswaldClk.second / 10)+'0',&w,1,0,sx,sy);
		oswald_draw_font58_scaled(gRow+w+1,gColumn+26-6*sy, (OswaldClk.second % 10)+'0',&w,1,0,sx,sy);
	}
	if(!OswaldClk.clk24hr)
		oswald_write_string(gRow+3,gColumn+3,FONT_6x9, FALSE,(OswaldClk.hour>12)?"PM":"AM");
	/* The date */
	off=0;
	ptr=daynames[OswaldClk.wday];
	off=mystrlen(ptr);
	mymemcpy(tstr,ptr,off);
	tstr[off++]=' ';
	if (OswaldClk.day_first) {
		off+=num2str(OswaldClk.day,tstr+off,1,sizeof(tstr)-off-3);
		tstr[off++]='.';
		off+=num2str(OswaldClk.month,tstr+off,1,sizeof(tstr)-off-2);
		tstr[off++]='.';
	} else {
		off+=num2str(OswaldClk.month,tstr+off,1,sizeof(tstr)-off-3);
		tstr[off++]='/';
		off+=num2str(OswaldClk.day,tstr+off,1,sizeof(tstr)-off-2);
		tstr[off++]=' ';
	}
	off+=num2str(OswaldClk.year,tstr+off,1,sizeof(tstr)-off-1);
	tstr[off]='\0';
	oswald_draw_rect(2,0,93,7,1);
	oswald_write_string(3, 0, FONT_5x8, 1, tstr);
	/* The minicalendar */
	gw=13;
	gh=11;
	oswald_draw_grid(2,7,1+gw*7+1,29,gw,gh);
	month=OswaldClk.month;
	year=OswaldClk.year;
	mday2yday(OswaldClk.year,OswaldClk.month,OswaldClk.day,&yday);
	yday2wday(OswaldClk.year,yday,&wday);
	yday=yday-((wday+6)%7); /* we begin the week in monday */
	yday2mday(year,yday, &month, &day);
	rollup=GetYearDays(year)[month]-GetYearDays(year)[month-1];
	if(day<=0) { /*Ok, we have gone to the previous year. Then fixup year/month*/
                year--;
                month=12;
                day=GetYearDays(year)[12]+day;
        }
	for(i=0,k=day;i<14;i++) {
		n=((k+i-1)%(rollup))+1;
		x=2+2+(i%7)*gw;
		y=7+2+(i/7)*gh;
      	        if(n==OswaldClk.day) {
			oswald_draw_rect(x-1,y-1,x-1+gw-1,y-1+gh-1,1);
			c=0;
      	        } else
			c=1;
      	        if(n<10) {
      	                 oswald_draw_tinydigit(x,y,n+'0',&w,c,!c);
      	        } else {
      	                 oswald_draw_tinydigit(x,y,n/10+'0',&w,c,!c);
      	                 oswald_draw_tinydigit(x+w,y,n%10+'0',&w,c,!c);
      	        }
	}
	/* The banner */
	oswald_draw_bitmap(0, 95-32, banner_img_width, banner_img_height, 1, banner_img_bits);
	hal_lcd_update_display();
}

void DrawHelpClock(boolean show_seconds)
{
	int w,x,y;
	unsigned char val;
	hal_lcd_clear_display();
	// Time
	val = OswaldClk.hour;
	if (!OswaldClk.clk24hr)
		val=(val>12)?val-12:val;
	x=31;
	y=40;
	oswald_draw_grid(x-2+7,0,x+32-7,95,2,2);
	oswald_draw_rect(x-2+1,y-4+1-6,x+32-1,y+15-1+6,1);
	if(val>=10)
		oswald_draw_font58_scaled(x,y,(val / 10)+'0',&w,0,1,1,2);
	oswald_draw_font58_scaled((x=x+5+2),y,(val % 10)+'0',&w,0,1,1,2);
	x+=5+2;
	if(OswaldClk.second % 2) {
		oswald_draw_rect(x,y+4,x+1,y+5,0);
		oswald_draw_rect(x,y+8,x+1,y+9,0);
	}
	x+=4;
	val = OswaldClk.minute;
	oswald_draw_font58_scaled(x,y,(val / 10)+'0',&w,0,1,1,2);
	oswald_draw_font58_scaled((x=x+5+2),y,(val % 10)+'0',&w,0,1,1,2);
	x=31;
	y=40;
	oswald_draw_grid(x-2,y-4-6,x+32,y+15+6,100,100);
	// Help text: left buttons
	oswald_write_string(0, 0,  FONT_5x8, 0, "[Edit]");
	oswald_write_string(0, 96/2-8,  FONT_5x8, 0, "Esc");
	oswald_write_string(0, 96/2,  FONT_5x8, 0, "[Left]");
	oswald_write_string(0, 96-8-1,  FONT_5x8, 0, "Light");
	// Help text: right buttons
	oswald_write_string(86, 0,  FONT_5x8, 0, "Up");
	oswald_write_string(72, 96/2-8,  FONT_5x8, 0, "Enter");
	oswald_write_string(65, 96/2,  FONT_5x8, 0, "[Right]");
	oswald_write_string(75, 96-8-1,  FONT_5x8, 0, "Down");
	// Status
	oswald_draw_grid(38-2,68-2,38+16+2,68+18+2,100,100);
	oswald_draw_rect(38-2+1,68-2+1,38+16+2-1,68+18+2-1,1);
	draw_status_icons(38,68,0);	

	// Commit display
	hal_lcd_update_display();
	
}