/************************************************************************
    MeOS - Orienteering Software
    Copyright (C) 2009-2011 Melin Software HB
    
    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/>.

    Melin Software HB - software@melin.nu - www.melin.nu
    Stigbergsvägen 7, SE-75242 UPPSALA, Sweden
    
************************************************************************/

#include "stdafx.h"
#include "localizer.h"
#include <fstream>
#include <vector>
#include "meos_util.h"

Localizer::Localizer(void)
{
  impl = new LocalizerImpl();
  owning = true;
  user = 0;
}

Localizer::~Localizer(void)
{
  if (user) {
    user->owning = true;
    impl = 0;
  }
  else
    delete impl;
}

void Localizer::set(Localizer &li) {
  if (li.user || user)
    throw std::exception("Runtime error");

  if (owning)
    delete impl;

  impl = li.impl;
  li.user = this;  
}


LocalizerImpl::LocalizerImpl(void)
{
}

LocalizerImpl::~LocalizerImpl(void)
{
}

const string &LocalizerImpl::translate(const string &str) 
{
  static int i = 0;
  const int bsize = 17;
  static string value[bsize];
  int len = str.length();

  if(len==0)
    return str;

  if (str[0]=='#') {
    i = (i + 1)%bsize;
    value[i] = str.substr(1); 
    return value[i];
  }

  if (str[0]==',' || str[0]==' ' || str[0]=='.'  || str[0]==':'  || str[0]==';') {
    unsigned k=1;
    while(str[k] && (str[k]==' ' || str[k]=='.' || str[k]==':'))
      k++;
    
    if (k<str.length()) {
      string sub = str.substr(k);
      i = (i + 1)%bsize;
      value[i] = str.substr(0, k) + translate(sub);
      return value[i];
    }
  }

  map<string, string>::const_iterator it = table.find(str);
  if (it != table.end())
    return it->second;

  int subst = str.find_first_of('#');
  if (subst != str.npos) {
    string s = translate(str.substr(0, subst));
    vector<string> split_vec;
    split(str.substr(subst+1), "#", split_vec);
    split_vec.push_back("");
    const char *subsymb = "XYZW";
    size_t subpos = 0;
    string ret;
    size_t lastpos = 0;
    for (size_t k = 0; k<s.size(); k++) {
      if (subpos>=split_vec.size() || subpos>=4)
        break;
      if (s[k] == subsymb[subpos]) {
        if (k>0 && isalnum(s[k-1]))
          continue;
        if (k+1 < s.size() && isalnum(s[k+1]))
          continue;
        ret += s.substr(lastpos, k-lastpos);
        ret += split_vec[subpos];
        lastpos = k+1;
        subpos++;
      }
    }
    if (lastpos<s.size())
      ret += s.substr(lastpos);

    i = (i + 1)%bsize;
    swap(value[i], ret);
    return value[i];
  }


  char last = str[len-1];
  if (last != ':' && last!='.' && last!=' ' && last != ',' && last != ';') {
#ifdef _DEBUG
    if (str.length()>2)
      unknown.insert(str);
#endif
    return str;
  }

  string suffix;
  int pos = str.find_last_not_of(last);

  while(pos>0) {
    char last = str[pos];
    if (last != ':' && last != ' ' && last != ',' && last != '.' && last != ';')
      break;
  
    pos = str.find_last_not_of(last, pos);
  }

  suffix = str.substr(pos+1);

  string key = str.substr(0, str.length()-suffix.length());
  it = table.find(key);
  if (it != table.end()) {
    i = (i + 1)%bsize;
    value[i] = it->second + suffix; 
    return value[i];
  }
#ifdef _DEBUG
  unknown.insert(key);
#endif

  return str;
}
const string newline = "\n";

void LocalizerImpl::saveUnknown(const string &file) 
{
  if (!unknown.empty()) {
    ofstream fout(file.c_str(), ios::trunc|ios::out);
    for (set<string>::iterator it = unknown.begin(); it!=unknown.end(); ++it) {
      string value = *it;
      string key = *it;
      int nl = value.find(newline);
      int n2 = value.find(".");

      if (nl!=string::npos || n2!=string::npos) {
        while (nl!=string::npos) {
          value.replace(nl, newline.length(), "\\n");
          nl = value.find(newline);
        }
        key = "help:" + itos(value.length()) + itos(value.find_first_of("."));
      }

      fout << key << " = " << value << endl;
    }
  }
}

void LocalizerImpl::saveTable(const string &file) 
{
  ofstream fout((language+"_"+file).c_str(), ios::trunc|ios::out);
  for (map<string, string>::iterator it = table.begin(); it!=table.end(); ++it) {
    string value = it->second;
    int nl = value.find(newline);
    while (nl!=string::npos) {
      value.replace(nl, newline.length(), "\\n");
      nl = value.find(newline);
    }
    fout << it->first << " = " << value << endl;
  }
}

void LocalizerImpl::loadTable(int id, const string &language) 
{
  string sname = "#"+itos(id);
  const char *name = sname.c_str();
  HRSRC hResInfo = FindResource(0, name, "#300");
  HGLOBAL hGlobal = LoadResource(0, hResInfo);

  if (hGlobal==0)
    return;

  int size = SizeofResource(0, hResInfo);

  const char *lang_src = (char *)LockResource(hGlobal);
  char *lang = new char[size];
  memcpy(lang, lang_src, size);
  char *bf;
  vector<string> raw;
  int pos = 0;
  while (pos < size) {
    bf = &lang[pos];
    while(pos<size && lang[pos] != '\n' && lang[pos] != '\r')
      pos++;
  
    if (lang[pos]=='\n' || lang[pos]=='\r') {
      lang[pos] = 0;
      if (strlen(bf)>0 && bf[0] != '#')
        raw.push_back(bf);
      pos++;
      if (pos<size && (lang[pos]=='\n' || lang[pos]=='\r'))
        pos++;
    }
  }

  delete[] lang;
  loadTable(raw, language);  
}

void LocalizerImpl::loadTable(const string &file, const string &language) 
{
  clear();
  ifstream fin(file.c_str(), ios::in);
  
  if (!fin.good())
    return;

  int line=0;
  char bf[1024];
  while (!fin.eof()) {
    line++;
    fin.getline(bf, 1024);
  }

  fin.seekg(0);
  fin.clear();
  fin.seekg(0);

  vector<string> raw;
  raw.reserve(line);
  while (!fin.eof()) {
    bf[0] = 0;
    fin.getline(bf, 1024);
    if (bf[0]!=0 && bf[0]!='#')
      raw.push_back(bf);
  }
  
  loadTable(raw, language);
}


void LocalizerImpl::loadTable(const vector<string> &raw, const string &language) 
{ 
  table.clear();
  this->language = language;
  for (size_t k=0;k<raw.size();k++) {
    const string &s = raw[k];
    int pos = s.find_first_of('=');

    if (pos==string::npos)
      throw std::exception("Bad file format.");
    int spos = pos;
    int epos = pos+1;
    while (spos>0 && s[spos-1]==' ')
      spos--;

    while (unsigned(epos)<s.size() && s[epos]==' ')
      epos++;

    string key = s.substr(0, spos);
    string value = s.substr(epos);

    int nl = value.find("\\n");
    while (nl!=string::npos) {
      value.replace(nl, 2, newline);
      nl = value.find("\\n");
    }

    table[key] = value;
  }
}

void LocalizerImpl::clear() 
{
  table.clear();
  unknown.clear();
  language.clear();
}
