#include "dicthiragana.h"
#include "inputmode.h"
#include "config.h"
#include <qapplication.h>
#include <qdir.h>
#include <qfile.h>
#include <qmessagebox.h>
#include <qtextstream.h>
#include <qregexp.h>


DictHiragana::DictHiragana() : 
  _dicthira(QDict<QString>(17, FALSE)),
  _dictkata(QDict<QString>(17, FALSE)),
  _dictalphbt(QDict<QString>()),
  _dictsymbol(QDict<QString>()),
  _dictkanainp(QDict<QString>(17, FALSE)),
  _dictdakuten(QDict<QString>())
{
  _dicthira.setAutoDelete(TRUE);
  _dictkata.setAutoDelete(TRUE);
  _dictalphbt.setAutoDelete(TRUE);
  _dictsymbol.setAutoDelete(TRUE);
  _dictkanainp.setAutoDelete(TRUE);
  _dictdakuten.setAutoDelete(TRUE);
}


DictHiragana::~DictHiragana() { }


void
DictHiragana::init()
{
  _dicthira.clear();
  _dictkata.clear();
  _dictalphbt.clear();
  _dictsymbol.clear();
  _dictkanainp.clear();
  _dictdakuten.clear();

  writeDictHira();
  writeDictKata();
  writeDictAlphbt();
  writeDictSymbol();
  writeDictKanaInp();
  writeDictDakuten();

  QString dictdir = QString(getenv("HOME")) + "/.kimera/dic/";
  initDict(_dicthira, dictdir + "hiragana.dic");          // ひらがな辞書初期化
  initDict(_dictkata, dictdir + "katakana.dic");          // カタカナ辞書初期化
  initDict(_dictalphbt, dictdir + "zenkakualphabet.dic"); // 全角英字辞書初期化
  initDict(_dictsymbol, dictdir + "numeralsymbols.dic");  // 全角数字記号辞書初期化
  initDict(_dictkanainp, dictdir + "kanainput.dic");      // かな入力辞書初期化
  initDict(_dictdakuten, dictdir + "dakuten.dic");        // かな入力濁点辞書初期化

  // 句読点・記号・括弧
  _dictsymbol.insert(",", new QString(Config::readEntry("_cmbtouten", ","))); 
  _dictsymbol.insert(".", new QString(Config::readEntry("_cmbkuten", ".")));
  _dictsymbol.insert("/", new QString(Config::readEntry("_cmbsymbol", "/")));
  _dictsymbol.insert("[", new QString(Config::readEntry("_cmbbracket", "[").left(1)));
  _dictsymbol.insert("]", new QString(Config::readEntry("_cmbbracket", "]").right(1)));
}


void
DictHiragana::initDict(QDict<QString>& dict, const QString& filename)
{
  if ( !dict.isEmpty() ) return;
  
  QFile file(filename);
  
  if ( !file.open(IO_ReadOnly) ) {
    QMessageBox::critical(0, "File open error", "Cannot open file: " + filename,
    			  QMessageBox::Ok | QMessageBox::Default, 0);
    qApp->quit();
    return;
  }
    
  QTextStream  stream(&file);
  stream.setEncoding(QTextStream::Latin1);

  while ( !stream.eof() ) {

    QString str;
    str = QString::fromLocal8Bit(stream.readLine());
    
    if ( !str.isEmpty() && !str.contains(QRegExp("^[ \t]")) && 
	 !str.contains(QRegExp("^##")) ) {
      QString keystr, itemstr;
      int idx = str.find(QRegExp("[ \t]"));
      if (idx >= 0) {
	keystr = str.left(idx);
	
	str.remove(0, keystr.length());
	itemstr = str.replace(QRegExp("[ \t]"), "");
	
	dict.insert(keystr, new QString(itemstr));
      }
    }
  }
  
  file.close();
  return;
}


// 平仮名へ変換する (濁点を前の文字に合わせて１文字にする 例:か゛-> が )
// parameter:    Roma string (only ASCII characters) or Hiragana string
// return value: Hiragana string
QString 
DictHiragana::convertToHira(const QString& src)
{
  // check parameter
  if (src.isEmpty()) {
    return src;

  } else if (src.local8Bit().length() != src.length()) {
    // 濁点変換
    Q_ASSERT(!_dictdakuten.isEmpty());
    
    if (src.length() == 1) return src;

    QString dest;
    int i = 0;
    while(i < src.length()) {
      QString* pstr;
      pstr = _dictdakuten.find( src.mid(i, 2) );
      
      if ( pstr ) {
	dest += *pstr;
	i++;
	
      } else {
	dest += src.mid(i, 1);
      }
      i++;
    }
    
    return dest;
  }
  
  Q_ASSERT(!_dicthira.isEmpty());
  Q_ASSERT(!_dictsymbol.isEmpty());
  
  QString str_roma(src);    // 一時作業領域
  QString dest;
  
  while ( !str_roma.isEmpty() ) {   
    uint i;
    i = (4 > str_roma.length()) ? str_roma.length() : 4;
    
    QString*  pstr;
    while (1) {
      // ひらがな検索
      pstr = _dicthira.find(str_roma.left(i));
      if (pstr) {
	dest += *pstr;
	break;
      }

      // 全角数字記号検索
      pstr = _dictsymbol.find(str_roma.left(i));
      if (pstr) {
	dest += *pstr;
	break;
      }

      if (i == 1) {
	dest += str_roma.left(i);
	break;
      }

      i--;
    }
    
    QRegExp rxnn("nn", FALSE);
    if (i == 2 && dest.right(1) == QString::fromLocal8Bit("ん") 
	&& !rxnn.exactMatch(str_roma.left(i))) {
      // 'nm'などを 'ん'に変換したときの処理
      str_roma.remove(0, 1);     // 前の１文字削除
    } else if (i == 2 && str_roma[0] == str_roma[1] 
	       && !rxnn.exactMatch(str_roma.left(i))) { 
      // 'tt'などを 'っ'に変換した時の文字列の処理     
      str_roma.remove(0, 1);     // 前の１文字削除
    } else {
      str_roma.remove(0, i);    // 変換した分を削除
    }
  }
  
  return dest;
}


// convertToHira を呼び出した後，最後の文字が'n'だったら
// 'ん' に変換
QString 
DictHiragana::forceConvtToHira(const QString& src)
{
  if (src.isEmpty()) return src;

  QString dest = convertToHira(src);
  QRegExp rxn("n", FALSE);
  if ( rxn.exactMatch(dest.right(1))) {
    dest = dest.replace(dest.length() - 1, 1, QString::fromLocal8Bit("ん")); 
  }
  
  return dest;
}


// parameter: Roma string (only ASCII characters) or Hiragana string
QString 
DictHiragana::convertToKata(const QString& src)
{
  Q_ASSERT(!_dictkata.isEmpty());

  QString dest;
  QString srchira;
  // check parameter
  if (src.local8Bit().length() == src.length()) {
    srchira = convertToHira(src);
  } else {
    srchira = src;
  }

  for (int i = 0; i < srchira.length(); i++) {
    QString* pstr;
    pstr = _dictkata.find( srchira.mid(i, 1) );
    if ( pstr ) {
      dest += *pstr;
    } else {
      dest += srchira.mid(i, 1);
    }
  }

  return  dest;
}


// parameter: Roma string (only ASCII characters) or Hiragana string
QString 
DictHiragana::forceConvtToKata(const QString& src)
{
  return convertToKata(forceConvtToHira(src));
}


// parameter: Roma string (only ASCII characters)
QString
DictHiragana::convertToZenkakuEisu(const QString& src)
{  
  Q_ASSERT(!_dictalphbt.isEmpty());
  Q_ASSERT(!_dictsymbol.isEmpty());

  QString dest;
  for (int i = 0; i < src.length(); i++) {
    QString* pstr;
    if ( pstr = _dictalphbt.find(src.mid(i, 1)) ) {  // if the key exists 
      dest += *pstr;
      
    } else if ( pstr = _dictsymbol.find(src.mid(i, 1)) ) {  // if the key exists 
      dest += *pstr;

    } else {
      dest += src.mid(i, 1);
    }
  }
  
  return dest;
}


QString 
DictHiragana::convertYomi(const QString& src, const InputMode& mode)
{
  switch (mode.id() & InputMode::ModeMask) {
  case InputMode::Hiragana:
    return convertToHira(src);
    break;
    
  case InputMode::Katakana:
    return convertToKata(src);
    break;
    
  case InputMode::ZenkakuEisu:
    if (src.local8Bit().length() != src.length()) {
      Q_ASSERT(0);
      break;
    }
    return convertToZenkakuEisu(src);
    break;
    
  default:
    Q_ASSERT(0);
    break;
  }

  return QString();
}


QString
DictHiragana::forceConvtYomi(const QString& src, const InputMode& mode)
{
  switch (mode.id() & InputMode::ModeMask) {
  case InputMode::Hiragana:
    return forceConvtToHira(src);
    break;
    
  case InputMode::Katakana:
    return forceConvtToKata(src);
    break;
    
  case InputMode::ZenkakuEisu:
    if (src.local8Bit().length() != src.length()) {
      Q_ASSERT(0);
      break;
    }
    return convertToZenkakuEisu(src);
    break;
    
  default:
    Q_ASSERT(0);
    break;
  }

  return QString();
}


//  かな入力変換
//  params: QKeyEvent
//  params: Input mode
//  return: Hiragana string
QString 
DictHiragana::convertYomi(const QKeyEvent& key, const InputMode& mode)
{
  if ( !(mode.id() & InputMode::KanaInput) ) {
    return QString();

  } else if (mode.id() & InputMode::ZenkakuEisu) {
    return convertToZenkakuEisu(key.text());
  }

  Q_ASSERT(!_dictkanainp.isEmpty());
  QString keystr;
  if (key.state() == Qt::NoButton) {
    keystr = key.text();
    
  } else if (key.state() == Qt::ShiftButton) { 
    keystr = QString("Shift+") + key.text();
    
  } else if (key.state() == Qt::Keypad) {
    keystr = QString("Keypad+") + key.text();
    
  } else {
    return QString();
  }
  
  QString* pres = _dictkanainp[keystr];
  if ( !pres ) return QString();

  switch (mode.id() & InputMode::ModeMask) {
  case InputMode::Hiragana:
    return *pres;
    break;
    
  case InputMode::Katakana:
    return convertToKata(*pres);
    break;
    
  default:
    Q_ASSERT(0);
    break;
  }

  return QString();
}


void
DictHiragana::writeDictHira() const
{
  QString s = QObject::tr("## ローマ字 ひらがな変換辞書

a	  あ
i         い
u         う
e         え
o         お

ka        か
ki        き
ku        く
ke        け
ko        こ

sa        さ
si        し
su        す
se        せ
so        そ

ta        た
ti        ち
tu        つ
te        て
to        と

na        な
ni        に
nu        ぬ
ne        ね
no        の

ha        は
hi        ひ
hu        ふ
he        へ
ho        ほ

ma        ま
mi        み
mu        む
me        め
mo        も

ya        や
yi        い
yu        ゆ
ye 	  いぇ
yo        よ

ra        ら
ri        り
ru        る
re        れ
ro        ろ

wa        わ
wi        ゐ
wu        う
we        うぇ
wo        を

ga        が
gi        ぎ
gu        ぐ
ge        げ
go        ご

za        ざ
zi        じ
zu        ず
ze        ぜ
zo        ぞ

da        だ
di        ぢ
du        づ
de        で
do        ど

ba        ば
bi        び
bu        ぶ
be        べ
bo        ぼ

pa        ぱ
pi        ぴ
pu        ぷ
pe        ぺ
po        ぽ

fa        ふぁ
fi        ふぃ
fu        ふ
fe        ふぇ
fo        ふぉ

ja        じゃ
ji        じ
ju        じゅ
je        じぇ
jo        じょ

ca	  か
cu        く
co        こ

la        ら
li        り
lu        る
le        れ
lo        ろ

va	  う゛ぁ
vi	  う゛ぃ
vu	  う゛
ve	  う゛ぇ
vo	  う゛ぉ

kya       きゃ
kyi       きぃ
kyu       きゅ
kye       きぇ
kyo       きょ

gya       ぎゃ
gyi       ぎぃ
gyu       ぎゅ
gye       ぎぇ
gyo       ぎょ

sya     しゃ
syi     しぃ
syu     しゅ
sye     しぇ
syo     しょ

zya     じゃ
zyi     じぃ
zyu     じゅ
zye     じぇ
zyo     じょ

jya     じゃ
jyi     じぃ
jyu     じゅ
jye     じぇ
jyo     じょ

tya     ちゃ
tyi     ちぃ
tyu     ちゅ
tye     ちぇ
tyo     ちょ

cya     ちゃ
cyi     ちぃ
cyu     ちゅ
cye     ちぇ
cyo     ちょ

dya     ぢゃ
dyi     ぢぃ
dyu     ぢゅ
dye     ぢぇ
dyo     ぢょ

nya     にゃ
nyi     にぃ
nyu     にゅ
nye     にぇ
nyo     にょ

hya     ひゃ
hyi     ひぃ
hyu     ひゅ
hye     ひぇ
hyo     ひょ

bya     びゃ
byi     びぃ
byu     びゅ
bye     びぇ
byo     びょ

pya     ぴゃ
pyi     ぴぃ
pyu     ぴゅ
pye     ぴぇ
pyo     ぴょ

mya     みゃ
myi     みぃ
myu     みゅ
mye     みぇ
myo     みょ

rya     りゃ
ryi     りぃ
ryu     りゅ
rye     りぇ
ryo     りょ

tsa     つぁ 
tsi     つぃ
tsu     つ
tse     つぇ
tso     つぉ

lya     りゃ
lyi     りぃ
lyu     りゅ
lye     りぇ
lyo     りょ

sha     しゃ
shi       し
shu     しゅ
she     しぇ
sho     しょ

tha     てゃ
thi     てぃ
thu     てゅ
the     てぇ
tho     てょ

dha     でゃ
dhi     でぃ
dhu     でゅ
dhe     でぇ
dho     でょ

cha     ちゃ
chi       ち
chu     ちゅ
che     ちぇ
cho     ちょ

gwa	ぐぁ
gwi	ぐぃ
gwu	ぐぅ
gwe	ぐぇ
gwo	ぐぉ

xa        ぁ
xi        ぃ
xu        ぅ
xe        ぇ
xo        ぉ

xwa       ゎ
xtu       っ
xtsu      っ
xya       ゃ
xyu       ゅ
xyo       ょ

nb       ん
nc       ん
nd       ん
nf       ん
ng       ん
nh       ん
nj       ん
nk       ん
nl       ん
nm       ん
nn       ん
np       ん
nr       ん
ns       ん
nt       ん
nv       ん
nw       ん
nx       ん
ny       ん
nz       ん

bb	っ
cc	っ
dd	っ
ff	っ
gg	っ
hh	っ
jj	っ
kk	っ
ll      っ
mm	っ
pp	っ
rr	っ
ss	っ
tt	っ
vv	っ
ww	っ
yy	っ
zz	っ
tch	っ
");

  QString d = QString(getenv("HOME")) + "/.kimera/dic";
  QDir dir( d );
  if ( !dir.exists() ) {
    dir.mkdir(dir.path());
  }
  
  QFile f( dir.filePath("hiragana.dic") );  
  if ( !f.exists() && f.open( IO_WriteOnly ) ) {
    QTextStream stream( &f );
    stream << s;
    f.close();
  } 
}


void
DictHiragana::writeDictKata() const
{
  QString s = QObject::tr("## ひらがな カタカナ変換辞書

あ    ア
い    イ
う    ウ
え    エ
お    オ

か    カ
き    キ
く    ク
け    ケ
こ    コ

さ    サ
し    シ
す    ス
せ    セ
そ    ソ

た    タ
ち    チ
つ    ツ
て    テ
と    ト

な    ナ
に    ニ
ぬ    ヌ
ね    ネ
の    ノ

は    ハ
ひ    ヒ
ふ    フ
へ    ヘ
ほ    ホ

ま    マ
み    ミ
む    ム
め    メ
も    モ

や    ヤ
ゆ    ユ
よ    ヨ

ら    ラ
り    リ
る    ル
れ    レ
ろ    ロ

わ    ワ
ゐ    ヰ
ゑ    ヱ
を    ヲ

ん    ン

が    ガ
ぎ    ギ
ぐ    グ
げ    ゲ
ご    ゴ

ざ    ザ
じ    ジ
ず    ズ
ぜ    ゼ
ぞ    ゾ

だ    ダ
ぢ    ヂ
づ    ヅ
で    デ
ど    ド

ば    バ
び    ビ
ぶ    ブ
べ    ベ
ぼ    ボ

ぱ    パ
ぴ    ピ
ぷ    プ
ぺ    ペ
ぽ    ポ

ぁ    ァ
ぃ    ィ
ぅ    ゥ
ぇ    ェ
ぉ    ォ

ゃ    ャ
ゅ    ュ
ょ    ョ

っ    ッ
ゎ    ヮ
");

  QString d = QString(getenv("HOME")) + "/.kimera/dic";
  QDir dir( d );
  if ( !dir.exists() ) {
    dir.mkdir(dir.path());
  }
  
  QFile f( dir.filePath("katakana.dic") );  
  if ( !f.exists() && f.open( IO_WriteOnly ) ) {
    QTextStream stream( &f );
    stream << s;
    f.close();
  } 
}


void
DictHiragana::writeDictAlphbt() const
{
  QString s = QObject::tr("## 全角英字変換辞書

a    ａ
b    ｂ
c    ｃ
d    ｄ
e    ｅ
f    ｆ
g    ｇ
h    ｈ
i    ｉ
j    ｊ
k    ｋ
l    ｌ
m    ｍ
n    ｎ
o    ｏ
p    ｐ
q    ｑ
r    ｒ
s    ｓ
t    ｔ
u    ｕ
v    ｖ
w    ｗ
x    ｘ
y    ｙ
z    ｚ

A    Ａ
B    Ｂ
C    Ｃ
D    Ｄ
E    Ｅ
F    Ｆ
G    Ｇ
H    Ｈ
I    Ｉ
J    Ｊ
K    Ｋ
L    Ｌ
M    Ｍ
N    Ｎ
O    Ｏ
P    Ｐ
Q    Ｑ
R    Ｒ
S    Ｓ
T    Ｔ
U    Ｕ
V    Ｖ
W    Ｗ
X    Ｘ
Y    Ｙ
Z    Ｚ
");

  QString d = QString(getenv("HOME")) + "/.kimera/dic";
  QDir dir( d );
  if ( !dir.exists() ) {
    dir.mkdir(dir.path());
  }
  
  QFile f( dir.filePath("zenkakualphabet.dic") );  
  if ( !f.exists() && f.open( IO_WriteOnly ) ) {
    QTextStream stream( &f );
    stream << s;
    f.close();
  } 
}


void
DictHiragana::writeDictSymbol() const
{
  QString s = QObject::tr("## 全角数字記号変換辞書 

1       １
2       ２
3       ３
4       ４
5       ５
6       ６
7       ７
8       ８
9       ９
0       ０

{       『
}       』
^       ＾
<       ＜
>       ＞
(       （
)       ）
-       ー
{       ｛
}       ｝

?       ？
!       ！
#       ＃
$       ＄
\"       ”
%       ％
&       ＆
'       ’
`       ｀
+       ＋
*       ＊
=       ＝
|       ｜
;       ；
:       ：
~       ￣
_       ＿
/       ／
\\       ￥

@/      ・
@\\     ＼
@       ＠
@~      〜
@||     ‖
@3      …
@2      ‥
");

  QString d = QString(getenv("HOME")) + "/.kimera/dic";
  QDir dir( d );
  if ( !dir.exists() ) {
    dir.mkdir(dir.path());
  }
  
  QFile f( dir.filePath("numeralsymbols.dic") );  
  if ( !f.exists() && f.open( IO_WriteOnly ) ) {
    QTextStream stream( &f );
    stream << s;
    f.close();
  }
}


void
DictHiragana::writeDictKanaInp() const
{
QString s = QObject::tr("## かな入力 キー割り当て

1         ぬ
Shift+!   ぬ
2         ふ
Shift+\"   ふ
3         あ
Shift+#   ぁ
4         う
Shift+$   ぅ
5         え
Shift+%   ぇ
6         お
Shift+&   ぉ
7         や
Shift+'   ゃ
8         ゆ
Shift+(   ゅ
9         よ
Shift+)   ょ
0         わ
Shift+~   を
-         ほ
Shift+=   ほ
^         へ
\\         ー
Shift+|   ー
Q         た
Shift+Q   た
W         て
Shift+W   て
E         い
Shift+E   ぃ
R         す
Shift+R   す
T         か
Shift+T   か
Y         ん
Shift+Y   ん
U         な
Shift+U   な
I         に
Shift+I   に
O         ら
Shift+O   ら
P         せ
Shift+P   『
@         ゛
Shift+`   ゛    
[         ゜
Shift+{   「
A         ち
Shift+A   ち
S         と
Shift+S   と
D         し
Shift+D   し
F         は
Shift+F   は
G         き
Shift+G   き
H         く
Shift+H   く
J         ま
Shift+J   ま
K         の
Shift+K   の
L         り
Shift+L   り
;         れ
Shift++   』
:         け
Shift+*   ヶ
]         む
Shift+}   」
Z         つ
Shift+Z   っ
X         さ
Shift+X   さ
C         そ
Shift+C   そ
V         ひ
Shift+V   ひ
B         こ
Shift+B   こ
N         み
Shift+N   み
M         も
Shift+M   も
,         ね
Shift+<   、
.         る
Shift+>   。
/         め
Shift+?   ・
\\         ろ
Shift+_   ｜
Keypad+0  ０   
Keypad+1  １
Keypad+2  ２
Keypad+3  ３
Keypad+4  ４
Keypad+5  ５
Keypad+6  ６
Keypad+7  ７
Keypad+8  ８
Keypad+9  ９
Keypad+/  ／
Keypad+*  ＊
Keypad+-  −
Keypad++  ＋
Keypad+.  ．
");

  QString d = QString(getenv("HOME")) + "/.kimera/dic";
  QDir dir( d );
  if ( !dir.exists() ) {
    dir.mkdir(dir.path());
  }
  
  QFile f( dir.filePath("kanainput.dic") );  
  if ( !f.exists() && f.open( IO_WriteOnly ) ) {
    QTextStream stream( &f );
    stream << s;
    f.close();
  } 
}


void
DictHiragana::writeDictDakuten() const
{
  QString s = QObject::tr("## かな入力 濁点文字変換辞書

か゛    が
き゛    ぎ
く゛    ぐ
け゛    げ
こ゛    ご

さ゛    ざ
し゛    じ
す゛    ず
せ゛    ぜ
そ゛    ぞ

た゛    だ
ち゛    ぢ
つ゛    づ
て゛    で
と゛    ど

は゛    ば
ひ゛    び
ふ゛    ぶ
へ゛    べ
ほ゛    ぼ

は゜    ぱ
ひ゜    ぴ
ふ゜    ぷ
へ゜    ぺ
ほ゜    ぽ

カ゛    ガ
キ゛    ギ
ク゛    グ
ケ゛    ゲ
コ゛    ゴ

サ゛    ザ
シ゛    ジ
ス゛    ズ
セ゛    ゼ
ソ゛    ゾ

タ゛    ダ
チ゛    ヂ
ツ゛    ヅ
テ゛    デ
ト゛    ド

ハ゛    バ
ヒ゛    ビ
フ゛    ブ
ヘ゛    ベ
ホ゛    ボ

ハ゜    パ  
ヒ゜    ピ
フ゜    プ
ヘ゜    ペ
ホ゜    ポ
");

  QString d = QString(getenv("HOME")) + "/.kimera/dic";
  QDir dir( d );
  if ( !dir.exists() ) {
    dir.mkdir(dir.path());
  }
  
  QFile f( dir.filePath("dakuten.dic") );  
  if ( !f.exists() && f.open( IO_WriteOnly ) ) {
    QTextStream stream( &f );
    stream << s;
    f.close();
  } 
}
