/*
 *  Copyright (C) 2008 Tuomas Peippo
 *
 *  This program is distributed under the terms of the
 *  GNU General Public License.
 *
 *  This file is part of Dave the Ordinary Spaceman.
 *
 *  Dave the Ordinary Spaceman 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.
 *
 *  Dave the Ordinary Spaceman 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 Dave the Ordinary Spaceman. If not, see
 *  <http://www.gnu.org/licenses/>.
 *
 */

#include "teletext.h"

#include "library.h"
#include <sstream>

const float realHeight = 80;
const float realWidth = 384;

// Fonttitiedoston rivit ja sarakkeet
const unsigned int letter_rows = 4;
const unsigned int letter_cols = 32;

Teletext::Teletext(const std::string &filename) : scale_x(1.0f), scale_y(1.0f), r(0), g(0), b(0), a(1) {

  using namespace std;
  if(filename.empty())
    font = lib["letters.png"];
  else
    font = lib[filename.c_str()];

  font->nearest();
  
  // Ainoastaan isot kirjaimet, muita voi lisäillä loppuun sitä mukaa ku tarvii
  unsigned int first = ' ';

  unsigned int i = first;
  int montako=0;
  for (i = first; i <= 'Z'; i++) {  
	std::string asciiString(1, i);
    characters[asciiString] = i - first;
    montako++;
  }

  //Isot ääkköset
  characters["RUATTALAANENOO"] = 27 + 32;
  characters["AE"] = 28 + 32;
  characters["OE"] = 29 + 32;

  for (i = '^'; i <= 'z'; i++) {
    std::string asciiString(1, i);
        const size_t size = characters.size();
	characters[asciiString] = size;
  }

  //Pienet ääkköset
  characters["ruattalaanenoo"] = 27 + 64;
  characters["ae"] = 28 + 64;
  characters["oe"] = 29 + 64;

  //Erikoismerkit
  characters["ylaloota"     ] =  0 + 32*3;
  characters["alaloota"     ] =  1 + 32*3;
  characters["vasenloota"   ] =  2 + 32*3;
  characters["oikealoota"   ] =  3 + 32*3;
  characters["loota"        ] =  4 + 32*3;
  characters["rasteriloota" ] =  5 + 32*3;
  characters["shakkiloota1" ] =  6 + 32*3;
  characters["vasenalaloota"] =  7 + 32*3;
  characters["vasenylaloota"] =  8 + 32*3;
  characters["oikeaylaloota"] =  9 + 32*3;
  characters["oikeaalaloota"] = 10 + 32*3;

  //for (std::map<std::string, int>::iterator i=characters.begin(); i!=characters.end(); ++i)
  //  cerr << i->first << " : " << i->second << endl;

  set_colors((float [4]){1.0f,1.0f,1.0f,1.0f}, (float [4]){1.0f,1.0f,1.0f,0.0f});
}

Teletext::~Teletext() {
 /*
  using namespace std;
  if (characters.size()) {
   
    map<const std::string, int, ltstr>::iterator iter;
    for(iter=characters.begin();iter!=characters.end();iter++){
      delete [] (*iter).first; 
    }
  }
  
  characters.clear();*/
}

void Teletext::set_char(const std::string &text, std::string::size_type pos) {

 if(pos >= this->text.length())
   return;
   
   colorData color;
   colorData bgColor;
   
   color.r = r;
   color.g = g;
   color.b = b;
   color.a = a;
   
   bgColor.r = bR;
   bgColor.g = bG;
   bgColor.b = bB;
   bgColor.a = bA;

   colorTable[pos] = color;
   bgColors[pos] = bgColor;
   
  this->text.replace(pos, 1, text);  
}

void Teletext::replace(const std::string &text, std::string::size_type pos)
{
  for (std::string::size_type i=0; i<text.size(); i++)
    set_char(std::string(1, text[i]), pos + i);
}

std::string Teletext::get_text() { return text;}

void Teletext::set_text(const std::string &text) {
  
  colorData color;
  colorData bgColor;

  color.r = r;
  color.g = g;
  color.b = b;
  color.a = a;
  
  bgColor.r = bR;
  bgColor.g = bG;
  bgColor.b = bB;
  bgColor.a = bA;
  
  std::string::const_iterator iter;
  
  for(iter=text.begin(); iter != text.end();iter++){
    
    colorTable[(iter)-text.begin()] = color;
    bgColors[(iter)-text.begin()] = bgColor;
  }

  this->text = text;  
}

void Teletext::set_position(const Vector &p) {
  
  position = p;
}

void Teletext::set_position(const Vector &p, const Vector &high)
{
  position = Vector(256.0f / high.x * p.x,
                    256.0f / high.y * p.y);
}

void Teletext::render(bool absoluteCoords) {
  
  using namespace std;
  
  font->bind();
	
  float fontW = realWidth / float(font->get_width() );
  float fontH = realHeight / float(font->get_height() );
	
  // 30 kirjainta per ruutu
  // Jotenkin järkevämmin sit ku saa jotenkin hienosti haettua nykysen
  // viewportin koon.
  const float w = 256.0f / 40;
  const float h = 256.0f / 25;

  glPushMatrix();

  if(absoluteCoords) {
	glMatrixMode( GL_PROJECTION );
        glPushMatrix();
	glLoadIdentity();

	gluOrtho2D( 0, 256, 0, 256 );
	glMatrixMode( GL_MODELVIEW );
	glLoadIdentity(); 
	
  }

  glTranslatef(position.x, position.y, 0);
  glScalef(scale_x, scale_y, 1.0f);

  stringstream charConv;

  string::const_iterator iter;
  float xpos = 0.0f;
  for(iter=text.begin();iter<text.end();iter++) {

    if (*iter == '\n') {  // Rivinvaihto
      glTranslatef(-xpos, -h, 0.0f);
      xpos = 0.0f;
      continue;
    }

    unsigned char u = (unsigned char)*iter;
    if (u >= 128) {  // Kyseessä on ääkkönen
      if (u == 0xc3) // UTF8
        switch ((unsigned char)*++iter) {
	case 0xa5: charConv << "ruattalaanenoo"; break;
	case 0xa4: charConv << "ae";             break;
	case 0xb6: charConv << "oe";             break;
	case 0x85: charConv << "RUATTALAANENOO"; break;
	case 0x84: charConv << "AE";             break;
	case 0x96: charConv << "OE";             break;
	default: charConv << "?";/*assert(!"Kummallinen UTF8-merkki!");*/ break;
        }
      else  // Ei UTF-8 joten oletetaan ISO-8859-1:ksi
        switch (u) {
	case 0xe5: charConv << "ruattalaanenoo"; break;
	case 0xe4: charConv << "ae";             break;
	case 0xf6: charConv << "oe";             break;
	case 0xc5: charConv << "RUATTALAANENOO"; break;
	case 0xc4: charConv << "AE";             break;
	case 0xd6: charConv << "OE";             break;
	default: charConv << "?"; /*assert(!"Kummallinen merkki joka ei oo edes UTF-8!");*/ break;
        }
    } else if (20 <= u && u <= 30)
      switch (u) {
      case 20: charConv << "ylaloota"     ; break;
      case 21: charConv << "alaloota"     ; break;
      case 22: charConv << "vasenloota"   ; break;
      case 23: charConv << "oikealoota"   ; break;
      case 24: charConv << "loota"        ; break;
      case 25: charConv << "rasteriloota" ; break;
      case 26: charConv << "shakkiloota1" ; break;
      case 27: charConv << "vasenalaloota"; break;
      case 28: charConv << "vasenylaloota"; break;
      case 29: charConv << "oikeaylaloota"; break;
      case 30: charConv << "oikeaalaloota"; break;
      }
    else
      charConv << *iter;

    if(characters.find( charConv.str() ) == characters.end()) 
      continue;

    const float x_offset = characters[charConv.str()] % letter_cols;
    const float y_offset = characters[charConv.str()] / letter_cols;

    charConv.str("");
    charConv.clear();



    glDisable(GL_TEXTURE_2D);
    
    
    if(bgColors.find(iter - text.begin()) != colorTable.end() ){
      colorData cData = bgColors[iter - text.begin()];
      glColor4f(cData.r, cData.g, cData.b, cData.a);

    }
    
    glBegin(GL_QUADS);
    glVertex2f(0.0f, 0.0f);
    glVertex2f(w, 0.0f);
    glVertex2f(w, h);
    glVertex2f(0.0f, h);
    glEnd();

    glEnable(GL_TEXTURE_2D);
    
    if(colorTable.find(iter - text.begin()) != colorTable.end() ){
      colorData cData = colorTable[iter - text.begin()];
      glColor4f(cData.r, cData.g, cData.b, cData.a);

    }

    glBegin(GL_QUADS);
    
    glTexCoord2f(fontW/letter_cols*x_offset, fontH/letter_rows*(y_offset+1));
    glVertex2f(0.0f, 0.0f);
    glTexCoord2f(fontW/letter_cols*(x_offset+1), fontH/letter_rows*(y_offset+1));
    glVertex2f(w, 0.0f);
    glTexCoord2f(fontW/letter_cols*(x_offset+1), fontH/letter_rows*y_offset);
    glVertex2f(w, h);
    glTexCoord2f(fontW/letter_cols*x_offset, fontH/letter_rows*y_offset);
    glVertex2f(0.0f, h);
    glEnd();

    
    glTranslatef(w, 0, 0);
    xpos += w;
    
  }

  if(absoluteCoords) {
	glMatrixMode( GL_PROJECTION );
        glPopMatrix();
        glMatrixMode( GL_MODELVIEW );
  }

  glPopMatrix();
}

void Teletext::set_scale(float x, float y)
{
  scale_x = x;
  scale_y = y;
}
void Teletext::set_bgcolor(float red, float green, float blue, float alpha)
{
  bR = red; bG = green; bB = blue; bA = alpha;
}

void Teletext::set_color(float red, float green, float blue, float alpha)
{
  r = red; g = green; b = blue; a = alpha;
}

void Teletext::set_colors(const float *fore, const float *back)
{
  set_color(  fore[0], fore[1], fore[2], fore[3]);
  set_bgcolor(back[0], back[1], back[2], back[3]);
}

void Teletext::set_color(unsigned char red, unsigned char green, unsigned char blue, unsigned char alpha)
{
  set_color(float(red)   / 255.0f,
            float(green) / 255.0f,
            float(blue)  / 255.0f,
            float(alpha) / 255.0f);
}
