//
//  lcd_gui_manage.c	  Part of GUI support library, Figure data manager
//  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 <stdio.h>						// debug
#include <stddef.h>						// NULL,...
#include <stdlib.h>						// abs()
#include "lcd_gui_figure.h"
#include "lcd_gui_manage.h"

//#define DEBUG1
//#define DEBUG2

#ifdef DEBUG1
#include <stdio.h>						// Debug
#define DEBUGP(...)		printf(__VA_ARGS__)
#define DUMP(...)		lcd_gui_figure_manageDump(__VA_ARGS__)
#else
#define DEBUGP(...)
#define DUMP(...)
#endif

//
//	Global area
//
struct lcd_guiGlobalFlags	lcd_guiGlobalFlags;


//
//	State control
//

//	Request for redisplay
void lcd_guiSetDirty(struct lcd_gui	*s){
	if (s) {
		s->flags.dirty           = 1;
		lcd_guiGlobalFlags.dirty = 1;
	}
	return;
}

//	Figure is disable
void lcd_guiSetHidden(struct lcd_gui *s, int f){
	if (s) {
		if (s->flags.hidden != f) {
			s->flags.hidden = f;
			if (f) {	// display->hidden
				lcd_guiSetDirtys(lcd_guiGetGroupParent(s));
			} else {	// hidden->display
				lcd_guiSetDirty(s);
			}
		}
	}
	return;
}

//
//	Link control
//

// Pointer relink
void lcd_guiSetRelink(struct lcd_gui *s){
	struct lcd_gui *p;

	p = NULL;
	for(; s != NULL; s = s->next) {
		s->prev = p;
		p = s;
		if (s->dispProg == lcd_guiDisplayGroup) {
			struct lcd_guiGroup		*g;
			struct lcd_guiParent	*a;

			g = (struct lcd_guiGroup *)s;
			a = (struct lcd_guiParent *)(g->top);
			if (a->seg.dispProg == NULL) {
				a->parent = g;
			}
			lcd_guiSetRelink(g->top);
		}
	}
	return;
}

//	Getting the parent block
struct lcd_guiGroup *lcd_guiGetGroupParent(struct lcd_gui *seg){
	struct lcd_gui			*s;
	struct lcd_guiParent	*p;

	p = NULL;
	for(s = seg; s != NULL; s = s->prev) {	// Top figure is parent block
		if (s->dispProg == NULL) {
			p = (struct lcd_guiParent *)s;
		}
	}
	return((p != NULL) ? p->parent : NULL);
}

//	The "Group segment" is searched with coordinate
struct lcd_guiGroup *lcd_guiFindGroupByPoint(struct lcd_gui *root, struct lcd_guiCoordinate *point) {
	struct lcd_guiGroup	*found;
	struct lcd_gui		*s;

	found = NULL;
	for(s = root; s != NULL; s = s->next) {		// Get last
		if (s->next == NULL) {
			break;
		}
	}
	for(; s != NULL; s = s->prev) {				// New to old
		if ((!s->flags.hidden) && (s->dispProg == lcd_guiDisplayGroup)) {
			struct lcd_guiGroup	*g;

			g = (struct lcd_guiGroup *)s;
			if ((g->area.x <= point->x) && (point->x < (g->area.x + g->area.width)) &&
			    (g->area.y <= point->y) && (point->y < (g->area.y + g->area.height))) {
				struct lcd_guiCoordinate	a;

				a.x = point->x - g->area.x;
				a.y = point->y - g->area.y;
				if ((found = lcd_guiFindGroupByPoint(g->top, &a)) != NULL) {
					break;
				}
				if (found == NULL) {
					found = g;
					break;
				}
			}
		}
	}
	return(found);
}


//
//	Utilities
//

// int to 7 segment pattern
void lcd_guiSet7segFixedPoint(struct lcd_gui7seg *seg, int i, int dp){
	const unsigned char	segmentFont[] = {
//            abcdefg.
			0b11111100,	// 0
			0b01100000,	// 1
			0b11011010,	// 2
			0b11110010,	// 3
			0b01100110,	// 4
			0b10110110,	// 5
			0b10111110,	// 6
			0b11100000,	// 7
			0b11111110,	// 8
			0b11110110,	// 9
	};
#define DOT_POINT	0b00000001
#define MINUS_SIGN	0b00000010
#define BLANK_OFF	0b00000000
	unsigned char	*pat;
	int				n;
	int				sign;

	n   = seg->column;
	pat = seg->pattern + n;
	sign = 0;
	if (i < 0) {
		i = abs(i);
		sign = 1;
		--n;
	}
	for(; n > 0; --n) {
		int	f;

		f = segmentFont[i % 10];
		if (dp == 0) {
			f |= DOT_POINT;
		}
		*(--pat) = f;
		--dp;
		i /= 10;
		if ((i == 0) && (dp < 0)) {
			break;
		}
	}
	if (sign) {
		*(--pat) = MINUS_SIGN;
	}
	for(; n > 1; --n) {
		*(--pat) = BLANK_OFF;
	}
	lcd_guiSetDirtys(seg);
	return;
}

#ifdef DEBUG1
void lcd_guiDebugDump(struct lcd_gui *s){
	DEBUGP("Dump: start=%08x\n", s);
	for(; s != NULL; s = s->next) {
		if (s->dispProg == lcd_guiDisplayGroup) {
			struct lcd_guiGroup *p;

			p = (struct lcd_guiGroup *)s;
			DEBUGP("Group=(%d,%d,%d,%d),%04x,%08x\n", p->area.x,p->area.y,p->area.width,p->area.height,p->backColor,p->eventProg);
			lcd_guiDebugDump(p->top);
		} else if (s->dispProg == lcd_guiDisplayRect) {
			struct lcd_guiRect *p;

			p = (struct lcd_guiRect *)s;
			DEBUGP("Rect=(%d,%d,%d,%d),%04x\n", p->area.x,p->area.y,p->area.width,p->area.height,p->color);
		} else if (s->dispProg == lcd_guiDisplayLine) {
			DEBUGP("Line\n");
		} else if (s->dispProg == lcd_guiDisplayPoly) {
			DEBUGP("Poly\n");
		} else if (s->dispProg == lcd_guiDisplayStr) {
			DEBUGP("Str\n");
		} else if (s->dispProg == lcd_guiDisplayImage) {
			DEBUGP("Image\n");
		} else if (s->dispProg == lcd_guiDisplayText) {
			struct lcd_guiText *p;

			p = (struct lcd_guiText *)s;
			DEBUGP("Text=(%d,%d,%d,%d),(%04x,%04x),(%d,%d),'%s',%08x\n",
					p->area.x,p->area.y,p->area.width,p->area.height,
					p->color.face,p->color.back,
					p->attr.horizontalAlign,p->attr.varticalAlign,
					p->str,p->font);
		} else if (s->dispProg == lcd_guiDisplayGage) {
			DEBUGP("Gage\n");
		} else if (s->dispProg == lcd_guiDisplay7seg) {
			DEBUGP("7seg\n");
		} else if (s->dispProg == lcd_guiDisplayBarChart) {
			DEBUGP("BarChart\n");
		} else if (s->dispProg == NULL) {
			struct lcd_guiParent *p;

			p = (struct lcd_guiParent *)s;
			DEBUGP("Parent=%08x\n", p->parent);
		} else {
			DEBUGP("Dump: Unkown=%08x\n", s);
		}
	}
	return;
}
#endif	// DEBUG
