/// \file stdbuttons.c Std touchscreen buttons handler for VSOS
/// \author Panu-Kristian Poiksalo, VLSI Solution Oy 2012

#include <vstypes.h>
#include <touch.h>
#include <lcd.h>
#include <stdbuttons.h>
#include <vo_stdio.h>
#include <string.h>
#include <timers.h>
#include <clockspeed.h>
#include <vo_gpio.h>
#include <vs1005h.h>
#include <volink.h>



StdButton *lastButtonPressed = NULL;
volatile StdButton *currentButton = NULL;

u_int16 virtualWidth = 240;
u_int16 virtualHeight = 320;



u_int16 bevelColor[3];
auto void DrawBevel(u_int16 __a1 x1, u_int16 __a0 y1, u_int16 __b1 x2,u_int16 __b0 y2, u_int16 __c0 flags) {
	
	if (flags & BTN_LOWERED) {
		bevelColor[0] = lcd0.textColor;//bevelColor[0] = lcd0.buttonHighlight;
		bevelColor[1] = lcd0.shadowColor;//bevelColor[1] = lcd0.buttonShadow;
		bevelColor[2] = lcd0.shadowColor;//bevelColor[2] = lcd0.buttonLoweredFace;
	} else {
		bevelColor[1] = lcd0.textColor;//bevelColor[0] = lcd0.buttonHighlight;
		bevelColor[0] = lcd0.shadowColor;//bevelColor[1] = lcd0.buttonShadow;
		bevelColor[2] = lcd0.buttonFaceColor;//bevelColor[2] = lcd0.buttonLoweredFace;
		if (flags & BTN_HIGHLIGHTED) {
			bevelColor[2] = lcd0.highlightColor;//bevelColor[2] = lcd0.buttonHighlightFace;
		}
	}

	if (flags & BTN_TEXT) {
		bevelColor[2] = lcd0.backgroundColor;
	}
	if (!(flags & BTN_NO_FACE)) {
		LcdFilledRectangle(x1,y1,x2,y2,0,bevelColor[2]);
	}
	if (!(flags & BTN_NO_BEVEL)) {
		LcdFilledRectangle(x1,y1,x2,y1,0,bevelColor[1]);
		LcdFilledRectangle(x1,y1,x1,y2,0,bevelColor[1]);
		LcdFilledRectangle(x1,y2,x2,y2,0,bevelColor[0]);
		LcdFilledRectangle(x2,y1,x2,y2,0,bevelColor[0]);
	}
}

void ButtonWrite(const char *s) {
	char ch;
	while (ch = *s++) {
		if (ch == '\r') {
			lcd0.x = lcd0.clipx1;
		}
		if (ch == '\n') {
			lcd0.x = lcd0.clipx2;
		}
		if (lcd0.x+7 > (lcd0.clipx2)) {
			lcd0.y += 8;
			if (lcd0.y + 9 >= lcd0.clipy2) {
				//lcd0.y = lcd0.clipy1; /* Wrap */
				return; /* Don't wrap */
			}
			lcd0.x = lcd0.clipx1;
			LcdFilledRectangle(lcd0.x, lcd0.y, lcd0.clipx2, lcd0.y+10, 0, lcd0.backgroundColor);
		}
		if (ch != '\n') {
			char text[2];
			text[0]  = ch;
			text[1] = 0;
			LcdTextOutXY(lcd0.x+1, lcd0.y, text);
			lcd0.x += 7;
		}
	}
}

void StdButtonDefaultRender(register const StdButton *button, register u_int16 op, register u_int16 x, register u_int16 y) {
	u_int16 originalFlags = button->flags;
	if (op == BTN_OP_UNSPECIFIED) {
	

		if (button == currentButton) {
			button->flags |= BTN_HIGHLIGHTED;
		}

		//currentColoring = &colorScheme[(button->flags >> 11) & 3];
		DrawBevel(button->x1,button->y1,button->x2,button->y2,button->flags);
		if (!(button->flags & BTN_TEXT)){
			lcd0.textColor = lcd0.buttonTextColor;
			lcd0.backgroundColor = bevelColor[2];
		}
		//lcd0.x = lcd0.clipx1 = 0;
		//lcd0.y = lcd0.clipy1 = 0;
		//printf("%04x",currentButton);
		lcd0.x = lcd0.clipx1 = button->x1+2;
		lcd0.y = lcd0.clipy1 = button->y1+1;
		lcd0.clipx2 = button->x2-1; 					// tarviiko -7
		lcd0.clipy2 = button->y2-1;
		if (button->flags & BTN_LOWERED) {
			lcd0.x++; lcd0.y++;
		}
		if (!(button->flags & BTN_NO_CAPTION)) {
			if (button->flags & BTN_CHECKABLE) {
				#if 0
				printf("%c",button->flags & BTN_CHECKED ? 0x95 : 0xb7);
				#else
				char s[2];
				s[0] = button->flags & BTN_CHECKED ? 0x95 : 0xb7;
				s[1] = '\0';
				ButtonWrite(s);
				#endif
			}
			ButtonWrite(button->caption);
		}	
	}
	button->flags = originalFlags;
}  

auto void MyRenderStdButton(register const StdButton *button) {
	__y lcdInfo lcdSave;
	memcpyXY(&lcdSave, &lcd0, sizeof(lcd0));
	//printf("REND(%s):%p ",button->caption,button->render);
	//printf("I6=%d ",GetI6());
	
	//if (button->render) {
		button->render(button,0,0,0);
	//} else {
	//	StdButtonDefaultRender(button);
	//}
	//printf("I6=%d ",GetI6());
	
	memcpyYX(&lcd0, &lcdSave, sizeof(lcd0));
} 



auto u_int16 physX(register u_int16 logX) {
	return ((logX*(lcd0.clipx2-lcd0.clipx1+1))/virtualWidth) + lcd0.clipx1;
}

auto u_int16 physY(register u_int16 logY) {
	return ((logY*(lcd0.clipy2-lcd0.clipy1+1))/virtualHeight) + lcd0.clipy1;
}


auto void MyCreateStdButton(register StdButton *button, register u_int16 result, register u_int16 flags, register s_int16 x, 
	register s_int16 y, register u_int16 w, register u_int16 h, register const char *caption){
	button->flags = flags;
	button->result = result;
	button->caption = caption;
	button->render = StdButtonDefaultRender;
	if (x==-1) {
		x = y % virtualWidth;
		y = y / virtualWidth;		
	}
	button->x1 = physX(x)+1;
	button->y1 = physY(y)+1;
	button->x2 = physX(x+w)-2;
	button->y2 = physY(y+h)-2;
}

auto void MySetVirtualResolution(register u_int16 screenWidth, register u_int16 screenHeight){
	//printf("SetVirtualResolution ");
	virtualWidth = screenWidth;
	virtualHeight = screenHeight; 
}

 
#if 1
auto s_int16 MyGetStdButtonPress(register StdButton *buttons) {
	s_int16 t;
	s_int16 x,y;	
	static u_int16 timeoutCounter=0;
	static s_int16 lastx, lasty = 0;

	Delay(1);

	pTouchInfo->calibrationMode = 0;
	t = GetTouchLocation(&x, &y);

	if (!t) { //Known no-press
		if (lastButtonPressed && (lastButtonPressed->flags & BTN_LOWERED)) {		
			lastButtonPressed->flags &= ~BTN_LOWERED;
			RenderStdButton(lastButtonPressed);
			{ 
				s_int16 result = lastButtonPressed->result;					
				lastButtonPressed = 0;
				return result;
			}
		}
		return 0;
	}
	if (t<0) { //Press in non-known location
		return 0;
	}
	if (lastButtonPressed) {
		
		if (
			((x != lastx) || (y != lasty))
		&& (x<=lastButtonPressed->x2) 
		&& (x>=lastButtonPressed->x1) 
		&& (y<=lastButtonPressed->y2) 
		&& (y>=lastButtonPressed->y1)
		) {
			lastButtonPressed->render(lastButtonPressed, 1, x, y);
			goto finally;
		} else	if (
		   (x<lastButtonPressed->x2+5) 
		&& (x>lastButtonPressed->x1-5) 
		&& (y<lastButtonPressed->y2+5) 
		&& (y>lastButtonPressed->y1-5)
		) {
			goto finally;
		} else {
			lastButtonPressed->flags &= ~BTN_LOWERED;
			RenderStdButton(lastButtonPressed);
			lastButtonPressed = 0;			
		}
	}
	while (buttons->result) {
		while(buttons->flags & BTN_DISABLED) {
			buttons++;
		}
		if ((x>=buttons->x1) && (x<=buttons->x2) && (y>=buttons->y1) && (y<=buttons->y2)) {
			lastButtonPressed = buttons;
			lastButtonPressed->flags |= BTN_LOWERED;
			RenderStdButton(lastButtonPressed);
			goto finally;
		}
		buttons++;
	}
	finally:	
	lastx = x;
	lasty = y;			
	return 0;	
}
#else
auto s_int16 MyGetStdButtonPress(register StdButton *buttons) {
	s_int16 t;
	s_int16 x,y;	
	static u_int16 timeoutCounter=0;
	static s_int16 lastx, lasty = 0;
	StdButton *firstButton = buttons;
	StdButton *previousButton = buttons;

	Delay(1);

	/*
	x = lcd0.textColor; y = lcd0.backgroundColor;
	lcd0.textColor = lcd0.defaultTextColor;
	lcd0.backgroundColor = 0;
	sprintf(s,"%04x%04x %04x%04x ",PERIP(INT_ENABLE1_HP),PERIP(INT_ENABLE0_HP),PERIP(INT_ENABLE1_LP),PERIP(INT_ENABLE0_LP));
	LcdTextOutXY(0,0,s);
	lcd0.textColor = x; lcd0.backgroundColor = y;
	*/

	if (currentButton == NULL) {
		currentButton = buttons;
		RenderStdButton(currentButton);
	}


	//touchCalibrationMode = 0;	
	//t = GetTouchLocation(&x, &y);
	previousButton = currentButton;
	if (GpioReadPin(0x00)) {
		while (GpioReadPin(0x00)) {
			Delay(1);
		};
		if (currentButton > firstButton) {
			currentButton--;
		}
		RenderStdButton(previousButton);
		RenderStdButton(currentButton);
	}
	if (GpioReadPin(0x01)) {
		while (GpioReadPin(0x01)){
			Delay(1);
		}
		currentButton++;
		if (currentButton->result == 0) {
			currentButton--;
		}
		RenderStdButton(previousButton);
		RenderStdButton(currentButton);
	}
	
	if (GpioReadPin(0x02)) {
		while (GpioReadPin(0x02)){
			Delay(1);
		}
		if (currentButton) return currentButton->result;
	}

	//if (GpioReadPin(0x03)) PERIP(INT_ENABLE0_HP) = 0;


	return 0;	
}
#endif



auto void MySetClippingRectangleToButton(register StdButton *button){
	u_int16 x1 = button->x1;
	u_int16 x2 = button->x2;
	u_int16 y1 = button->y1;
	u_int16 y2 = button->y2;
	//Coloring *btnColoring = &colorScheme[(button->flags >> 11) & 3];
	if (!(button->flags & BTN_NO_BEVEL)) {
		// If button has bevel, reduce the clipping rectangle
		x1+=2;
		x2-=2;
		y1+=2;
		y2-=2;
	}
	if (button->flags & BTN_NO_BACKGROUND) {
		// If button has no background, increase the clipping rectangle
		x1-=1;
		x2+=1;
		y1-=1;
		y2+=1;
	}
	lcd0.x = lcd0.clipx1 = x1;
	lcd0.y = lcd0.clipy1 = y1;
	lcd0.clipx2 = x2;
	lcd0.clipy2 = y2;
	/*
	lcd0.textColor = btnColoring->buttonText;
	lcd0.backgroundColor = btnColoring->buttonFace;
	if (button->flags & BTN_TEXT) {
		lcd0.textColor = btnColoring->textColor;
		lcd0.backgroundColor = btnColoring->textBackground;
	}
	*/
}


//_RenderStdButton=32728:FCN/VOID
//_CreateStdButton=32729:FCN/VOID
//_SetVirtualResolution=32730:FCN/VOID
//_GetStdButtonPress=32731:FCN/VOID
//_SetClippingRectangleToButton=32732:FCN/VOID

void SetHandlers() {
	SetHandler(CreateStdButton, MyCreateStdButton);
	SetHandler(RenderStdButton, MyRenderStdButton);
	SetHandler(SetVirtualResolution, MySetVirtualResolution);
	SetHandler(GetStdButtonPress, MyGetStdButtonPress);
	SetHandler(SetClippingRectangleToButton, MySetClippingRectangleToButton);	
}
