
// See
// - http://ja.wikipedia.org/wiki/%E3%83%AD%E3%83%BC%E3%83%9E%E5%AD%97%E5%85%A5%E5%8A%9B
//  > ローマ字入力 - Wikipedia
//
// See - http://la.ma.la/js/roma.html
//      > JavaScriptでローマ字かな変換してみるテスト

MYAPP.namespace('MYAPP.katoy.typing.hira2roma');

MYAPP.katoy.typing.hira2roma = function() {

    // dependencies

    // private properties nad methods
    var Constr,
    /**
     * ひらがな:ローマ字 の変換の定義.
     * @type {string}
     * @const
     */
    h2r_table = '' +
    'あ:a,  い:i,       う:u,      え:e,  お:o,' +
    'か:ka, き:ki,      く:ku,     け:ke, こ:ko,' +
    'さ:sa, し:si|shi,  す:su,     せ:se, そ:so,' +
    'た:ta, ち:ti|chi,  つ:tu|tsu, て:te, と:to,' +
    'な:na, に:ni,      ぬ:nu,     ね:ne, の:no,' +
    'は:ha, ひ:hi,      ふ:hu|fu,  へ:he, ほ:ho,' +
    'ま:ma, み:mi,      む:mu,     め:me, も:mo,' +
    'や:ya,             ゆ:yu,           よ:yo,' +
    'ら:ra, り:ri,      る:ru,     れ:re, ろ:ro,' +
    'わ:wa, ゐ:wyi,                ゑ:wue,を:wo,' +
    'ん:nn|n\',' +
    'が:ga, ぎ:gi,    ぐ:gu, げ:ge, ご:go,' +
    'ざ:za, じ:zi|ji, ず:zu, ぜ:ze, ぞ:zo,' +
    'だ:da, ぢ:di,    づ:du, で:de, ど:do,' +
    'ば:ba, び:bi,    ぶ:bu, べ:be, ぼ:bo,' +
    'ぱ:pa, ぴ:pi,    ぷ:pu, ぺ:pe, ぽ:po,' +
    'ー:-|^,' +
    'ぁ:xa,  ぃ:xi,  ぅ:xu,  ぇ:xe, ぉ:xo,' +
    'ヵ:xka, ヶ:xke, ' +
    'っ:xtu|xtsu,' +
    'ゃ:xya, ゅ:xyu, ょ:xyu, ゎ:xwa,' +
    'きゃ:kya, きゅ:kyu, きぇ:kye, きょ:kyo,' +
    'ぎゃ:gya, ぎゅ:gyu, ぎょ:gyo,' +
    'しゃ:sya|sha, しゅ:syu|shu, しぇ:sye|she, しょ:syo|sho,' +
    'じゃ:zya|ja|jya,  じゅ:zyu|ju|jyu,  じぇ:zye|je,  じょ:zyo|jo|jyo,' +
    'ちゃ:tya|cha|cya, ちゅ:tyu|chu|cyu, ちぇ:tye|che, ちょ:tyo|cho|cyo,' +
    'ぢゃ:dya, ぢゅ:dyu, ぢょ:dyo,' +
    'にゃ:nya, にゅ:nyu, にょ:nyo,' +
    'ひゃ:hya, ひゅ:hyu, ひょ:hyo,' +
    'びゃ:bya, びゅ:byu, ぴょ:byo,' +
    'ぴゃ:hya, ぴゅ:hyu, ぴょ:hyo,' +
    'みゃ:mya, みゅ:myu, みょ:myo,' +
    'りゃ:rya, りゅ:ryu, りょ:ryo,' +
    'つぁ:tsa, つぇ:tse, つぉ:tso,' +
    'てぃ:thi|t\'i, でぃ:dhi|d\'i, てゅ:thu|t\'yu, でゅ:dhu|d\'yu,' +
    'ふぁ:fa|hwa, ふぃ:fi|hwi, ふゅ:fyu|hwyu, ふぇ:fe|hwe, ふぉ:fo|hwo,' +
    'いぇ:ye,' +
    'うぃ:whi|wi, うぇ:whe|we, うぉ:who,' +
    'ヴぁ:va, ヴぃ:vi, ヴ:vu, ヴぇ:ve, ヴぉ:vo,' +
    'ヴゅ:vyu,' +
    'くぁ:kwa|qa, くぃ:kwi|qi, くぇ:kwe|qe, くぉ:kwo|qo,' +
    'ぐぁ:gwa,' +
    'つぃ:tsi,' +
    'とぅ:twu|t\'u, どぅ:dwu|d\'u',

    /**
     * ひらがな:カタカナ の変換の定義.
     * @type {string}
     * @const
     */
    h2k_table = '' +
    'あ:ア, い:イ,  う:ウ,  え:エ, お:オ,' +
    'か:カ, き:キ,  く:ク,  け:ケ, こ:コ,' +
    'さ:サ, し:シ,  す:ス,  せ:セ, そ:ソ,' +
    'た:タ, ち:チ,  つ:ツ,  て:テ, と:ト,' +
    'な:ナ, に:ニ,  ぬ:ヌ,  ね:ネ, の:ノ,' +
    'は:ハ, ひ:ヒ,  ふ:フ,  へ:ヘ, ほ:ホ,' +
    'ま:マ, み:ミ,  む:ム,  め:メ, も:モ,' +
    'や:ヤ,        ゆ:ユ,        よ:ヨ,' +
    'ら:ラ, り:リ,  る:ル,  れ:レ, ろ:ロ,' +
    'わ:ワ, ゐ:ヰ,         ゑ:ヱ ,を:ヲ,' +
    'ん:ン,' +
    'が:ガ, ぎ:ギ,  ぐ:グ, げ:ゲ, ご:ゴ,' +
    'ざ:ザ, じ:ジ,  ず:ズ, ぜ:ゼ, ぞ:ゾ,' +
    'だ:ダ, ぢ:ヂ,  づ:ヅ, で:デ, ど:ド,' +
    'ば:バ, び:ビ,  ぶ:ブ, べ:ベ, ぼ:ボ,' +
    'ぱ:パ, ぴ:ピ,  ぷ:プ, ぺ:ペ, ぽ:ポ,' +
    'ぁ:ァ, ぃ:ィ,  ぅ:ゥ, ぇ:ェ, ぉ:ォ,' +
    'っ:ッ,' +
    'ゃ:ャ, ゅ:ュ, ょ:ョ,' +
    'ゎ:ヮ',
    hira2roma,
    roma2hira,
    hira2kana,
    kana2hira;

    /**
     * ひらがな-> ローマ字.
     * @param {string} hira_str ひらがな.
     * @return {string} ローマ字.
     */
    function to_roma(hira_str) {
        var roma = '';
        for (var i = 0, len = hira_str.length; i < len; i++) {

            var r2 = [];
            if (i + 1 < len) {
                var c2 = hira_str.charAt(i) + hira_str.charAt(i + 1);
                r2 = hira2roma[c2];
            }

            if ((typeof r2 !== 'undefined') && (r2.length > 0)) {
                roma += r2[0];
                i++;
            } else if (hira_str.charAt(i) === 'っ') {
                if (i + 1 < len) {
                    var n1 = hira2roma[hira_str.charAt(i + 1)];
                    if (n1) {
                        var n00 = n1[0].charAt(0);
                        if ('cdfghjklmpqrstvwxyz'.indexOf(n00) >= 0) {
                            roma += n00;
                        } else {
                            roma += 'xtu';
                        }
                    } else {
                        roma += 'xtu';
                    }
                }
            } else {
                var c1 = hira_str.charAt(i),
                r1 = hira2roma[c1];

                if (typeof r1 !== 'undefined') {
                    roma += r1[0];
                } else {
                    roma += c1;
                }
            }
        }
        return roma.toUpperCase();
    }

    /**
     * ローマ字-> ひらがな.
     * @param {string} text ローマ字.
     * @return {string} ひらがな.
     */
    function to_hira(text) {
        var nstr = [],
        skip = 0,
        substr,
        latin = /[a-zA-Z.,-\^]/;

        for (var pos = 0, len = text.length; pos < len; pos++) {
            if (skip > 0) {
                skip--;
                continue;
            }
            substr = text.charAt(pos);
            if (!latin.test(substr)) {
                nstr.push(substr);
                continue;
            }

            var slen = 5,
            f = false;
            while (--slen) {
                substr = text.slice(pos, pos + slen);
                var hira = roma2hira[substr.toLowerCase()];
                if (typeof hira === 'undefined') {
                    continue;
                }
                f = true;
                skip = (slen === 2) ? 1 : slen - 1;
                //「っ」の場合、一文字戻す
                if ((slen === 2) && (hira.charAt(0) === 'っ')) {
                    pos--;
                }
                nstr.push(hira);
                break;
            }
            if (!f) {
                nstr.push(substr);
            }
        }
        return nstr.join('');
    }

    /**
     * ひらがな-> カタカナ.
     * @param {string} text ひらがな.
     * @return {string} カタカナ.
     */
    function hira_to_kana(text) {
        var kana = '';
        for (var i = 0, len = text.length; i < len; i++) {
            var k = hira2kana[text.charAt(i)];
            if (typeof k === 'undefined') {
                k = text.charAt(i);
            }
            kana += k;
        }
        return kana;
    }

    /**
     * カタカナ-> ひらがな.
     * @param {string} text ひらがな.
     * @return {string} カタカナ.
     */
    function kana_to_hira(text) {
        var hira = '';
        for (var i = 0, len = text.length; i < len; i++) {
            var h = kana2hira[text.charAt(i)];
            if (typeof h === 'undefined') {
                h = text.charAt(i);
            }
            hira += h;
        }
        return hira;
    }

    /**
     * ローマ字-> カタカナ.
     * @param {string} text ローマ字.
     * @return {string} カタカナ.
     */
    function to_kana(text) {
        return hira_to_kana(to_hira(text));
    }

    function init_hira2roma() {
        var h2r = [];

        var ws = h2r_table.replace(/^\s+|\s+$/g, '').split(',');
        for (var i = 0, len = ws.length; i < len; i++) {
            var w = ws[i].replace(/^\s+|\s+$/g, ''),
            ss = w.split(':'),
            hira = ss[0],
            romas = ss[1].split('|');

            h2r[hira] = romas;
        }
        return h2r;
    }

    function init_roma2hira() {
        var r2h = [];

        var ws = h2r_table.replace(/^\s+|\s+$/g, '').split(',');
        for (var i = 0, len = ws.length; i < len; i++) {
            var w = ws[i].replace(/^\s+|\s+$/g, ''),
            ss = w.split(':'),
            hira = ss[0],
            romas = ss[1].replace(/^\s+|\s+$/g, '').split('|');

            for (var j = 0, len2 = romas.length; j < len2; j++) {
                r2h[romas[j]] = hira;
            }
        }
        r2h.bb = 'っ';
        r2h.cc = 'っ';
        r2h.dd = 'っ';
        r2h.ff = 'っ';
        r2h.gg = 'っ';
        r2h.hh = 'っ';
        r2h.jj = 'っ';
        r2h.kk = 'っ';
        r2h.ll = 'っ';
        r2h.mm = 'っ';
        r2h.pp = 'っ';
        r2h.qq = 'っ';
        r2h.rr = 'っ';
        r2h.ss = 'っ';
        r2h.tt = 'っ';
        r2h.vv = 'っ';
        r2h.ww = 'っ';
        r2h.xx = 'っ';
        r2h.yy = 'っ';
        r2h.zz = 'っ';
        return r2h;
    }

    function init_hira2kana() {
        var h2k = [],
        ws = h2k_table.replace(/^\s+|\s+$/g, '').split(',');

        for (var i = 0, len = ws.length; i < len; i++) {
            var w = ws[i].replace(/^\s+|\s+$/g, ''),
            ss = w.split(':');

            h2k[ss[0]] = ss[1];
        }
        return h2k;
    }

    function init_kana2hira() {
        var k2h = [],
        key,
        hasOwn = Object.prototype.hasOwnProperty;
        for (key in hira2kana) {
            if (hasOwn.call(hira2kana, key)) {
                k2h[hira2kana[key]] = key;
            }
        }
        return k2h;
    }
    // one-time init procedures
    hira2roma = init_hira2roma();
    roma2hira = init_roma2hira();
    hira2kana = init_hira2kana();
    kana2hira = init_kana2hira();

    // public API -- constructor
    Constr = function(obj) {
        this.elements = this.toArray(obj);
    };

    // public API -- prototype
    Constr.prototype = {
        constructor: MYAPP.katoy.typing.hira2roma,
        version: '1.0',
        toArray: function(obj) {
            var a = [];
            if (typeof obj !== 'undefined') {
                for (var i = 0, len = obj.length; i < len; i += 1) {
                    a[i] = obj[i];
                }
            }
            return a;
        },

        to_roma: to_roma,
        to_kana: to_kana,
        to_hira: to_hira,
        hira_to_kana: hira_to_kana,
        kana_to_hira: kana_to_hira

    };
    // return the constroctor
    return Constr;
}();
