// HTTP POST demo.
// transmits the scanned data to a webserver
// for the Opticon OPH-5000i
// By Oscar Jacobse
// M3985

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "lib.h"
#include "AdvancedMenu.h"
#include "http_request.h"
#include "logo.h"

#define VERSION						"3985.0"
#define DATA_FILE					"data.txt"
#define PORT						8080					// webserver port
#define MAX_BARCODE					32
#define MAX_INPUT					16
#define RGB(r,g,b)					((long)(((unsigned char)(b)|((long)((unsigned char)(g))<<8))|(((long)(unsigned char)(r))<<16)))
#define NO_ID						(-1)
#define KEYBOARD_INPUT				(-2)
#define MAX_IP_ADDRESS				(3+1+3+1+3+1+3)			// xxx.xxx.xxx.xxx
#define WLAN_CONNECTION_TIMEOUT		(30000/20)

#define MENU_ID_SCAN	1
#define MENU_ID_POST	2
#define MENU_ID_CONFIG	3

#define MENU_FORE_COLOR     RGB_WHITE
#define MENU_BACK_COLOR     0x427cbe    
#define MENU_BUTTON_COLOR   RGB_YELLOW
#define MENU_APPLY_COLOR    0xfcd9ff    
#define MENU_SELECT_COLOR   0x284a70    

#define FORE_COLOR          RGB_WHITTE
#define BACK_COLOR          0xf7f7f7    
#define SELECT_COLOR        RGB_BLUE
#define DISABLE_COLOR       0xb0b0b0    
#define GIUDE_BUTTON        RGB_BLUE
#define APPLY_COLOR         RGB_MAGENTA
#define TITLE_SET_COLOR     RGB_BLUE
#define TITLE_TASK_COLOR    0x008000    

const struct {
	const int id;
	const char *symb_text;
}	symb_tab[] = {
		{ID_EAN_13,"EAN-13"},
		{ID_UPC_A,"UPC-A"},
		{ID_EAN_8,"EAN-8"},
		{ID_UPC_E,"UPC-E"},
		{ID_ISBN,"ISBN"},
		{ID_ISSN,"ISSN"},
		{ID_ISMN,"ISMN"}, 
		{ID_CODE39,"CODE-39"},
		{ID_CODABAR,"CODABAR"},
		{ID_D_2OF5,"INDUSTRIAL 2OF5"},
		{ID_I_2OF5,"INTERLEAVED 2OF5"},
		{ID_CODE93,"CODE-93"},
		{ID_CODE128,"CODE-128"},
		{ID_MSI_PLESSEY,"MSI/PLESSEY"},
		{ID_IATA,"IATA"},
		{ID_UK_PLESSEY,"UK/PLESSEY"},
		{ID_TELEPEN,"TELEPEN"},
		{ID_MATRIX,"MATRIX 2OF5"},
		{ID_MATRIX_CP,"CHINESE POST MATRIX 2OF5"},
		{ID_NW7_ABC,"CODABAR ABC"},
		{ID_NW7_CX,"CODABAR CX"},
		{ID_SCODE,"SCODE"},
		{ID_LAETUS,"CODE39 TRIOPTIC"},
		{ID_C39_FUL,"CODE39 FULL ASCII"},
		{ID_C39_ITP,"CODE39 ITALIAN PHARMACEUTICAL"},
		{ID_EAN128,"EAN-128"},
		{ID_GS1_DATABAR,"GS1 DATABAR"},
		{ID_RSS_LIMITED,"GS1 LIMITED"},
		{ID_RSS_EXPANDED,"GS1 EXPANDED"},
		{ID_PDF417,"PDF417"},
		{ID_CCC_COMPOSITE,"COMMPOSITE C"},
		{ID_MICRO_PDF417,"MICROPDF417"},
		{ID_CCA_COMPOSITE,"COMMPOSITE A"},
		{ID_CCB_COMPOSITE,"COMMPOSITE B"},
		{ID_CODE11,"CODE-11"},
		{ID_EAN128_CCC,"EAN-128 WITH CC-C COMPOSITE"},
		{ID_C_3OF5,"CODE 3OF5"},
		{ID_JAN_13,"JAN-13"},
		{ID_INST_13,"INSTORE-13"},
		{ID_JAN_8,"JAN-8"},
		{ID_INST_8,"INSTORE-8"},
		{ID_INTELLIGENT_MAIL,"INTELLIGENT_MAIL"},
		{ID_POSTNET,"POSTNET"},
		{ID_JAPANESE_POSTAL,"JAPANESE_POSTAL"},
		{ID_CODABLOCK_F,"CODABLOCK_F"},
		{ID_DATA_MATRIX_ECC200,"DATA_MATRIX ECC200"},
		{ID_DATA_MATRIX_ECC140,"DATA_MATRIX_ECC140"},
		{ID_AZTEC_CODE,"AZTEC_CODE"},
		{ID_AZTEC_RUNES,"AZTEC_RUNES"},
		{ID_CHINESE_SENSIBLE_CODE,"CHINESE_SENSIBLE_CODE"},
		{ID_QR_CODE,"QR_CODE"},
		{ID_MICRO_QR_CODE,"MICRO_QR_CODE"},
		{ID_MAXI_CODE,"MAXI_CODE"},
		{ID_COMPOSITE_GS1DATABAR,"COMPOSITE_GS1DATABAR"},
		{ID_COMPOSITE_UPCEAN,"COMPOSITE_UPCEAN"},
		{ID_PLANET,"PLANET"},
		{ID_NETHERLANDS_KIX,"NETHERLANDS_KIX"},
		{ID_UK_POSTAL,"UK_POSTAL"},
		{ID_AUSTRALIAN_POSTAL,"AUSTRALIAN_POSTAL"},
		{ID_MAILMARK_4_STATE_POSTAL,"MAILMARK_4_STATE_POSTAL"},
		{NO_ID," "},
		{KEYBOARD_INPUT,"KEYBOARD"},
	};



static const AM_ColorPalette CustomColor[] = {
    //ForeColor,        BackColor,        Select_ForeColor, Select_BackColor,  Control_ForeColor
    { MENU_FORE_COLOR,  MENU_BACK_COLOR,  RGB_WHITE,        MENU_SELECT_COLOR, MENU_BUTTON_COLOR }, //#0: Task menu base color
    { MENU_FORE_COLOR,  MENU_BACK_COLOR,  0,                0,                 MENU_APPLY_COLOR  }, //#1: Task menu apply color
    { RGB_BLACK,        BACK_COLOR,       RGB_WHITE,        SELECT_COLOR,      GIUDE_BUTTON      }, //#2: Base color
    { RGB_WHITE,        RGB_BLUE,         0,                0,                 0                 }, //#3: Title of Setting
    { GIUDE_BUTTON,     BACK_COLOR,       0,                0,                 GIUDE_BUTTON      }, //#4: Guide color
    { RGB_WHITE,        TITLE_TASK_COLOR, 0,                0,                 0                 }, //#5: Title 0f tasks
    { RGB_BLACK,        RGB_WHITE,        RGB_BLACK,        RGB_YELLOW,        RGB_BLUE          }, //#6: Input field color
    { APPLY_COLOR,      BACK_COLOR,       0,                0,                 APPLY_COLOR       }, //#7: Apply color
};


#define PX_MENU           0  // Task menu base color
#define PX_MENU_APPLY     1  // Task menu apply color
#define PX_BASE           2  // Base color
#define PX_TITLE_SETTING  3  // Title of Setting
#define PX_GUIDE          4  // Guide color
#define PX_TITLE_TASK     5  // Title 0f tasks
#define PX_EDIT           6  // Input field color
#define PX_APPLY          7  // Apply color



// Options for the task menu screen
static const AM_Option MenuOption = {
    MENU_FORE_COLOR,                                // MenuForeColor
    DISABLE_COLOR,                                  // MenuDisabledForeColor
    MENU_BACK_COLOR,                                // MenuBackColor
    sizeof(CustomColor)/sizeof(AM_ColorPalette),      // NumberOfColorPalette
    (pAM_ColorPalette)CustomColor,                  // ColorPalettes
    0,                                              // OptionFlag
    HUGE_FONT,                                      // DefaultFont
    1                                               // DefaultLineSpacing
};



static const AM_MenuItem MainMenuTable[] = {
//   itemID,        y,           x, menuText,     Palette,       visible, enabled, selectable, showControl,   checked, font
	{0,					0,	1, "HTTP POST DEMO",	PX_TITLE_SETTING,	true,    true,    false,      AM_NO_CONTROL, false,   LARGE_FONT},
    {MENU_ID_SCAN,		1,	1, "  Scan   ", PX_MENU,			true,    true,    true,       AM_NO_CONTROL},
    {MENU_ID_POST,		2,	1, "POST Data", PX_MENU,			true,    true,    true,       AM_NO_CONTROL},
    {MENU_ID_CONFIG,	3,	1, " Config  ",	PX_MENU,			true,    true,    true,       AM_NO_CONTROL},
    {-1}
};

static char ip_address[MAX_IP_ADDRESS+1];
static char url[200];

int wait_key(void);
int scan_barcode(char *barcode,int max);
void show_opticon_logo(void);
void append_file(char *barcode);
void scanning(void);
void set_ip_address(void);
bool IsWLANConnected(void);
void http_post_file(void);



int wait_key(void)
{
	int key;

	while((key=getchar()) == -1)
			Idle();
	return(key);
}

int scan_barcode(char *barcode,int max)
{
	struct barcode bcode;

	bcode.text = barcode;
	bcode.min = 5;
	bcode.max = max;
	ScannerPower(ON, 300);
	while(ReadBarcode(&bcode) != OK)
	{		
		if(IsScannerOff())
		{
			ScannerPower(OFF, 0);
			return (NO_ID);
		}
		Idle();
	}
	ScannerPower(OFF, 0);
	return (bcode.id);
}


void show_opticon_logo(void)
{
	int x,y,x1,y1;
	int count;
	
	x=0;
	y=0;
	x1=0;
	y1=0;
	for(count=0; count < (sizeof(_logo_pix) / sizeof(_logo_pix[0]));count++)
	{
		x=(_logo_pix[count] >> 8);
		y=(_logo_pix[count] & 0x7F);

		if (_logo_pix[count] & 0x0080)
		{
			DrawLine(7+x1/2,120+y1/2,7+x/2, 120+y/2, RGB(0,110,182) );
		}
		x1=x;
		y1=y;
	}	
}

void append_file(char *barcode)
{
	FILE *fp;
	if ((fp=fopen(DATA_FILE,"r+b")) == NULL)
		fp=fopen(DATA_FILE,"wb");
	if (fp != NULL)
	{
		fseek(fp,0L,SEEK_END);
		fprintf(fp,"%s\r\n",barcode);
		fclose(fp);
	}
}



void scanning(void)
{
	char barcode[MAX_BARCODE+1];
	char input[MAX_INPUT+1];
	int id;
	int n;
	int key;
	int count;
	long prev_color;
	
	SetTextColor(RGB_BLACK);
	SetBackColor(RGB_WHITE);
	SetFont(LARGE_FONT, NULL);
	putchar('\f');
	show_opticon_logo();
	memset(barcode,'\0',sizeof(barcode));
	memset(input,'\0',sizeof(input));
	Cursor(BLINKING);
	id = NO_ID;
	count=0;
	
	for(;;)
	{
		ResetKey();
		GotoXY(0,0);
		printf("Scan barcode\n%-16.16s\n%-16.16s\n%-16.16s\n",input,barcode,(strlen(barcode) <= 16) ? " " : barcode+16);
		prev_color=SetTextColor(RGB(0,110,182));
		for(n=0;n < (sizeof(symb_tab)/sizeof(symb_tab[0]));n++)
		{
			if (id == symb_tab[n].id)
			{
				printf("%-16.16s",symb_tab[n].symb_text);
				break;
			}
		}
		SetTextColor(prev_color);
		GotoXY(count,1);
		key=wait_key();
		switch(key)
		{
			case BS_KEY:
				if (count > 0)
				{
					count--;
					input[count] = '\0';
					break;
				}
				Sound(TLONG, VHIGH, SERROR,0);
			break;
			
			case CLEAR_KEY:
			Cursor(OFF);
			return;
			
			case ENT_KEY:
				if (count)
				{
					strcpy(barcode,input);
					count=0;
					id = KEYBOARD_INPUT;
					memset(input,'\0',sizeof(input));
					append_file(barcode);
				}
			break;
			
			case TRIGGER_KEY:
				memset(input,'\0',sizeof(input));
				count=0;
				id=scan_barcode(barcode,MAX_BARCODE);
				if (id == NO_ID)
				{
					GoodReadLed(RED, 10);
					Sound(TLONG, VHIGH, SERROR,0);
					break;
				}
				append_file(barcode);
				GoodReadLed(GREEN, 10);
				Sound(TSTANDARD, VHIGH, SMEDIUM, SHIGH, 0);
			break;
			
			default:
				if ((key >= '0') && (key <= '9') && (count < MAX_INPUT))
				{
					input[count++] = key;
					break;
				}
				Sound(TLONG, VHIGH, SERROR,0);
			break;
		}
	}
}

void set_ip_address(void)
{
	char string[MAX_IP_ADDRESS+1];
	int count,key,len,n;
	int x,y;
	long prev_color;
	
	SetFont(LARGE_FONT, NULL);
	printf("\fIP Address\n%s\nENT=change\nClear=OK\n",(ip_address[0] == '\0') ? "<empty>" : ip_address);
	GotoXY(0,5);
	prev_color=SetTextColor(RGB_YELLOW);
	printf("This is the IP \naddress of your\ncomputer");
	SetTextColor(prev_color);
	ResetKey();
	if (wait_key() != ENT_KEY)
		return;
	Cursor(BLINKING);
	strcpy(string,"___.___.___.___");
	len=MAX_IP_ADDRESS;
	count=0;
	x=0;y=1;
	for(;;)
	{
		GotoXY(x, y);
		printf("%s",string);
		GotoXY(x+count,y);
		key = wait_key();
		switch (key)
		{
			case TRIGGER_KEY:
			case ENT_KEY:
				for(n=0;n < MAX_IP_ADDRESS;n++)
				{
					if (string[n] == '_')
					{
						Sound(TLONG, VMEDIUM, SERROR, NULL);
						break;
					}
				}
				if ((atoi(string) > 255) ||
					(atoi(string+4) > 255) ||
					(atoi(string+8) > 255) ||
					(atoi(string+12) > 255))
				{
					Sound(TLONG, VMEDIUM, SERROR, NULL);
					break;
				}
				Sound(TSHORT, VMEDIUM, SMEDIUM, NULL);
				Cursor(OFF);
				strcpy(ip_address,string);
				return;

			case BS_KEY:
				if(count > 0)
				{
					count--;
					if (string[count] == '.')
						count--;
					string[count] = '_';
					Sound(TSHORT, VMEDIUM, SMEDIUM, NULL);
				}
				else
					Sound(TLONG, VMEDIUM, SERROR, NULL);
				break;

			case CLR_KEY:
				Sound(TSHORT, VMEDIUM, SMEDIUM, NULL);
				for(count=0;count < len;count++)
					if (string[count] != '.')
						string[count] = '_';
				count=0;
				break;

			case Q1_KEY:
				count--;
				if (string[count] == '.')
					count--;
				if (count < 0)
				{
					count=0;
					Sound(TLONG, VMEDIUM, SERROR, NULL);
				}
			break;
			
			case Q2_KEY:
				count++;
				if (string[count] == '.')
					count++;
				if (count >= len)
				{
					count=len-1;
					Sound(TLONG, VMEDIUM, SERROR, NULL);
				}
			break;

			
			default:
				if(count < len)
				{
					string[count++] = key;
					if (string[count] == '.')
						count++;
					Sound(TSHORT, VMEDIUM, SMEDIUM, NULL);
				}
				else
					Sound(TLONG, VMEDIUM, SERROR, NULL);
		}
	}
}

bool IsWLANConnected(void)
{
	int status;
	bool isConnected = false;

	if (SysGetWLANConnectStatus(&status)){
		isConnected = (status == SYS_WLAN_STATUS_CONNECTED)? true :false;
	}
	return isConnected;
}


void http_post_file(void)
{
	FILE *fp;
	HTTP_REQUEST_HANDLE http;
	struct ffblk ffblkSt;
	unsigned int waitStartTick;
	long prev_color;
	char *mem;
	char *ptr;
	char filename[40+1];
	struct date_struct d;
	struct time_struct t;
	char responsePhase;
	unsigned int responseStatus;
	char *content;
	unsigned int content_length;
	char *header;
	unsigned int headerLength;
	
	SetFont(LARGE_FONT, NULL);
	prev_color=SetTextColor(RGB_YELLOW);
	GetDate(&d);
	GetTime(&t);
	sprintf(filename,"scan_%02d%02d%02d%02d%02d%d.txt",d.da_day,d.da_mon,d.da_year % 100,t.ti_hour,t.ti_min,t.ti_sec);
	sprintf(url,"http://%d.%d.%d.%d:%d/",atoi(ip_address),atoi(ip_address+4),atoi(ip_address+8),atoi(ip_address+12),PORT);
	if (findfirst(DATA_FILE, &ffblkSt) != OK)
	{
		printf("\fNo data\nto transmit!\npress CLEAR");
		ResetKey();
		wait_key();
		return;
	}
	if ((mem = malloc(ffblkSt.filesize)) == NULL)
	{
		SetTextColor(RGB_RED);
		printf("\fMem error\n%d\nbytes",ffblkSt.filesize);
		SetTextColor(prev_color);
		ResetKey();
		wait_key();
		return;
	}
	if ((fp=fopen(DATA_FILE,"rb")) != NULL)
	{
		fread(mem,ffblkSt.filesize,1,fp);
		fclose(fp);
	}
	strcat(url,filename);
	if ((ptr=strchr(url+8,':')) != NULL)
		*ptr='\0';
	printf("\fPost data to:\n%s\n",url+7);
	if (ptr != NULL)
		*ptr = ':';
	SysSetWLANPower(SYS_WLAN_POWER_AUTO);
	SysWLANInit(NULL);
	HTTP_InitHttpRequest();
	waitStartTick = GetTickCount();
	printf("Connecting..\n");
	while(!IsWLANConnected())
	{
		if (GetTickCount() - waitStartTick > WLAN_CONNECTION_TIMEOUT)
		{
			SetTextColor(RGB_RED);
			printf("WLAN timeout!\n");
			SetTextColor(prev_color);
			ResetKey();
			wait_key();
			return;
		}
		Idle();
	}
	printf("Connected Wlan\n");
	http = HTTP_CreateRequest(url,HTTP_REQ_POST,mem,ffblkSt.filesize,"Connection: close\r\n",3000,0);
	if (!http)
	{
		SetTextColor(RGB_RED);
		printf("POST failed\n");
		SetTextColor(prev_color);
		free(mem);
		ResetKey();
		wait_key();
		return;
	}
	for(;;)
	{
		//Wait for HTTP response
		if (!HTTP_GetResponse(http,
			&responsePhase, 
			&responseStatus, 
			&content, 
			&content_length, 
			&header, &headerLength))
		{
			SetTextColor(RGB_RED);
			printf(">System error!\n");
			SetTextColor(RGB_YELLOW);
			break;
		}
		else
		{
			switch(responsePhase)
			{
				case HTTP_REQUEST_CONNECTION_ERROR:
					SetTextColor(RGB_RED);
					printf(">CONNECTION_ERROR!\n");
					SetTextColor(RGB_YELLOW);
				break;

				case HTTP_REQUEST_SYSTEM_ERROR:
					SetTextColor(RGB_RED);
					printf(">SYSTEM_ERROR!\n");
					SetTextColor(RGB_YELLOW);
                break;
				
				case HTTP_REQUEST_TIMEOUT:
					SetTextColor(RGB_RED);
					printf(">TIMEOUT!\n");
					SetTextColor(RGB_YELLOW);
                break;

				case HTTP_REQUEST_FINISHED:
					printf(">FINISHED\n status=%d\n", responseStatus);
					if ((responseStatus == 201) || (responseStatus == 200))
					{
						//printf(" %d bytes received\n", content_length);
                       //printf("%s\n", content);
					   remove(DATA_FILE);
					}
                    break;

				default:
					Idle();
                continue; 
			}
			break;
		}
	}
	HTTP_CloseRequest(http);
	free(mem);
	ResetKey();
	wait_key();
}


void main(void)
{
    MENU_HANDLE hMenu;
    int event;
    int task;


	memset(ip_address,'\0',sizeof(ip_address));
    hMenu = AM_CreateMenu(MainMenuTable, (const pAM_Option)&MenuOption);
    for(;;)
	{
        AM_ShowMenu(hMenu, AM_SELECT_ANY_ID);
		for(;;)
		{
           event = AM_ExecMenu(hMenu);
		   if (event == F1_KEY)
		   {
			   SetFont(LARGE_FONT, NULL);
			   printf("\fHttp POST demo\nVersion: %s",VERSION);
			   ResetKey();
			   wait_key();
			   break;
		   }
		   if (event == SCAN_KEY)
		   {
				task = AM_GetSelectedLine(hMenu);
				switch(task)
				{
					case MENU_ID_SCAN:
					scanning();
					break;
					
					case MENU_ID_POST:
					http_post_file();
					break;
					
					case MENU_ID_CONFIG:
					set_ip_address();
					break;
				}
				break;
		   }
		}
    }
}
