//
//  lcd_gui_create.c	  Part of GUI support library, Generic object
//  Copyright(C)2014 Toyohiko Togashi tog001@nifty.com
//
//
//  This program is free software; you can redistribute it and/or modify it under the terms of the
//  GNU General Public License as published by the Free Software Foundation; either version 3
//  of the License, or (at your option) any later version.
//
//  This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
//  without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
//  See the GNU General Public License for more details.
//
//  You should have received a copy of the GNU General Public License along with this program.
//  If not, see <http://www.gnu.org/licenses/>
//
//
//    Update history
//    ---------- ----- -------------------------------------------
//    2014.02.15 v0.0  First cording
//    2014.03.15 v0.2  Commit
//

#include <stddef.h>
#include <stdlib.h>						// alloc,free
#include "lcd_gui_figure.h"
#include "lcd_gui_manage.h"
#include "lcd_gui_create.h"
#include "lcd_draw.h"					// LCD_SCREEN_WIDTH,...


//=====================================================================
//
//		Static memory functions
//
//=====================================================================

//
//	Argument is converted to control block
//
struct lcd_guiRect *lcd_guiInitRect(struct lcd_guiRect *alloc, short x, short y, short width, short height, unsigned short color){
	lcd_guiSetDirty(&(alloc->seg));
	alloc->seg.dispProg    = lcd_guiDisplayRect;
	alloc->area.x          = x;
	alloc->area.y          = y;
	alloc->area.width      = width;
	alloc->area.height     = height;
	alloc->color           = color;
	return(alloc);
}

struct lcd_guiLine *lcd_guiInitLine(struct lcd_guiLine *alloc, short sx, short sy, short ex, short ey, short lineWidth, unsigned short color){
	lcd_guiSetDirty(&(alloc->seg));
	alloc->seg.dispProg    = lcd_guiDisplayLine;
	alloc->startPoint.x    = sx;
	alloc->startPoint.y    = sy;
	alloc->endPoint.x      = ex;
	alloc->endPoint.y      = ey;
	alloc->color           = color;
	alloc->lineWidth       = lineWidth;
	return(alloc);
}

struct lcd_guiStr *lcd_guiInitStr(struct lcd_guiStr *alloc, short x, short y, unsigned short faceColor, unsigned short backColor, char *str){
	lcd_guiSetDirty(&(alloc->seg));
	alloc->seg.dispProg    = lcd_guiDisplayStr;
	alloc->point.x         = x;
	alloc->point.y         = y;
	alloc->color.face      = faceColor;
	alloc->color.back      = backColor;
	alloc->str             = str;
	return(alloc);
}

struct lcd_guiImage *lcd_guiInitImage(struct lcd_guiImage *alloc, short x, short y, short width, short height, unsigned short *image){
	lcd_guiSetDirty(&(alloc->seg));
	alloc->seg.dispProg    = lcd_guiDisplayImage;
	alloc->area.x          = x;
	alloc->area.y          = y;
	alloc->area.width      = width;
	alloc->area.height     = height;
	alloc->image           = image;
	return(alloc);
}

struct lcd_guiPoly *lcd_guiInitPoly(struct lcd_guiPoly *alloc, struct lcd_guiCoordinate *point, int n, int m, short lineWidth, unsigned short color){
	lcd_guiSetDirty(&(alloc->seg));
	alloc->seg.dispProg    = lcd_guiDisplayPoly;
	alloc->color           = color;
	alloc->lineWidth       = lineWidth;
	alloc->n               = n;
	alloc->m               = m;
	alloc->point           = point;
	return(alloc);
}

struct lcd_guiArc *lcd_guiInitArc(struct lcd_guiArc *alloc, short x, short y, short r, float srad, float erad, short lineWidth, unsigned short color){
	lcd_guiSetDirty(&(alloc->seg));
	alloc->seg.dispProg    = lcd_guiDisplayArc;
	alloc->center.x        = x;
	alloc->center.y        = y;
	alloc->r               = r;
	alloc->startRad        = srad;
	alloc->endRad          = erad;
	alloc->lineWidth       = lineWidth;
	alloc->color           = color;
	return(alloc);
}

struct lcd_guiText *lcd_guiInitText(struct lcd_guiText *alloc, short x, short y, short width, short height,
		unsigned short faceColor, unsigned short backColor, int hAlign, int vAlign, char *str, const struct lcd_font *font){
	lcd_guiSetDirty(&(alloc->seg));
	alloc->seg.dispProg    = lcd_guiDisplayText;
	alloc->area.x          = x;
	alloc->area.y          = y;
	alloc->area.width      = width;
	alloc->area.height     = height;
	alloc->color.face      = faceColor;
	alloc->color.back      = backColor;
	alloc->attr.horizontalAlign = hAlign;
	alloc->attr.varticalAlign   = vAlign;
	alloc->str             = str;
	alloc->font            = font;
	return(alloc);
}

struct lcd_guiGage *lcd_guiInitGage(struct lcd_guiGage *alloc, short x, short y, short width, short height,
		unsigned short faceColor, unsigned short backColor, int vartical, float value){
	lcd_guiSetDirty(&(alloc->seg));
	alloc->seg.dispProg    = lcd_guiDisplayGage;
	alloc->area.x          = x;
	alloc->area.y          = y;
	alloc->area.width      = width;
	alloc->area.height     = height;
	alloc->color.face      = faceColor;
	alloc->color.back      = backColor;
	alloc->attr.vartical   = vartical;
	alloc->value           = value;
	return(alloc);
}

struct lcd_guiBarChart *lcd_guiInitBarChart(struct lcd_guiBarChart *alloc, short x, short y, short width, short height,
		unsigned short backColor, int vartical, int n, float *value, unsigned short *color){
	lcd_guiSetDirty(&(alloc->seg));
	alloc->seg.dispProg    = lcd_guiDisplayBarChart;
	alloc->area.x          = x;
	alloc->area.y          = y;
	alloc->area.width      = width;
	alloc->area.height     = height;
	alloc->backColor       = backColor;
	alloc->attr.vartical   = vartical;
	alloc->number          = n;
	alloc->value           = value;
	alloc->color           = color;
	return(alloc);
}

struct lcd_gui7seg *lcd_guiInit7seg(struct lcd_gui7seg *alloc, short x, short y, short width, short height,
		unsigned short faceColor, unsigned short backColor, short lineWidth, int column, unsigned char *pattern){
	lcd_guiSetDirty(&(alloc->seg));
	alloc->seg.dispProg    = lcd_guiDisplay7seg;
	alloc->area.x          = x;
	alloc->area.y          = y;
	alloc->area.width      = width;
	alloc->area.height     = height;
	alloc->color.face      = faceColor;
	alloc->color.back      = backColor;
	alloc->lineWidth       = lineWidth;
	alloc->column          = column;
	alloc->pattern         = pattern;
	return(alloc);
}

struct lcd_guiParent *lcd_guiInitParent(struct lcd_guiParent *alloc, struct lcd_guiGroup *parent){
	alloc->seg.dispProg     = NULL;
	alloc->seg.flags.hidden = 1;
	alloc->parent           = parent;
	return(alloc);
}

struct lcd_guiGroup *lcd_guiInitGroup(
		struct lcd_guiGroup	*alloc,
		short				x,
		short				y,
		short				width,
		short				height,
		unsigned short		backColor,
		struct lcd_gui		*figures,
		void				(*eventProg)(enum lcd_guiEvent event, struct lcd_guiCoordinate *touch, struct lcd_guiGroup *seg))
{
	struct lcd_guiParent	*p;

	alloc->seg.dispProg = lcd_guiDisplayGroup;
	alloc->area.x       = x;
	alloc->area.y       = y;
	alloc->area.width   = width;
	alloc->area.height  = height;
	alloc->backColor    = backColor;
	alloc->eventProg    = eventProg;
	lcd_guiSetDirtys(alloc);

	// Create or init dummy figure (parent pointer)
	p = (struct lcd_guiParent *)alloc->top;
	if (p == NULL) {
		p = lcd_guiNewParent(alloc);
	} else {
		lcd_guiInitParent(p, alloc);
	}
	if (figures != NULL) {
		p->seg.next   = figures;
		figures->prev = (struct lcd_gui *)p;
	}
	return(alloc);
}

void lcd_guiDefaultActionRoot(enum lcd_guiEvent event, struct lcd_guiCoordinate *touch, struct lcd_guiGroup *seg){
	struct lcd_guiRoot *root;

	if (event == LCD_GUI_EVENT_TOUCH) {
		root = (struct lcd_guiRoot *)seg;
		if (root->popup) {
			lcd_guiDelete(root->popup);
			root->popup = NULL;
		}
	}
	return;
}

struct lcd_guiRoot	*lcd_guiInitRoot(struct lcd_guiRoot *alloc, unsigned short backColor, struct lcd_gui *figures, void (*eventProg)(enum lcd_guiEvent event, struct lcd_guiCoordinate *touch, struct lcd_guiGroup *seg)){
	if (eventProg == NULL) {
		eventProg = lcd_guiDefaultActionRoot;
	}
	lcd_guiInitGroup((struct lcd_guiGroup *)alloc, 0, 0, LCD_SCREEN_WIDTH, LCD_SCREEN_HEIGHT, backColor, figures, eventProg);
	alloc->popup = NULL;
	return(alloc);
}


//=====================================================================
//
//		Dynamic memory functions
//
//=====================================================================

//
//	Allocation segment block
//
struct lcd_gui	*lcd_guiAlloc(struct lcd_guiGroup *group, size_t len){
	struct lcd_gui	*alloc;

	if ((alloc = calloc(1, len)) != NULL) {
		if (group != NULL) {
			alloc->flags.malloc = 1;
			if (group->top == NULL) {
				group->top = alloc;
			} else {
				struct lcd_gui	*p;

				for(p = group->top; p != NULL; p = p->next){
					if (p->next == NULL) {	// This block is last
						p->next     = alloc;
						alloc->prev = p;
						alloc->next = NULL;
						break;
					}
				}
			}
		}
	}
	return(alloc);
}


//
//	Deallocation segment block
//
void lcd_guiDealloc(struct lcd_gui *alloc){

	if (alloc->dispProg == lcd_guiDisplayGroup) {
		struct lcd_guiGroup *g;
		struct lcd_gui 		*p;
		struct lcd_gui 		*s;

		g = (struct lcd_guiGroup *)alloc;
		for(p = g->top; p != NULL; p = s){
			s = p->next;
			lcd_guiDealloc(p);
		}
	}
	if (alloc->prev != NULL) {
		alloc->prev->next = alloc->next;
	}
	if (alloc->next != NULL) {
		alloc->next->prev = alloc->prev;
	}
	if (alloc->flags.malloc) {
		free(alloc);
	} else {
		alloc->next = NULL;
		alloc->prev = NULL;
	}
	return;
}

