/* Copyright (C) 2007  Mikko Sysikaski <mikko.sysikaski@gmail.com>
 * This program is free software distributed under GNU General Public License
 * version 3 or (at your option) any later version.
 * No warranty of any kind is provided. See the accompanying file COPYING for details.
 */

#include "lcd.h"
#include <GL/gl.h>
#include <fstream>
#include <cstdio>
#include <limits>
#include <cstring>

static const float SIZEH = 1.0f;
static const float SIZEW = 0.5f*SIZEH;

LCD LCD::m_instance;

void LCD::doLoad(const char* deffile)
{
	std::ifstream in(deffile);
	if (!in.is_open()) {
		fprintf(stderr, "Couldn't open lcd definition file %s\n", deffile);
		return;
	}

	int num = 0;
	while(in && num < 'z'-'a' + 10 + 2) {
		char ch;
		short res = 0;
		if (in.peek() == '#') {
			in.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
			continue;
		}
		while((ch=in.get()) != '\n') {
			if (!in)
				return;
			short tmp;
			if (isdigit(ch))
				tmp = ch-'0';
			else
				tmp = ch-'a'+10;
			res |= 1<<tmp;
		}

		if (num <= 'z'-'a')
			alphabet[num] = res;
		else
			digits[num-('z'-'a'+1)] = res;

		++num;
	}
	
}

inline
void LCD::line(float x1, float y1, float x2, float y2)
{
	glVertex2f(x1, y1);
	glVertex2f(x2, y2);
}

inline
void LCD::print(LCDLine ch, float offset)
{
	if (ch & UP)
		line(offset, SIZEH, offset+SIZEW, SIZEH);
	if (ch & UP_LEFT)
		line(offset, SIZEH, offset, 0.5f*SIZEH);
	if (ch & UP_MIDDLE)
		line(offset+0.5f*SIZEW, SIZEH, offset+0.5f*SIZEW, 0.5f*SIZEH);
	if (ch & UP_RIGHT)
		line(offset+SIZEW, SIZEH, offset+SIZEW, 0.5f*SIZEH);
	if (ch & MIDDLE_LEFT)
		line(offset, 0.5f*SIZEH, offset+0.5f*SIZEW, 0.5f*SIZEH);
	if (ch & MIDDLE_RIGHT)
		line(offset+0.5f*SIZEW, 0.5f*SIZEH, offset+SIZEW, 0.5f*SIZEH);
	if (ch & DOWN_LEFT)
		line(offset, 0.5f*SIZEH, offset, 0);
	if (ch & DOWN_MIDDLE)
		line(offset+0.5f*SIZEW, 0.5f*SIZEH, offset+0.5f*SIZEW, 0);
	if (ch & DOWN_RIGHT)
		line(offset+SIZEW, 0.5*SIZEH, offset+SIZEW, 0);
	if (ch & DOWN)
		line(offset, 0, offset+SIZEW, 0);
	if (ch & UP_BSLASH)
		line(offset, SIZEH, offset+0.5f*SIZEW, 0.5f*SIZEH);
	if (ch & UP_SLASH)
		line(offset+0.5f*SIZEW, 0.5f*SIZEH, offset+SIZEW, SIZEH);
	if (ch & DOWN_SLASH)
		line(offset, 0, offset+0.5f*SIZEW, 0.5f*SIZEH);
	if (ch & DOWN_BSLASH)
		line(offset+0.5f*SIZEW, 0.5f*SIZEH, offset+SIZEW, 0);
}

int LCD::doPrint(const char* str, Alignment align)
{
	if (align == RIGHT) {
		glPushMatrix();
		glTranslatef(int(-strlen(str))*SIZEW*1.2f, 0, 0);
	} else if (align == MIDDLE) {
		glPushMatrix();
		glTranslatef(int(-strlen(str))*SIZEW*0.6f, 0, 0);
	}
	//	glTranslatef(-1*SIZEW*1.2f, 0, 0);
	glBegin(GL_LINES);
	float offset = 0.0f;
	int counter = 0;
	for(; *str; ++str) {
		LCDLine tmp;
		if (isdigit(*str)) {
			tmp = LCDLine(this->digits[*str-'0']);
			print(tmp, offset);
		} else if (isalpha(*str)) {
			tmp = LCDLine(alphabet[*str-'a']);
			print(tmp, offset);
		} else if (*str == '.') {
			glEnd();
			glBegin(GL_POINTS);
			glVertex2f(offset-SIZEW*0.1f, 0);
			glEnd();
			glBegin(GL_LINES);
			continue;
		} else if (*str == '/')
			print(LCDLine(UP_SLASH | DOWN_SLASH), offset);
		else if (*str == '\n') {
			offset = 0;
			glEnd();
			glTranslatef(0, -1.2, 0);
			glBegin(GL_LINES);
			++counter;
			continue;
		} else if (*str == '-')
			print(LCDLine(MIDDLE_LEFT | MIDDLE_RIGHT), offset);
		else if (*str == '\"') {
			glEnd();
			glBegin(GL_POINTS);
			glVertex2f(offset+SIZEW*0.2, SIZEH*0.8);
			glVertex2f(offset+SIZEW*0.8, SIZEH*0.8);
			glEnd();
			glBegin(GL_LINES);
		}
#ifdef _NOUTF8
		else if (*str == ';') {
#else
		else if (!strncmp(str, "ä", 2)) {
#endif
			print(LCDLine(this->alphabet[0]), offset);
			glEnd();
			glBegin(GL_POINTS);
			glVertex2f(offset+SIZEW*0.3, SIZEH*1.2);
			glVertex2f(offset+SIZEW*0.7, SIZEH*1.2);
			glEnd();
			glBegin(GL_LINES);
#ifndef _NOUTF8
			++str;
#endif
		}// else printf("lol: %i: %c\n", *str, *str);
		offset += SIZEW*1.2f;
	}
	glEnd();
	if (align > 0)
		glPopMatrix();
	return counter;
}
