// -*- mode:c++; tab-width:4; c-basic-offset:4; indent-tabs-mode:nil -*-
/* Unikey Vietnamese Input Method
 * Copyright (C) 2000-2005 Pham Kim Long
 * Contact:
 *   unikey@gmail.com
 *   UniKey project: http://unikey.org
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor
 * Boston, MA 02110-1301, USA.
 */

#include <iostream>
#include "inputproc.h"

using namespace std;

/*
unsigned char WordBreakSyms[] = {
	',', ';', ':', '.', '\"', '\'', '!', '?', ' ',
	'<', '>', '=', '+', '-', '*', '/', '\\',
	'_', '~', '`', '@', '#', '$', '%', '^', '&', '(', ')', '{', '}', '[', ']'};
*/

unsigned char WordBreakSyms[] = {
	',', ';', ':', '.', '\"', '\'', '!', '?', ' ',
	'<', '>', '=', '+', '-', '*', '/', '\\',
	'_', '@', '#', '$', '%', '&', '(', ')', '{', '}', '[', ']', '|'}; //we excluded ~, `, ^

VnLexiName AZLexiUpper[] = 
  {vnl_A, vnl_B, vnl_C, vnl_D, vnl_E, vnl_F, vnl_G, vnl_H, vnl_I, vnl_J,
   vnl_K, vnl_L, vnl_M, vnl_N, vnl_O, vnl_P, vnl_Q, vnl_R, vnl_S, vnl_T,
   vnl_U, vnl_V, vnl_W, vnl_X, vnl_Y, vnl_Z};

VnLexiName AZLexiLower[] =
  {vnl_a, vnl_b, vnl_c, vnl_d, vnl_e, vnl_f, vnl_g, vnl_h, vnl_i, vnl_j,
   vnl_k, vnl_l, vnl_m, vnl_n, vnl_o, vnl_p, vnl_q, vnl_r, vnl_s, vnl_t,
   vnl_u, vnl_v, vnl_w, vnl_x, vnl_y, vnl_z};

UkCharType UkcMap[256];

struct _ascVnLexi {
    int asc;
    VnLexiName lexi;
};

//List of western characters outside range A-Z that are
//also Vietnamese characters
_ascVnLexi AscVnLexiList[] = {
    {0xC0, vnl_A2},
    {0xC1, vnl_A1},
    {0xC2, vnl_Ar},
    {0xC2, vnl_A4},
    {0xC8, vnl_E2},
    {0xC9, vnl_E1},
    {0xCA, vnl_Er},
    {0xCC, vnl_I2},
    {0xCD, vnl_I1},
    {0xD2, vnl_O2},
    {0xD3, vnl_O1},
    {0xD4, vnl_Or},
    {0xD5, vnl_O4},
    {0xD9, vnl_U2},
    {0xDA, vnl_U1},
    {0xDD, vnl_Y1},
    {0xE0, vnl_a2},
    {0xE1, vnl_a1},
    {0xE2, vnl_ar},
    {0xE3, vnl_a4},
    {0xE8, vnl_e2},
    {0xE9, vnl_e1},
    {0xEA, vnl_er},
    {0xEC, vnl_i2},
    {0xED, vnl_i1},
    {0xF2, vnl_o2},
    {0xF3, vnl_o1},
    {0xF4, vnl_or},
    {0xF5, vnl_o4},
    {0xF9, vnl_u2},
    {0xFA, vnl_u1},
    {0xFD, vnl_y1},
    {0x00, vnl_nonVnChar}
};

VnLexiName IsoVnLexiMap[256];

bool ClassifierTableInitialized = false;

DllExport UkKeyMapping TelexMethodMapping[] = {
    {'Z', vneTone0},
    {'S', vneTone1},
    {'F', vneTone2},
    {'R', vneTone3},
    {'X', vneTone4},
    {'J', vneTone5},
    {'W', vne_telex_w},
    {'A', vneRoof_a},
    {'E', vneRoof_e},
    {'O', vneRoof_o},
    {'D', vneDd},
    {'[', vneCount + vnl_oh},
    {']', vneCount + vnl_uh},
    {'{', vneCount + vnl_Oh},
    {'}', vneCount + vnl_Uh},
    {0, vneNormal}
};

DllExport UkKeyMapping SimpleTelexMethodMapping[] = {
    {'Z', vneTone0},
    {'S', vneTone1},
    {'F', vneTone2},
    {'R', vneTone3},
    {'X', vneTone4},
    {'J', vneTone5},
    {'W', vneHookAll},
    {'A', vneRoof_a},
    {'E', vneRoof_e},
    {'O', vneRoof_o},
    {'D', vneDd},
    {0, vneNormal}
};

DllExport UkKeyMapping SimpleTelex2MethodMapping[] = {
    {'Z', vneTone0},
    {'S', vneTone1},
    {'F', vneTone2},
    {'R', vneTone3},
    {'X', vneTone4},
    {'J', vneTone5},
    {'W', vne_telex_w},
    {'A', vneRoof_a},
    {'E', vneRoof_e},
    {'O', vneRoof_o},
    {'D', vneDd},
    {0, vneNormal}
};

DllExport UkKeyMapping VniMethodMapping[] = {
    {'0', vneTone0},
    {'1', vneTone1},
    {'2', vneTone2},
    {'3', vneTone3},
    {'4', vneTone4},
    {'5', vneTone5},
    {'6', vneRoofAll},
    {'7', vneHook_uo},
    {'8', vneBowl},
    {'9', vneDd},
    {0, vneNormal}
};

DllExport UkKeyMapping VIQRMethodMapping[] = {
    {'0', vneTone0},
    {'\'', vneTone1},
    {'`', vneTone2},
    {'?', vneTone3},
    {'~', vneTone4},
    {'.', vneTone5},
    {'^', vneRoofAll},
    {'+', vneHook_uo},
    {'*', vneHook_uo},
    {'(', vneBowl},
    {'D', vneDd},
    {'\\', vneEscChar},
    {0, vneNormal}
};

DllExport UkKeyMapping MsViMethodMapping[] = {
    {'5', vneTone2},
    {'%', vneTone2},
    {'6', vneTone3},
    {'^', vneTone3},
    {'7', vneTone4},
    {'&', vneTone4},
    {'8', vneTone1},
    {'*', vneTone1},
    {'9', vneTone5},
    {'(', vneTone5},
    {'1', vneCount + vnl_ab},
    {'!', vneCount + vnl_Ab},
    {'2', vneCount + vnl_ar},
    {'@', vneCount + vnl_Ar},
    {'3', vneCount + vnl_er},
    {'#', vneCount + vnl_Er},
    {'4', vneCount + vnl_or},
    {'$', vneCount + vnl_Or},
    {'0', vneCount + vnl_dd},
    {')', vneCount + vnl_DD},
    {'[', vneCount + vnl_uh},
    {']', vneCount + vnl_oh},
    {'{', vneCount + vnl_Uh},
    {'}', vneCount + vnl_Oh},
    {0, vneNormal}
};

//-------------------------------------------
void SetupInputClassifierTable()
{
  unsigned int c;
  int i;

  for (c=0; c<=32; c++) {
    UkcMap[c] = ukcReset;
  }

  for (c=33; c<256; c++) {
    UkcMap[c] = ukcNonVn;
  }

  /*
  for (c = '0'; c <= '9'; c++)
    UkcMap[c] = ukcNonVn;
  */

  for (c = 'a'; c <= 'z'; c++)
    UkcMap[c] = ukcVn;
  for (c = 'A'; c <= 'Z'; c++)
    UkcMap[c] = ukcVn;

  for (i=0; AscVnLexiList[i].asc; i++) {
      UkcMap[AscVnLexiList[i].asc] = ukcVn;
  }

  UkcMap[(unsigned char)'j'] = ukcNonVn;
  UkcMap[(unsigned char)'J'] = ukcNonVn;
  UkcMap[(unsigned char)'f'] = ukcNonVn;
  UkcMap[(unsigned char)'F'] = ukcNonVn;
  UkcMap[(unsigned char)'w'] = ukcNonVn;
  UkcMap[(unsigned char)'W'] = ukcNonVn;

  int count = sizeof(WordBreakSyms)/sizeof(unsigned char);
  for (i = 0; i < count; i++)
    UkcMap[WordBreakSyms[i]] = ukcWordBreak;

  //Calculate IsoVnLexiMap
  for (i = 0; i < 256; i++) {
      IsoVnLexiMap[i] = vnl_nonVnChar;
  }

  for (i = 0; AscVnLexiList[i].asc; i++) {
      IsoVnLexiMap[AscVnLexiList[i].asc] = AscVnLexiList[i].lexi;
  }

  for (c = 'a'; c <= 'z'; c++) {
      IsoVnLexiMap[c] = AZLexiLower[c - 'a'];
  }

  for (c = 'A'; c <= 'Z'; c++) {
      IsoVnLexiMap[c] = AZLexiUpper[c - 'A'];
  }
}

//-------------------------------------------
void UkInputProcessor::init()
{
  if (!ClassifierTableInitialized) {
    SetupInputClassifierTable();
    ClassifierTableInitialized = true;
  }
  setIM(UkTelex);
}

//-------------------------------------------
int UkInputProcessor::setIM(UkInputMethod im)
{
    m_im = im;
    switch (im) {
        case UkTelex:
            useBuiltIn(TelexMethodMapping);
            break;
        case UkSimpleTelex:
            useBuiltIn(SimpleTelexMethodMapping);
            break;
        case UkSimpleTelex2:
            useBuiltIn(SimpleTelex2MethodMapping);
            break;
        case UkVni:
            useBuiltIn(VniMethodMapping);
            break;
        case UkViqr:
            useBuiltIn(VIQRMethodMapping);
            break;
        case UkMsVi:
            useBuiltIn(MsViMethodMapping);
            break;
        default:
            m_im = UkTelex;
            useBuiltIn(TelexMethodMapping);
    }
    return 1;
}

//-------------------------------------------
int UkInputProcessor::setIM(int map[256])
{
  int i;
  m_im = UkUsrIM;
  for (i=0; i<256; i++)
    m_keyMap[i] = map[i];
  return 1;
}
  

//-------------------------------------------
void UkResetKeyMap(int keyMap[256])
{
  unsigned int c;
  for (c=0; c<256; c++)
    keyMap[c] = vneNormal;
}

//-------------------------------------------
void UkInputProcessor::useBuiltIn(UkKeyMapping *map)
{
    UkResetKeyMap(m_keyMap);
    for (int i=0; map[i].key; i++) {
        m_keyMap[map[i].key] = map[i].action;
        if (map[i].action < vneCount) {
            if (islower(map[i].key)) {
                m_keyMap[toupper(map[i].key)] = map[i].action;
            }
            else if (isupper(map[i].key)) {
                m_keyMap[tolower(map[i].key)] = map[i].action;
            }
        }
    }
}

//-------------------------------------------
void UkInputProcessor::keyCodeToEvent(unsigned int keyCode, UkKeyEvent & ev)
{
    ev.keyCode = keyCode;
    if (keyCode > 255) {
        ev.evType = vneNormal;
        ev.vnSym = IsoToVnLexi(keyCode);
        ev.chType = (ev.vnSym == vnl_nonVnChar)? ukcNonVn : ukcVn;
    }
    else {
        ev.chType = UkcMap[keyCode];
        ev.evType = m_keyMap[keyCode];

        if (ev.evType >= vneTone0 && ev.evType <= vneTone5) {
            ev.tone = ev.evType - vneTone0;
        }

        if (ev.evType >= vneCount) {
            ev.chType = ukcVn;
            ev.vnSym = (VnLexiName)(ev.evType - vneCount);
            ev.evType = vneMapChar;
        }
        else {
            ev.vnSym = IsoToVnLexi(keyCode);
        }
    }
}

//----------------------------------------------------------------
// This method translates a key stroke to a symbol.
// Key strokes are simply considered character input, not action keys as in
// keyCodeToEvent method
//----------------------------------------------------------------
void UkInputProcessor::keyCodeToSymbol(unsigned int keyCode, UkKeyEvent & ev)
{
    ev.keyCode = keyCode;
    ev.evType = vneNormal;
    ev.vnSym = IsoToVnLexi(keyCode);
    if (keyCode > 255) {
        ev.chType = (ev.vnSym == vnl_nonVnChar)? ukcNonVn : ukcVn;
    }
    else {
        ev.chType = UkcMap[keyCode];
    }
}

//-------------------------------------------
UkCharType UkInputProcessor::getCharType(unsigned int keyCode)
{
  if (keyCode > 255)
    return (IsoToVnLexi(keyCode) == vnl_nonVnChar) ? ukcNonVn : ukcVn;
  return UkcMap[keyCode];
}

//-------------------------------------------
void UkInputProcessor::getKeyMap(int map[256])
{
  int i;
  for (i=0; i<256; i++)
    map[i] = m_keyMap[i];
}

