/*
 Copyright (c) 2012, Guillaume Marty

 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
 in the Software without restriction, including without limitation the rights
 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 copies of the Software, and to permit persons to whom the Software is
 furnished to do so, subject to the following conditions:

 The above copyright notice and this permission notice shall be included in
 all copies or substantial portions of the Software.

 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 THE SOFTWARE.
 */

/**
 * Normalize Japanese inputs and expose function to perform several conversions.
 *
 * Note: The space character is treated like a roman character as it usually
 *   has the same width as them in Japanese texts.
 *
 * \@todo Replace characters range from ãˆ  to ã‰ƒ, ãŠ€ to ãŠ° and ã‡° to ã‡¿.
 * \@todo Lazy initializations of conversionTables and converters.
 * \@todo Would fixHalfwidthKana be useful?
 *
 * Descriptions of functions exposed:
 * normalizeJapanese ã€Œå…¨è§’ã€�è‹±å­—ãƒ»æ•°å­—ã‚’ã€Œå�Šè§’ã€�ã€�ã€Œå�Šè§’ã€�è¨˜ãƒ»ã‚«ã‚¿ã‚«ãƒŠã‚’ã€Œå…¨è§’ã€�ã�«å¤‰æ�›
 * converters.fullwidthToHalfwidth.alphabet    ã€Œå…¨è§’ã€�è‹±å­—ã‚’ã€Œå�Šè§’ã€�ã�«å¤‰æ�›
 * converters.halfwidthToFullwidth.alphabet    ã€Œå�Šè§’ã€�è‹±å­—ã‚’ã€Œå…¨è§’ã€�ã�«å¤‰æ�›
 * converters.fullwidthToHalfwidth.numbers     ã€Œå…¨è§’ã€�æ•°å­—ã‚’ã€Œå�Šè§’ã€�ã�«å¤‰æ�›
 * converters.halfwidthToFullwidth.numbers     ã€Œå�Šè§’ã€�æ•°å­—ã‚’ã€Œå…¨è§’ã€�ã�«å¤‰æ�› ã€Œå…¨è§’ã€�ã‚¹ãƒšãƒ¼ã‚¹ã‚’ã€Œå�Šè§’ã€�
 * converters.fullwidthToHalfwidth.punctuation ã€Œå…¨è§’ã€�è¨˜å�·ã‚’ã€Œå�Šè§’ã€�ã�«å¤‰æ�› ã€Œå�Šè§’ã€�ã‚¹ãƒšãƒ¼ã‚¹ã‚’ã€Œå…¨è§’ã€�
 * converters.halfwidthToFullwidth.punctuation ã€Œå�Šè§’ã€�è¨˜å�·ã‚’ã€Œå…¨è§’ã€�ã�«å¤‰æ�›
 * converters.fullwidthToHalfwidth.katakana    ã€Œå…¨è§’ã‚«ã‚¿ã‚«ãƒŠã€�ã‚’ã€Œå�Šè§’ã‚«ã‚¿ã‚«ãƒŠã€�ã�«å¤‰æ�›
 * converters.halfwidthToFullwidth.katakana    ã€Œå�Šè§’ã‚«ã‚¿ã‚«ãƒŠã€�ã‚’ã€Œå…¨è§’ã‚«ã‚¿ã‚«ãƒŠã€�ã�«å¤‰æ�›
 * converters.hiraganaToKatakana               ã€Œã‚«ã‚¿ã‚«ãƒŠã€�ã‚’ã€Œã�²ã‚‰ã�Œã�ªã€�ã�«å¤‰æ�›
 * converters.katakanaToHiragana               ã€Œã�²ã‚‰ã�Œã�ªã€�ã‚’ã€Œã‚«ã‚¿ã‚«ãƒŠã€�ã�«å¤‰æ�›
 */

var flip = require('../util/utils.js').flip;
var merge = require('../util/utils.js').merge;
var replacer = require('../util/utils').replacer;

// From http://fernweh.jp/b/mb_convert_kana_js/
var conversionTables = {
  fullwidthToHalfwidth: {
    alphabet: {
      'ï½�': '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',
      'ã€€': ' ' // Fullwidth space
    },

    numbers: {
      'ï¼�': '0',
      'ï¼‘': '1',
      'ï¼’': '2',
      'ï¼“': '3',
      'ï¼”': '4',
      'ï¼•': '5',
      'ï¼–': '6',
      'ï¼—': '7',
      'ï¼˜': '8',
      'ï¼™': '9'
    },

    symbol: {
      'ï¼¿': '_',
      'ï¼�': '-',
      'ï¼Œ': ',',
      'ï¼›': ';',
      'ï¼š': ':',
      'ï¼�': '!',
      'ï¼Ÿ': '?',
      'ï¼�': '.',
      'ï¼ˆ': '(',
      'ï¼‰': ')',
      'ï¼»': '[',
      'ï¼½': ']',
      'ï½›': '{',
      'ï½�': '}',
      'ï¼ ': '@',
      'ï¼Š': '*',
      'ï¼¼': '\\',
      'ï¼�': '/',
      'ï¼†': '&',
      'ï¼ƒ': '#',
      'ï¼…': '%',
      'ï½€': '`',
      'ï¼¾': '^',
      'ï¼‹': '+',
      'ï¼œ': '<',
      'ï¼�': '=',
      'ï¼�': '>',
      'ï½œ': '|',
      // Never converted: 'ï½�': '~',
      'â‰ª': 'Â«',
      'â‰«': 'Â»',
      'â”€': '-',
      'ï¼„': '$',
      'ï¼‚': '"'
    },

    purePunctuation: {
      'ã€�': 'ï½¤',
      'ã€‚': 'ï½¡',
      'ãƒ»': 'ï½¥',
      'ã€Œ': 'ï½¢',
      'ã€�': 'ï½£'
    },

    punctuation: {},

    katakana: {
      'ã‚›': 'ï¾�',
      'ã‚œ': 'ï¾Ÿ',
      'ãƒ¼': 'ï½°',

      'ãƒ´': 'ï½³ï¾�',
      'ã‚¬': 'ï½¶ï¾�',
      'ã‚®': 'ï½·ï¾�',
      'ã‚°': 'ï½¸ï¾�',
      'ã‚²': 'ï½¹ï¾�',
      'ã‚´': 'ï½ºï¾�',
      'ã‚¶': 'ï½»ï¾�',
      'ã‚¸': 'ï½¼ï¾�',
      'ã‚º': 'ï½½ï¾�',
      'ã‚¼': 'ï½¾ï¾�',
      'ã‚¾': 'ï½¿ï¾�',
      'ãƒ€': 'ï¾€ï¾�',
      'ãƒ‚': 'ï¾�ï¾�',
      'ãƒ…': 'ï¾‚ï¾�',
      'ãƒ‡': 'ï¾ƒï¾�',
      'ãƒ‰': 'ï¾„ï¾�',
      'ãƒ�': 'ï¾Šï¾�',
      'ãƒ‘': 'ï¾Šï¾Ÿ',
      'ãƒ“': 'ï¾‹ï¾�',
      'ãƒ”': 'ï¾‹ï¾Ÿ',
      'ãƒ–': 'ï¾Œï¾�',
      'ãƒ—': 'ï¾Œï¾Ÿ',
      'ãƒ™': 'ï¾�ï¾�',
      'ãƒš': 'ï¾�ï¾Ÿ',
      'ãƒœ': 'ï¾�ï¾�',
      'ãƒ�': 'ï¾�ï¾Ÿ',

      'ã‚¡': 'ï½§',
      'ã‚¢': 'ï½±',
      'ã‚£': 'ï½¨',
      'ã‚¤': 'ï½²',
      'ã‚¥': 'ï½©',
      'ã‚¦': 'ï½³',
      'ã‚§': 'ï½ª',
      'ã‚¨': 'ï½´',
      'ã‚©': 'ï½«',
      'ã‚ª': 'ï½µ',
      'ã‚«': 'ï½¶',
      'ã‚­': 'ï½·',
      'ã‚¯': 'ï½¸',
      'ã‚±': 'ï½¹',
      'ã‚³': 'ï½º',
      'ã‚µ': 'ï½»',
      'ã‚·': 'ï½¼',
      'ã‚¹': 'ï½½',
      'ã‚»': 'ï½¾',
      'ã‚½': 'ï½¿',
      'ã‚¿': 'ï¾€',
      'ãƒ�': 'ï¾�',
      'ãƒƒ': 'ï½¯',
      'ãƒ„': 'ï¾‚',
      'ãƒ†': 'ï¾ƒ',
      'ãƒˆ': 'ï¾„',
      'ãƒŠ': 'ï¾…',
      'ãƒ‹': 'ï¾†',
      'ãƒŒ': 'ï¾‡',
      'ãƒ�': 'ï¾ˆ',
      'ãƒ�': 'ï¾‰',
      'ãƒ�': 'ï¾Š',
      'ãƒ’': 'ï¾‹',
      'ãƒ•': 'ï¾Œ',
      'ãƒ˜': 'ï¾�',
      'ãƒ›': 'ï¾�',
      'ãƒ�': 'ï¾�',
      'ãƒŸ': 'ï¾�',
      'ãƒ ': 'ï¾‘',
      'ãƒ¡': 'ï¾’',
      'ãƒ¢': 'ï¾“',
      'ãƒ£': 'ï½¬',
      'ãƒ¤': 'ï¾”',
      'ãƒ¥': 'ï½­',
      'ãƒ¦': 'ï¾•',
      'ãƒ§': 'ï½®',
      'ãƒ¨': 'ï¾–',
      'ãƒ©': 'ï¾—',
      'ãƒª': 'ï¾˜',
      'ãƒ«': 'ï¾™',
      'ãƒ¬': 'ï¾š',
      'ãƒ­': 'ï¾›',
      'ãƒ¯': 'ï¾œ',
      'ãƒ²': 'ï½¦',
      'ãƒ³': 'ï¾�'
    }
  },

  halfwidthToFullwidth: {}
};

var fixFullwidthKana = {
  'ã‚�ã‚›': 'ã‚�',
  'ãƒ½ã‚›': 'ãƒ¾',

  'ã�†ã‚›': 'ã‚”',
  'ã�‹ã‚›': 'ã�Œ',
  'ã��ã‚›': 'ã��',
  'ã��ã‚›': 'ã��',
  'ã�‘ã‚›': 'ã�’',
  'ã�“ã‚›': 'ã�”',
  'ã�•ã‚›': 'ã�–',
  'ã�—ã‚›': 'ã�˜',
  'ã�™ã‚›': 'ã�š',
  'ã�›ã‚›': 'ã�œ',
  'ã��ã‚›': 'ã��',
  'ã�Ÿã‚›': 'ã� ',
  'ã�¡ã‚›': 'ã�¢',
  'ã�¤ã‚›': 'ã�¥',
  'ã�¦ã‚›': 'ã�§',
  'ã�¨ã‚›': 'ã�©',
  'ã�¯ã‚›': 'ã�°',
  'ã�¯ã‚œ': 'ã�±',
  'ã�²ã‚›': 'ã�³',
  'ã�²ã‚œ': 'ã�´',
  'ã�µã‚›': 'ã�¶',
  'ã�µã‚œ': 'ã�·',
  'ã�¸ã‚›': 'ã�¹',
  'ã�¸ã‚œ': 'ã�º',
  'ã�»ã‚›': 'ã�¼',
  'ã�»ã‚œ': 'ã�½',
  'ã�£ã�ª': 'ã‚“ã�ª',
  'ã�£ã�«': 'ã‚“ã�«',
  'ã�£ã�¬': 'ã‚“ã�¬',
  'ã�£ã�­': 'ã‚“ã�­',
  'ã�£ã�®': 'ã‚“ã�®',

  'ã‚¦ã‚›': 'ãƒ´',
  'ã‚«ã‚›': 'ã‚¬',
  'ã‚­ã‚›': 'ã‚®',
  'ã‚¯ã‚›': 'ã‚°',
  'ã‚±ã‚›': 'ã‚²',
  'ã‚³ã‚›': 'ã‚´',
  'ã‚µã‚›': 'ã‚¶',
  'ã‚·ã‚›': 'ã‚¸',
  'ã‚¹ã‚›': 'ã‚º',
  'ã‚»ã‚›': 'ã‚¼',
  'ã‚½ã‚›': 'ã‚¾',
  'ã‚¿ã‚›': 'ãƒ€',
  'ãƒ�ã‚›': 'ãƒ‚',
  'ãƒ„ã‚›': 'ãƒ…',
  'ãƒ†ã‚›': 'ãƒ‡',
  'ãƒˆã‚›': 'ãƒ‰',
  'ãƒ�ã‚›': 'ãƒ�',
  'ãƒ�ã‚œ': 'ãƒ‘',
  'ãƒ’ã‚›': 'ãƒ“',
  'ãƒ’ã‚œ': 'ãƒ”',
  'ãƒ•ã‚›': 'ãƒ–',
  'ãƒ•ã‚œ': 'ãƒ—',
  'ãƒ˜ã‚›': 'ãƒ™',
  'ãƒ˜ã‚œ': 'ãƒš',
  'ãƒ›ã‚›': 'ãƒœ',
  'ãƒ›ã‚œ': 'ãƒ�',
  'ãƒƒãƒŠ': 'ãƒ³ãƒŠ',
  'ãƒƒãƒ‹': 'ãƒ³ãƒ‹',
  'ãƒƒãƒŒ': 'ãƒ³ãƒŒ',
  'ãƒƒãƒ�': 'ãƒ³ãƒ�',
  'ãƒƒãƒ�': 'ãƒ³ãƒ�'
};

var fixCompositeSymbolsTable = {
  'ã‹€': '1æœˆ',
  'ã‹�': '2æœˆ',
  'ã‹‚': '3æœˆ',
  'ã‹ƒ': '4æœˆ',
  'ã‹„': '5æœˆ',
  'ã‹…': '6æœˆ',
  'ã‹†': '7æœˆ',
  'ã‹‡': '8æœˆ',
  'ã‹ˆ': '9æœˆ',
  'ã‹‰': '10æœˆ',
  'ã‹Š': '11æœˆ',
  'ã‹‹': '12æœˆ',

  'ã� ': '1æ—¥',
  'ã�¡': '2æ—¥',
  'ã�¢': '3æ—¥',
  'ã�£': '4æ—¥',
  'ã�¤': '5æ—¥',
  'ã�¥': '6æ—¥',
  'ã�¦': '7æ—¥',
  'ã�§': '8æ—¥',
  'ã�¨': '9æ—¥',
  'ã�©': '10æ—¥',
  'ã�ª': '11æ—¥',
  'ã�«': '12æ—¥',
  'ã�¬': '13æ—¥',
  'ã�­': '14æ—¥',
  'ã�®': '15æ—¥',
  'ã�¯': '16æ—¥',
  'ã�°': '17æ—¥',
  'ã�±': '18æ—¥',
  'ã�²': '19æ—¥',
  'ã�³': '20æ—¥',
  'ã�´': '21æ—¥',
  'ã�µ': '22æ—¥',
  'ã�¶': '23æ—¥',
  'ã�·': '24æ—¥',
  'ã�¸': '25æ—¥',
  'ã�¹': '26æ—¥',
  'ã�º': '27æ—¥',
  'ã�»': '28æ—¥',
  'ã�¼': '29æ—¥',
  'ã�½': '30æ—¥',
  'ã�¾': '31æ—¥',

  'ã�˜': '0ç‚¹',
  'ã�™': '1ç‚¹',
  'ã�š': '2ç‚¹',
  'ã�›': '3ç‚¹',
  'ã�œ': '4ç‚¹',
  'ã��': '5ç‚¹',
  'ã��': '6ç‚¹',
  'ã�Ÿ': '7ç‚¹',
  'ã� ': '8ç‚¹',
  'ã�¡': '9ç‚¹',
  'ã�¢': '10ç‚¹',
  'ã�£': '11ç‚¹',
  'ã�¤': '12ç‚¹',
  'ã�¥': '13ç‚¹',
  'ã�¦': '14ç‚¹',
  'ã�§': '15ç‚¹',
  'ã�¨': '16ç‚¹',
  'ã�©': '17ç‚¹',
  'ã�ª': '18ç‚¹',
  'ã�«': '19ç‚¹',
  'ã�¬': '20ç‚¹',
  'ã�­': '21ç‚¹',
  'ã�®': '22ç‚¹',
  'ã�¯': '23ç‚¹',
  'ã�°': '24ç‚¹',

  'ã�»': 'å¹³æˆ�',
  'ã�¼': 'æ˜­å’Œ',
  'ã�½': 'å¤§æ­£',
  'ã�¾': 'æ˜�æ²»',
  'ã�¿': 'æ ªå¼�ä¼šç¤¾',

  'ãŒ€': 'ã‚¢ãƒ‘ãƒ¼ãƒˆ',
  'ãŒ�': 'ã‚¢ãƒ«ãƒ•ã‚¡',
  'ãŒ‚': 'ã‚¢ãƒ³ãƒšã‚¢',
  'ãŒƒ': 'ã‚¢ãƒ¼ãƒ«',
  'ãŒ„': 'ã‚¤ãƒ‹ãƒ³ã‚°',
  'ãŒ…': 'ã‚¤ãƒ³ãƒ�',
  'ãŒ†': 'ã‚¦ã‚ªãƒ³',
  'ãŒ‡': 'ã‚¨ã‚¹ã‚¯ãƒ¼ãƒ‰',
  'ãŒˆ': 'ã‚¨ãƒ¼ã‚«ãƒ¼',
  'ãŒ‰': 'ã‚ªãƒ³ã‚¹',
  'ãŒŠ': 'ã‚ªãƒ¼ãƒ ',
  'ãŒ‹': 'ã‚«ã‚¤ãƒª', //æµ·é‡Œ
  'ãŒŒ': 'ã‚«ãƒ©ãƒƒãƒˆ',
  'ãŒ�': 'ã‚«ãƒ­ãƒªãƒ¼',
  'ãŒ�': 'ã‚¬ãƒ­ãƒ³',
  'ãŒ�': 'ã‚¬ãƒ³ãƒ�',
  'ãŒ�': 'ã‚®ã‚¬',
  'ãŒ‘': 'ã‚®ãƒ‹ãƒ¼',
  'ãŒ’': 'ã‚­ãƒ¥ãƒªãƒ¼',
  'ãŒ“': 'ã‚®ãƒ«ãƒ€ãƒ¼',
  'ãŒ”': 'ã‚­ãƒ­',
  'ãŒ•': 'ã‚­ãƒ­ã‚°ãƒ©ãƒ ',
  'ãŒ–': 'ã‚­ãƒ­ãƒ¡ãƒ¼ãƒˆãƒ«',
  'ãŒ—': 'ã‚­ãƒ­ãƒ¯ãƒƒãƒˆ',
  'ãŒ˜': 'ã‚°ãƒ©ãƒ ',
  'ãŒ™': 'ã‚°ãƒ©ãƒ ãƒˆãƒ³',
  'ãŒš': 'ã‚¯ãƒ«ã‚¼ã‚¤ãƒ­',
  'ãŒ›': 'ã‚¯ãƒ­ãƒ¼ãƒ�',
  'ãŒœ': 'ã‚±ãƒ¼ã‚¹',
  'ãŒ�': 'ã‚³ãƒ«ãƒŠ',
  'ãŒ�': 'ã‚³ãƒ¼ãƒ�',
  'ãŒŸ': 'ã‚µã‚¤ã‚¯ãƒ«',
  'ãŒ ': 'ã‚µãƒ³ãƒ�ãƒ¼ãƒ ',
  'ãŒ¡': 'ã‚·ãƒªãƒ³ã‚°',
  'ãŒ¢': 'ã‚»ãƒ³ãƒ�',
  'ãŒ£': 'ã‚»ãƒ³ãƒˆ',
  'ãŒ¤': 'ãƒ€ãƒ¼ã‚¹',
  'ãŒ¥': 'ãƒ‡ã‚·',
  'ãŒ¦': 'ãƒ‰ãƒ«',
  'ãŒ§': 'ãƒˆãƒ³',
  'ãŒ¨': 'ãƒŠãƒ�',
  'ãŒ©': 'ãƒ�ãƒƒãƒˆ',
  'ãŒª': 'ãƒ�ã‚¤ãƒ„',
  'ãŒ«': 'ãƒ‘ãƒ¼ã‚»ãƒ³ãƒˆ',
  'ãŒ¬': 'ãƒ‘ãƒ¼ãƒ„',
  'ãŒ­': 'ãƒ�ãƒ¼ãƒ¬ãƒ«',
  'ãŒ®': 'ãƒ”ã‚¢ã‚¹ãƒˆãƒ«',
  'ãŒ¯': 'ãƒ”ã‚¯ãƒ«',
  'ãŒ°': 'ãƒ”ã‚³',
  'ãŒ±': 'ãƒ“ãƒ«',
  'ãŒ²': 'ãƒ•ã‚¡ãƒ©ãƒƒãƒ‰',
  'ãŒ³': 'ãƒ•ã‚£ãƒ¼ãƒˆ',
  'ãŒ´': 'ãƒ–ãƒƒã‚·ã‚§ãƒ«',
  'ãŒµ': 'ãƒ•ãƒ©ãƒ³',
  'ãŒ¶': 'ãƒ˜ã‚¯ã‚¿ãƒ¼ãƒ«',
  'ãŒ·': 'ãƒšã‚½',
  'ãŒ¸': 'ãƒšãƒ‹ãƒ’',
  'ãŒ¹': 'ãƒ˜ãƒ«ãƒ„',
  'ãŒº': 'ãƒšãƒ³ã‚¹',
  'ãŒ»': 'ãƒšãƒ¼ã‚¸',
  'ãŒ¼': 'ãƒ™ãƒ¼ã‚¿',
  'ãŒ½': 'ãƒ�ã‚¤ãƒ³ãƒˆ',
  'ãŒ¾': 'ãƒœãƒ«ãƒˆ',
  'ãŒ¿': 'ãƒ›ãƒ³',
  'ã�€': 'ãƒ�ãƒ³ãƒ‰',
  'ã��': 'ãƒ›ãƒ¼ãƒ«',
  'ã�‚': 'ãƒ›ãƒ¼ãƒ³',
  'ã�ƒ': 'ãƒ�ã‚¤ã‚¯ãƒ­',
  'ã�„': 'ãƒ�ã‚¤ãƒ«',
  'ã�…': 'ãƒ�ãƒƒãƒ�',
  'ã�†': 'ãƒ�ãƒ«ã‚¯',
  'ã�‡': 'ãƒ�ãƒ³ã‚·ãƒ§ãƒ³',
  'ã�ˆ': 'ãƒŸã‚¯ãƒ­ãƒ³',
  'ã�‰': 'ãƒŸãƒª',
  'ã�Š': 'ãƒŸãƒªãƒ�ãƒ¼ãƒ«',
  'ã�‹': 'ãƒ¡ã‚¬',
  'ã�Œ': 'ãƒ¡ã‚¬ãƒˆãƒ³',
  'ã��': 'ãƒ¡ãƒ¼ãƒˆãƒ«',
  'ã��': 'ãƒ¤ãƒ¼ãƒ‰',
  'ã��': 'ãƒ¤ãƒ¼ãƒ«',
  'ã��': 'ãƒ¦ã‚¢ãƒ³',
  'ã�‘': 'ãƒªãƒƒãƒˆãƒ«',
  'ã�’': 'ãƒªãƒ©',
  'ã�“': 'ãƒ«ãƒ”ãƒ¼',
  'ã�”': 'ãƒ«ãƒ¼ãƒ–ãƒ«',
  'ã�•': 'ãƒ¬ãƒ ',
  'ã�–': 'ãƒ¬ãƒ³ãƒˆã‚²ãƒ³',
  'ã�—': 'ãƒ¯ãƒƒãƒˆ'
};

// punctuation is pure_punctuation
conversionTables.fullwidthToHalfwidth.punctuation = merge(
    conversionTables.fullwidthToHalfwidth.symbol,
    conversionTables.fullwidthToHalfwidth.purePunctuation
)

// Fill in the conversion tables with the flipped tables.
conversionTables.halfwidthToFullwidth.alphabet = flip(conversionTables.fullwidthToHalfwidth.alphabet);
conversionTables.halfwidthToFullwidth.numbers = flip(conversionTables.fullwidthToHalfwidth.numbers);
conversionTables.halfwidthToFullwidth.symbol = flip(conversionTables.fullwidthToHalfwidth.symbol);
conversionTables.halfwidthToFullwidth.purePunctuation = flip(conversionTables.fullwidthToHalfwidth.purePunctuation);
conversionTables.halfwidthToFullwidth.punctuation = flip(conversionTables.fullwidthToHalfwidth.punctuation);
conversionTables.halfwidthToFullwidth.katakana = flip(conversionTables.fullwidthToHalfwidth.katakana);

// Build the normalization table.
conversionTables.normalize = merge(
    conversionTables.fullwidthToHalfwidth.alphabet,
    conversionTables.fullwidthToHalfwidth.numbers,
    conversionTables.fullwidthToHalfwidth.symbol,
    conversionTables.halfwidthToFullwidth.purePunctuation,
    conversionTables.halfwidthToFullwidth.katakana
    );

var converters = {
  fullwidthToHalfwidth: {
    alphabet: replacer(conversionTables.fullwidthToHalfwidth.alphabet),
    numbers: replacer(conversionTables.fullwidthToHalfwidth.numbers),
    symbol: replacer(conversionTables.fullwidthToHalfwidth.symbol),
    purePunctuation: replacer(conversionTables.fullwidthToHalfwidth.purePunctuation),
    punctuation: replacer(conversionTables.fullwidthToHalfwidth.punctuation),
    katakana: replacer(conversionTables.fullwidthToHalfwidth.katakana)
  },

  halfwidthToFullwidth: {
    alphabet: replacer(conversionTables.halfwidthToFullwidth.alphabet),
    numbers: replacer(conversionTables.halfwidthToFullwidth.numbers),
    symbol: replacer(conversionTables.halfwidthToFullwidth.symbol),
    purePunctuation: replacer(conversionTables.halfwidthToFullwidth.purePunctuation),
    punctuation: replacer(conversionTables.halfwidthToFullwidth.punctuation),
    katakana: replacer(conversionTables.halfwidthToFullwidth.katakana)
  },

  fixFullwidthKana: replacer(fixFullwidthKana),
  normalize: replacer(conversionTables.normalize)
};

var fixCompositeSymbols = replacer(fixCompositeSymbolsTable);


/**
 * Convert hiragana to fullwidth katakana.
 * According to http://jsperf.com/converting-japanese, these implementations are
 * faster than using lookup tables.
 *
 * @param {string} str A string.
 * @return {string} A string not containing hiragana.
 */
converters.hiraganaToKatakana = function(str) {
  str = converters.halfwidthToFullwidth.katakana(str);
  str = converters.fixFullwidthKana(str);

  str = str.replace(/ã‚�/g, 'ãƒ½');
  str = str.replace(/ã‚�/g, 'ãƒ¾');
  //str = str.replace(/?/g, 'ğ›€€'); // Letter archaic E

  str = str.replace(/[ã��-ã‚–]/g, function(str) {
    return String.fromCharCode(str.charCodeAt(0) + 96);
  });

  return str;
};


/**
 * Convert katakana to hiragana.
 *
 * @param {string} str A string.
 * @return {string} A string not containing katakana.
 */
converters.katakanaToHiragana = function(str) {
  str = converters.halfwidthToFullwidth.katakana(str);
  str = converters.fixFullwidthKana(str);

  str = str.replace(/ãƒ½/g, 'ã‚�');
  str = str.replace(/ãƒ¾/g, 'ã‚�');
  //str = str.replace(/?/g, 'ğ›€�'); // Letter archaic E

  str = str.replace(/[ã‚¡-ãƒ¶]/g, function(str) {
    return String.fromCharCode(str.charCodeAt(0) - 96);
  });

  return str;
};


/**
 * Fix kana and apply the following processes;
 * * Replace repeat characters
 * * Alphabet to halfwidth
 * * Numbers to halfwidth
 * * Punctuation to fullwidth
 * * Katakana to fullwidth
 * * Fix fullwidth kana
 * * Replace composite symbols
 *
 * @param {string} str
 * @return {string}
 */
var normalize_ja = function(str) {
  // Replace repeat characters.
  str = str
    .replace(/(..)ã€…ã€…/g, '$1$1')
    .replace(/(.)ã€…/g, '$1$1');

  str = converters.normalize(str);
  str = converters.fixFullwidthKana(str);

  // Replace composite symbols.
  str = fixCompositeSymbols(str);

  return str;
};

exports.normalize_ja = normalize_ja;
exports.converters = converters;
