//-------------------------------------------------------------------------
//
// The MIT License (MIT)
//
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
//-------------------------------------------------------------------------

#define _GNU_SOURCE

#include <assert.h>
#include <ctype.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <math.h>
#include <netinet/in.h>
#include <pthread.h>
#include <time.h>
#include <unistd.h>

#include "backgroundLayer.h"
#include "image.h"
#include "imageLayer.h"
#include "imageGraphics.h"
#include "loadpng.h"
//#include "scrollingLayer.h"
#include "jsmn.h"
#include "key.h"

#include "bcm_host.h"

#define PORT 6867

//-------------------------------------------------------------------------

#define NDEBUG

//-------------------------------------------------------------------------

int	s_width;
int	s_height;
int	margin = 15;
int	i = 0;

int	j = 0;
int	k = 0;
int	l = 0;

int	horizalign = 71;
int	valign = 1;

char line[512] = "";
char ldl[12][64];

char pagestore[4096][64];
// pagestore, pages start each 16 rows (page 1 @ 16, page 2 = 32, ...)
//
// header properties located at first row
// byte 0: page number
// byte 1: line count
// byte 2: spare, freeze, advise, warn
// byte 3: spare, flip, roll, chain
//
// byte 4: line 1 - separator, flash, reverse, border
// byte 5: line 1 - color
// repeat for each line
//
// line properties
// byte 34: row number
// byte 35: height/width
// repeat for each line
//

char omcw[8]; 
// omcw
// byte 1: spare, regSep, botSolid, topSolid (bitwise)
// byte 2: top Page
// byte 3: bottom Page
//

volatile bool run = true;

IMAGE_LAYER_T		solid;
IMAGE_LAYER_T		over;
//SCROLLING_LAYER_T	horz_scroll;
//SCROLLING_LAYER_T	vert_scroll;
IMAGE_T			horz_image;
IMAGE_T			vert_image;

IMAGE_T smallcharmap;
IMAGE_T charmap;

IMAGE_T charset1;
IMAGE_T charset2;
IMAGE_T charset3;
IMAGE_T charset4;
IMAGE_T charset5;
IMAGE_T charset6;
IMAGE_T charset7;

RGBA8_T black_color  = {  0,   0,   0, 255};
RGBA8_T white_color  = {255, 255, 255, 255};
RGBA8_T red_color    = {255,   0,   0, 255};
RGBA8_T green_color  = {  0, 255,   0, 255};
RGBA8_T blue_color   = {  0,   0, 255, 255};
RGBA8_T yellow_color = {255, 255,   0, 255};
RGBA8_T purple_color = {128,   0, 128, 255};
RGBA8_T clear_color  = {  0,   0,   0,   0};

RGBA8_T star_white   = {215, 215, 215, 255};
RGBA8_T star_black   = {  0,   0,   0, 255};
RGBA8_T star_gray    = { 98,  98,  98, 255};
RGBA8_T star_red     = { 96,   0,   0, 255};
RGBA8_T star_green   = {  0, 129,   0, 255};
RGBA8_T star_blue    = {  0,   0,  96, 255};
RGBA8_T star_purple  = { 66,  11, 149, 255};

static int jsoneq(const char *json, jsmntok_t *tok, const char *s) {
    if (tok->type == JSMN_STRING && (int)strlen(s) == tok->end - tok->start && strncmp(json + tok->start, s, tok->end - tok->start) == 0) {
        return 0;
    }
    return -1;
}

void createSock() {
	
	int server_fd, new_socket, valread;
	struct sockaddr_in address;
	int opt = 1;
	int addrlen = sizeof(address);
	char buffer[4096] = {0};
	char *hello = "Hello from server";

	// Create socket file descriptor
	if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) {
		perror ("socket failed");
		exit(EXIT_FAILURE);
	}

	// Attach socket to the PORT
	if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof(opt))) {
		perror("setsockopt");
		exit(EXIT_FAILURE);
	}

	address.sin_family = AF_INET;
	address.sin_addr.s_addr = INADDR_ANY;
	address.sin_port = htons( PORT );

	if (bind(server_fd, (struct sockaddr *) &address, sizeof (address)) <0) {
		perror("bind failed");
		exit(EXIT_FAILURE);
	}

	if (listen(server_fd, 3) < 0) {
		perror("listen");
		exit(EXIT_FAILURE);
	}
	if ((new_socket = accept(server_fd, (struct sockaddr*)&address, (socklen_t*)&addrlen)) < 0) {
		perror("accept");
		exit(EXIT_FAILURE);
	}
	
	int buflen = 0;
	int bufread = 1;
	int valoffset = 0;

	while (bufread) {
		char scb[4096] = {0};
		valread = read(new_socket, scb, sizeof(scb));
		
		if (!buflen){
			for (int z = 0; scb[z] != '#'; z++) {
				if (scb[z] > 47 && scb[z] < 58) {
					buflen = ((buflen * 10) + (scb[z] - 48)); 
				}
			}
		}

		if ((valread + valoffset) <= sizeof(buffer)) {
			for(int y = 0; y < valread; y++) {
				buffer[valoffset + y] = scb[y];
			}
		}

		if(buflen <= valread) {
			bufread = 0;
		} else {
			valoffset += valread;
			buflen -= valread;
		}

		printf("buflen: %d\n", buflen);
		printf("valoff: %d\n", valoffset);

	}
	printf( "%s\nsize: %i\n\n", buffer,valread);

	// -- json part
	
	for (int j = 0; buffer[j] != '{'; j++) {
		buffer[j] = ' ';
	}

	int r;

	jsmn_parser p;
	jsmntok_t t[256] = {0};

	jsmn_init(&p);
	r = jsmn_parse(&p, buffer, strlen(buffer), t, 256);

	char stx[128];
	
	// == OMCW JSON
	
	// Useful variables
	char sub[24] = "pageData";
	char scratch[16][64];

	int lgp0[9] = {0};
	// lgp0[x] = line counter for decoded json
	// + These values are used to count which lines attribs get assigned to
	//
	// Where x: is used in
	// 0: separator
	// 1: flash
	// 2: reverse
	// 3: border
	// 4: color
	// 5: height
	// 6: width
	// 7: textData
	//

	for(int q = 0; q < 16; q++) {
		for(int qq = 0; qq < sizeof(scratch[q]); qq++) {
			scratch[q][qq] = 0;
		}
	}

	for (int i = 1; i < r; i++) {
		if (jsoneq(buffer, &t[i], "bottomSolid") == 0) {
			sprintf(stx, "%.*s", t[i+1].end - t[i+1].start, buffer + t[i+1].start);
			int mt = strcmp(stx, "true");
			if (mt == 0) {
				omcw[1] = (omcw[1] | 1);
			} else {
				omcw[1] = (omcw[1] & ~1);
			}
		}
		if (jsoneq(buffer, &t[i], "topSolid") == 0) {
			sprintf(stx, "%.*s", t[i+1].end - t[i+1].start, buffer + t[i+1].start);
			int mt = strcmp(stx, "true");
			if (mt == 0) {
				omcw[1] = (omcw[1] | 2);
			} else {
				omcw[1] = (omcw[1] & ~2);
			}
		}
		if (jsoneq(buffer, &t[i], "regionSeparator") == 0) {
			sprintf(stx, "%.*s", t[i+1].end - t[i+1].start, buffer + t[i+1].start);
			int mt = strcmp(stx, "true");
			if (mt == 0) {
				omcw[1] = (omcw[1] | 4);
			} else {
				omcw[1] = (omcw[1] & ~4);
			}
		}
		if (jsoneq(buffer, &t[i], "topPage") == 0) {
			sprintf(stx, "%.*s", t[i+1].end - t[i+1].start, buffer + t[i+1].start);
			int fp = 0;
			sscanf(stx, "%d", &fp);
			if (fp >= 0 && fp < 255) {
				omcw[2] = fp;
			}
		}
		if (jsoneq(buffer, &t[i], "ldlPage") == 0) {
			sprintf(stx, "%.*s", t[i+1].end - t[i+1].start, buffer + t[i+1].start);
			int bp = 0;
			sscanf(stx, "%d", &bp);
			if (bp >= 0 && bp < 4) {
				omcw[3] = bp;
			}
		}
	// == pageData JSON

	if (strstr (buffer, sub)) {
		//
		// Header Attributes
		//
		if (jsoneq(buffer, &t[i], "pageNumber") == 0) {
			sprintf(stx, "%.*s", t[i+1].end - t[i+1].start, buffer + t[i+1].start);
			int pn = 0;
			sscanf(stx, "%d", &pn);
			if (pn >= 0 && pn < 255) {
				scratch[0][0] = pn;
			}

		}
		if (jsoneq(buffer, &t[i], "lineCount") == 0) {
			sprintf(stx, "%.*s", t[i+1].end - t[i+1].start, buffer + t[i+1].start);
			int lc = 0;
			sscanf(stx, "%d", &lc);
			if (lc >= 0 && lc < 16) {
				scratch[0][1] = lc;
			}
		}
		//
		// Page Attributes
		//
		if (jsoneq(buffer, &t[i], "freeze") == 0) {
			sprintf(stx, "%.*s", t[i+1].end - t[i+1].start, buffer + t[i+1].start);
			int t = strcmp(stx, "true");
			if (t == 0) {
				scratch[0][2] |= 4;
			} else {
				scratch[0][2] &= ~4;
			}
		}
		if (jsoneq(buffer, &t[i], "advisory") == 0) {
			sprintf(stx, "%.*s", t[i+1].end - t[i+1].start, buffer + t[i+1].start);
			int t = strcmp(stx, "true");
			if (t == 0) {
				scratch[0][2] |= 2;
			} else {
				scratch[0][2] &= ~2;
			}
		}
		if (jsoneq(buffer, &t[i], "warning") == 0) {
			sprintf(stx, "%.*s", t[i+1].end - t[i+1].start, buffer + t[i+1].start);
			int t = strcmp(stx, "true");
			if (t == 0) {
				scratch[0][2] |= 1;
			} else {
				scratch[0][2] &= ~1;
			}
		}
		//
		if (jsoneq(buffer, &t[i], "flip") == 0) {
			sprintf(stx, "%.*s", t[i+1].end - t[i+1].start, buffer + t[i+1].start);
			int t = strcmp(stx, "true");
			if (t == 0) {
				scratch[0][3] |= 4;
			} else {
				scratch[0][3] &= ~4;
			}
		}
		if (jsoneq(buffer, &t[i], "roll") == 0) {
			sprintf(stx, "%.*s", t[i+1].end - t[i+1].start, buffer + t[i+1].start);
			int t = strcmp(stx, "true");
			if (t == 0) {
				scratch[0][3] |= 2;
			} else {
				scratch[0][3] &= ~2;
			}
		}
		if (jsoneq(buffer, &t[i], "chain") == 0) {
			sprintf(stx, "%.*s", t[i+1].end - t[i+1].start, buffer + t[i+1].start);
			int t = strcmp(stx, "true");
			if (t == 0) {
				scratch[0][3] |= 1;
			} else {
				scratch[0][3] &= ~1;
			}
		}
		//
		// Line Attributes
		//
		if (jsoneq(buffer, &t[i], "separator") == 0) {
			sprintf(stx, "%.*s", t[i+1].end - t[i+1].start, buffer + t[i+1].start);
			
			int t = strcmp(stx, "true");
			if (t == 0) {
				scratch[0][4 + (2 * (lgp0[0] % 15))] |= 8;
			} else {
				scratch[0][4 + (2 * (lgp0[0] % 15))] &= ~8;
			}

			lgp0[0]++;

		}
		if (jsoneq(buffer, &t[i], "flash") == 0) {
			sprintf(stx, "%.*s", t[i+1].end - t[i+1].start, buffer + t[i+1].start);
			
			int t = strcmp(stx, "true");
			if (t == 0) {
				scratch[0][4 + (2 * (lgp0[1] % 15))] |= 4;
			} else {
				scratch[0][4 + (2 * (lgp0[1] % 15))] &= ~4;
			}

			lgp0[1]++;

		}
		if (jsoneq(buffer, &t[i], "reverse") == 0) {
			sprintf(stx, "%.*s", t[i+1].end - t[i+1].start, buffer + t[i+1].start);
			
			int t = strcmp(stx, "true");
			if (t == 0) {
				scratch[0][4 + (2 * (lgp0[2] % 15))] |= 2;
			} else {
				scratch[0][4 + (2 * (lgp0[2] % 15))] &= ~2;
			}

			lgp0[2]++;
			
		}
		if (jsoneq(buffer, &t[i], "border") == 0) {
			sprintf(stx, "%.*s", t[i+1].end - t[i+1].start, buffer + t[i+1].start);
			

			int t = strcmp(stx, "true");
			if (t == 0) {
				scratch[0][4 + (2 * (lgp0[3] % 15))] |= 1;
			} else {
				scratch[0][4 + (2 * (lgp0[3] % 15))] &= ~1;
			}

			lgp0[3]++;
			
		}
		if (jsoneq(buffer, &t[i], "color") == 0) {
			sprintf(stx, "%.*s", t[i+1].end - t[i+1].start, buffer + t[i+1].start);
			
			int cl = 0;
			sscanf(stx, "%d", &cl);
			if (cl >= 0 && cl < 16) {
				scratch[0][5 + (2 * (lgp0[4] % 15))] = cl;
			}

			lgp0[4]++;
			
		}
		//
		if (jsoneq(buffer, &t[i], "rowNumber") == 0) {
			sprintf(stx, "%.*s", t[i+1].end - t[i+1].start, buffer + t[i+1].start);
			
			int rn = 0;
			sscanf(stx, "%d", &rn);
			if (rn >= 0 && rn < 16) {
				scratch[0][34 + (2 * (lgp0[5] % 15))] = rn;
			}

			lgp0[5]++;
			
		}
		if (jsoneq(buffer, &t[i], "height") == 0) {
			sprintf(stx, "%.*s", t[i+1].end - t[i+1].start, buffer + t[i+1].start);

			int hx = 0;
			sscanf(stx, "%d", &hx);
			if (hx >= 0 && hx < 4) {
				hx = hx << 2;
				hx = hx & 12;
				scratch[0][35 + (2 * (lgp0[6] % 15))] |= hx;
				printf("%i\n", hx);
			}

			lgp0[6]++;
			
		}
		if (jsoneq(buffer, &t[i], "width") == 0) {
			sprintf(stx, "%.*s", t[i+1].end - t[i+1].start, buffer + t[i+1].start);
			
			int wx = 0;
			sscanf(stx, "%d", &wx);
			if (wx >= 0 && wx < 4) {
				wx = wx & 3;
				scratch[0][35 + (2 * (lgp0[7] % 15))] |= wx;
			}

			lgp0[7]++;
			
		}
		if (jsoneq(buffer, &t[i], "textData") == 0) {
			sprintf(stx, "%.*s", t[i+1].end - t[i+1].start, buffer + t[i+1].start);
			char data[64] = {0};
			int cadvance = 0;
			strncpy(data, stx, sizeof(data));

			for(int c = 0; c < sizeof(data); c++) {
				if (data[c] == 92 && data[c+1] == 92) {
					cadvance ++;
				}
				scratch[1 + (lgp0[8] % 15)][c] = data[c + cadvance];
			}

			lgp0[8]++;
			
		}
	}

	}
	for (int x = 0; x < sizeof(scratch[0]); x++) {
		printf ("%02x, ", scratch[0][x]);
	}
	printf("\n");
	for (int x = 0; x < sizeof(scratch[1]); x++) {
		printf ("%02x, ", scratch[1][x]);
	}
	printf("\n");
	for (int x = 0; x < sizeof(scratch[2]); x++) {
		printf ("%02x, ", scratch[2][x]);
	}
	printf("\n");
	for (int x = 0; x < sizeof(scratch[3]); x++) {
		printf ("%02x, ", scratch[3][x]);
	}
	printf("\n\n");

	if (scratch[0][0] > 0 && scratch[0][0] < 256) {
		for (int l = 0; l < sizeof(scratch[0]); l++) {
			pagestore[16 * scratch[0][0]][l] = scratch[0][l];
		}
		if(scratch[0][1] > 0 && scratch[0][1] < 16) {
			for (int j = 0; j < scratch[0][1]; j++) {
				strncpy(pagestore[(16 * scratch[0][0]) + 1 + j], scratch[1 + j], sizeof(scratch[1 + j]));
			}
			scratch[0][1] = 0;
		}
		scratch[0][0] = 0;
	}

	for (int x = 0; x < sizeof(pagestore[800]); x++) {
		printf ("%02x, ", pagestore[800][x]);
	}
	printf("\n");
	for (int x = 0; x < sizeof(pagestore[801]); x++) {
		printf ("%02x, ", pagestore[801][x]);
	}
	printf("\n");
	for (int x = 0; x < sizeof(pagestore[802]); x++) {
		printf ("%02x, ", pagestore[802][x]);
	}
	printf("\n");
	for (int x = 0; x < sizeof(pagestore[803]); x++) {
		printf ("%02x, ", pagestore[803][x]);
	}
	printf("\n\n");

	// ==

	// --

	send(new_socket, hello, strlen(hello), 0);
	close(new_socket);
	close(server_fd);

}

void* tcpServ(void* arg) {

	pthread_detach(pthread_self());
	
	while(1) {
		createSock();
	}

	pthread_exit(NULL);
}

void tcpEst() {
	pthread_t ptid;

	pthread_create(&ptid, NULL, &tcpServ, NULL);

}

void drawChar(int cx, int cy, char str[], IMAGE_T *charset, IMAGE_T *image) {
	// Charmap
	int lc = 0;
	RGBA8_T pixel = {0,0,0,0};
	for (lc = 0; lc < strlen(str); lc++) {

		int lx = 0;
		int ly = 0;

		if (str[lc]) {
			lx = str[lc] - 32;
			ly = str[lc] - 32;
		}

		lx = lx % 16;

		ly = ly / 16;
		ly = ly % 6; 

		for (j = 0; j < 30; j++) {
			for (k = 0; k < 30; k++) {
				getPixelRGB(charset, k + (lx * 30), j + (ly * 32), &pixel);
				setPixelRGB(image, cx + k + (lc * 17), cy + j, &pixel);
			}
		}
	}
}

//-------------------------------------------------------------------------

int pcount = 0;
int g0, g1 = 0;

int main(int argc, char *argv[])
{
	
	struct timespec ntime, ntime1;

	int32_t layer = 8991;

	srand(time(NULL));

	bcm_host_init();

    //--
	int m = 0;
	int n = 0;
	for (m = 0; m < 4096; m++) {
		for (n = 0; n < strlen(pagestore[m]); n++) {
			pagestore[m][n] = 32;	
		}
	}
	for (int mm = 1; mm < 256; mm++) {
		for (int nn = 0; nn < 16; nn++) {
			pagestore[16 * mm][5 + (nn * 2)] = 2;
		}
	}

	tcpEst();

    if (loadPng(&charmap, "charset2.png") == false)
    {
        fprintf(stderr, "unable to load charset2.png\n");
        exit(EXIT_FAILURE);
    }


    if (loadPng(&smallcharmap, "charset1.png") == false)
    {
        fprintf(stderr, "unable to load charset1.png\n");
        exit(EXIT_FAILURE);
    }

    initImage( &horz_image, VC_IMAGE_RGBA32, 720, 480, false );
    clearImageRGB( &horz_image, &clear_color );

    //--

    DISPMANX_DISPLAY_HANDLE_T display = vc_dispmanx_display_open(0);
    assert(display != 0);

    DISPMANX_MODEINFO_T info;
    int result = vc_dispmanx_display_get_info(display, &info);
    assert(result == 0);
    s_width = info.width;
    s_height = info.height;

    //---------------------------------------------------------------------

    BACKGROUND_LAYER_T backgroundLayer;
    initBackgroundLayer(&backgroundLayer, 0x0000, layer);


    initImageLayer ( &solid, s_width, s_height, VC_IMAGE_RGBA32 );
    createResourceImageLayer( &solid, layer );
    clearImageRGB( &(solid.image), &clear_color);


    initImageLayer ( &over, s_width, s_height, VC_IMAGE_RGBA32 );
    createResourceImageLayer( &over, layer+1 );
    clearImageRGB( &(over.image), &clear_color);


    //imageBoxFilledRGB( &(solid.image), 0, 0, 720, 480, &star_green );
    //imageBoxFilledRGB( &(solid.image), 0, 0, 720, 480, &star_black );
    imageBoxFilledRGB( &(solid.image), 0, 380, 720, 382, &star_white );
    imageBoxFilledRGB( &(solid.image), 0, 382, 720, 480, &star_purple );

    changeSourceAndUpdateImageLayer( &solid );

    //---------------------------------------------------------------------

    DISPMANX_UPDATE_HANDLE_T update = vc_dispmanx_update_start(0);
    assert(update != 0);

    addElementBackgroundLayer( &backgroundLayer, display, update );

    addElementImageLayerOffset( &solid, 0, 0, display, update );

    addElementImageLayerOffset( &over, 0, 0, display, update );

    result = vc_dispmanx_update_submit_sync(update);
    assert(result == 0);

	//---------------------------------------------------------------------

	//ReadData();
	//LoadData();

	int ldli = 1;
	int ldlcount = 0;
	int pagecount = 0;

	// Set default omcw state
	omcw[1] = 5;
	omcw[2] = 1;
	omcw[3] = 1;

	while (run) {
		
		int kp = 0;
		if (keyPressed(&kp)) {

			kp = tolower(kp);

			switch(kp) {
				case 27:
					run = false;	
					break;
				case 'q':
					run = false;	
					break;
				default:

					break;
			}
		}

		DISPMANX_UPDATE_HANDLE_T update = vc_dispmanx_update_start(0);
		assert(update != 0);

		int result = vc_dispmanx_update_submit_sync(update);
		assert(result == 0);

//--

		time_t s;
		struct tm* current_time;

		// Time in seconds
		s = time(NULL);

		// Get current time
		current_time = localtime(&s);
		
		// Establish current time variables
		int hr = current_time -> tm_hour;
		int min = current_time -> tm_min;
		int sec = current_time -> tm_sec;
        
		// Character sets for hour and meridian
		char chr[3];
		char mer[3];
		
		// Set meridian to AM by default
		sprintf(mer, "AM");
        
		// Convert hr int from 24 hour to 12 hour
		if (hr == 0)
		{
			sprintf(chr, "12");
		}
		
		//If hr is 12, set to PM
		if (hr == 12)
			sprintf(mer, "PM");
		
		// Subtract off time after 12
		if (hr > 0 && hr > 12)
		{
			hr -= 12;
			sprintf(mer, "PM");
		}
		
		// Add padding to beginning if 1..9
		if (hr > 0 && hr < 10)
		{
			sprintf(chr, " %01d", hr);
		} else if (hr > 9 && hr < 24) {
			sprintf(chr, "%02d", hr);
		}

		// Declare weekday
		char wday[4];

		// Convert weekday int to abbreviation
		switch (current_time->tm_wday)
		{
			case 0:
				sprintf(wday, "Sun");
				break;
			case 1:
				sprintf(wday, "Mon");
				break;
			case 2:
				sprintf(wday, "Tue");
				break;
			case 3:
				sprintf(wday, "Wed");
				break;
			case 4:
				sprintf(wday, "Thu");
				break;
			case 5:
				sprintf(wday, "Fri");
				break;
			case 6:
				sprintf(wday, "Sat");
				break;
			case 7:
				sprintf(wday, "Sun");
				break;
		}
		
		// Declare month
		char mon[4];
		
		// Convert month int to abbreviation
		switch(current_time->tm_mon)
		{
			case 0:
				sprintf(mon, "Jan");
				break;
			case 1:
				sprintf(mon, "Feb");
				break;
			case 2:
				sprintf(mon, "Mar");
				break;
			case 3:
				sprintf(mon, "Apr");
				break;
			case 4:
				sprintf(mon, "May");
				break;
			case 5:
				sprintf(mon, "Jun");
				break;
			case 6:
				sprintf(mon, "Jul");
				break;
			case 7:
				sprintf(mon, "Aug");
				break;
			case 8:
				sprintf(mon, "Sep");
				break;
			case 9:
				sprintf(mon, "Oct");
				break;
			case 10:
				sprintf(mon, "Nov");
				break;
			case 11:
				sprintf(mon, "Dec");
				break;
		}

		// Declare day of month
		char mday[3];

		// If single digit day, add padding, otherwise print int
		if (current_time->tm_mday < 10)
		{
			sprintf(mday, " %01d", current_time->tm_mday);
		} else {
			sprintf(mday, "%02d", current_time->tm_mday);
		}
        
		char ldlclock[12];
		char ldldate[12];
        
		//%3s %3s %2d           %2d:%02d:%02d %2s
		//%3s %3s %2d           %2d:%02d:%02d    
		sprintf(ldlclock, "%s:%02d:%02d %2s", chr, min, sec, mer);
		sprintf(ldldate, "%3s %3s %s", wday, mon, mday);
		char ldlsmallstr0[48] = "";
		sprintf(ldlsmallstr0, "%s           %s", ldldate, ldlclock);

	
	imageBoxFilledRGB( &(solid.image), 0, 0, 720, 480, &clear_color );
	//imageBoxFilledRGB( &(solid.image), 0, 380, 720, 480, &clear_color );

	if (omcw[1] & 1) {
		imageBoxFilledRGB( &(solid.image), 0, 380, 720, 480, &star_purple );
	}
	if (omcw[1] & 2) {
		if (pagestore[16 * omcw[2]][5] == 5) {
			imageBoxFilledRGB( &(solid.image), 0, 0, 720, 379, &star_purple );
		} else if (pagestore[16 * omcw[2]][5] == 0) {
			imageBoxFilledRGB( &(solid.image), 0, 0, 720, 379, &star_gray );
		} else {
			imageBoxFilledRGB( &(solid.image), 0, 0, 720, 379, &star_green );
		}
	}
	if (omcw[1] & 4) {
		imageBoxFilledRGB( &(solid.image), 0, 380, 720, 381, &star_white );
	}
	
	changeSourceAndUpdateImageLayer( &solid );

	imageBoxFilledRGB( &(over.image), 0, 0, 720, 380, &clear_color );

	if (omcw[2] > 0 && omcw[2] < 256) {
		if (pagestore[16 * omcw[2]][0] > 0 
		&& pagestore[16 * omcw[2]][0] < 256) {
			if (pagestore[16 * omcw[2]][1] > 0 
			&& pagestore[16 * omcw[2]][1] < 16) {
				int lc = 0;
				for(int i = 0; (i < pagestore[16 * omcw[2]][1]) | (lc < 16); i++) {	
					if (((pagestore[(16 * omcw[2])][35 + (2 * i)] & 12) >> 2) == 0) {
						drawChar(horizalign, 
							(40 + (20 * lc) + valign), 
							pagestore[(16 * omcw[2]) + i + 1], 
							&smallcharmap, &(over.image));
						lc += 1;
					}
					if (((pagestore[(16 * omcw[2])][35 + (2 * i)] & 12) >> 2) == 1) {
						drawChar(horizalign, 
							(40 + (20 * lc) + 2 + valign), 
							pagestore[(16 * omcw[2]) + i + 1], 
							&charmap, &(over.image));
						lc += 2;
					}
				}
			}
		
		}
	}

	imageBoxFilledRGB( &(over.image), 0, 380, 720, 480, &clear_color );
	
	if (omcw[3]) {

		drawChar(horizalign, 383, ldlsmallstr0, &smallcharmap, &(over.image));
		imageBoxFilledRGB( &(over.image), 0, 405, 720, 480, &clear_color );
		if (pagestore[800][1] > 0 && pagestore[800][1] < 16) {
			if(ldli > 0 && ldli < 16) {
				drawChar(horizalign, 405, pagestore[800 + ldli], &charmap, &(over.image));
			}
		}
	}
        ldlcount++;

	if((ldlcount % 40) == 39) {
	ldli++;
		if(ldli <= pagestore[800][1]) {
				
		} else {
			ldli = 1;
		}
	}

	if((pagecount % 11000) == 10999) {
	}


	changeSourceAndUpdateImageLayer( &over );

//--

	ntime.tv_sec = 0;
	ntime.tv_nsec = 16000000;
        nanosleep(&ntime, &ntime1);
    }

    keyboardReset();

    //destroyBackgroundLayer(&backgroundLayer);
    //destroyImageLayer(&imageLayer);

    result = vc_dispmanx_display_close(display);
    assert(result == 0);

    return 0;
}

