import { actionAddins } from ".";
import {
  IAction,
  IActionResult,
  IActionNode,
  IActionProperty,
  IField,
  IContext,
  IVarName,
} from "../types/ActionTypes";
import { ConditionTree } from "../types/Conditions";

/**
 *  アクションの属性定義
 */
interface IConversionProps {
  field: IField;
  conversion: string;
  verName: IVarName;
}

const fullWidthToHalfWidthMap: { [key: string]: string } = {
  ガ: "ｶﾞ",
  ギ: "ｷﾞ",
  グ: "ｸﾞ",
  ゲ: "ｹﾞ",
  ゴ: "ｺﾞ",
  ザ: "ｻﾞ",
  ジ: "ｼﾞ",
  ズ: "ｽﾞ",
  ゼ: "ｾﾞ",
  ゾ: "ｿﾞ",
  ダ: "ﾀﾞ",
  ヂ: "ﾁﾞ",
  ヅ: "ﾂﾞ",
  デ: "ﾃﾞ",
  ド: "ﾄﾞ",
  バ: "ﾊﾞ",
  ビ: "ﾋﾞ",
  ブ: "ﾌﾞ",
  ベ: "ﾍﾞ",
  ボ: "ﾎﾞ",
  パ: "ﾊﾟ",
  ピ: "ﾋﾟ",
  プ: "ﾌﾟ",
  ペ: "ﾍﾟ",
  ポ: "ﾎﾟ",
  ヴ: "ｳﾞ",
  ヷ: "ﾜﾞ",
  ヺ: "ｦﾞ",
  ア: "ｱ",
  イ: "ｲ",
  ウ: "ｳ",
  エ: "ｴ",
  オ: "ｵ",
  カ: "ｶ",
  キ: "ｷ",
  ク: "ｸ",
  ケ: "ｹ",
  コ: "ｺ",
  サ: "ｻ",
  シ: "ｼ",
  ス: "ｽ",
  セ: "ｾ",
  ソ: "ｿ",
  タ: "ﾀ",
  チ: "ﾁ",
  ツ: "ﾂ",
  テ: "ﾃ",
  ト: "ﾄ",
  ナ: "ﾅ",
  ニ: "ﾆ",
  ヌ: "ﾇ",
  ネ: "ﾈ",
  ノ: "ﾉ",
  ハ: "ﾊ",
  ヒ: "ﾋ",
  フ: "ﾌ",
  ヘ: "ﾍ",
  ホ: "ﾎ",
  マ: "ﾏ",
  ミ: "ﾐ",
  ム: "ﾑ",
  メ: "ﾒ",
  モ: "ﾓ",
  ヤ: "ﾔ",
  ユ: "ﾕ",
  ヨ: "ﾖ",
  ラ: "ﾗ",
  リ: "ﾘ",
  ル: "ﾙ",
  レ: "ﾚ",
  ロ: "ﾛ",
  ワ: "ﾜ",
  ヲ: "ｦ",
  ン: "ﾝ",
  ァ: "ｧ",
  ィ: "ｨ",
  ゥ: "ｩ",
  ェ: "ｪ",
  ォ: "ｫ",
  ッ: "ｯ",
  ャ: "ｬ",
  ュ: "ｭ",
  ョ: "ｮ",
  "。": "｡",
  "、": "､",
  ー: "ｰ",
  "「": "｢",
  "」": "｣",
  "・": "･",
  "　": " ", // 全角スペースも半角スペースに変換
};

const halfWidthToFullWidthMap: { [key: string]: string } = {
  ｶﾞ: "ガ",
  ｷﾞ: "ギ",
  ｸﾞ: "グ",
  ｹﾞ: "ゲ",
  ｺﾞ: "ゴ",
  ｻﾞ: "ザ",
  ｼﾞ: "ジ",
  ｽﾞ: "ズ",
  ｾﾞ: "ゼ",
  ｿﾞ: "ゾ",
  ﾀﾞ: "ダ",
  ﾁﾞ: "ヂ",
  ﾂﾞ: "ヅ",
  ﾃﾞ: "デ",
  ﾄﾞ: "ド",
  ﾊﾞ: "バ",
  ﾋﾞ: "ビ",
  ﾌﾞ: "ブ",
  ﾍﾞ: "ベ",
  ﾎﾞ: "ボ",
  ﾊﾟ: "パ",
  ﾋﾟ: "ピ",
  ﾌﾟ: "プ",
  ﾍﾟ: "ペ",
  ﾎﾟ: "ポ",
  ｳﾞ: "ヴ",
  ﾜﾞ: "ヷ",
  ｦﾞ: "ヺ",
  ｱ: "ア",
  ｲ: "イ",
  ｳ: "ウ",
  ｴ: "エ",
  ｵ: "オ",
  ｶ: "カ",
  ｷ: "キ",
  ｸ: "ク",
  ｹ: "ケ",
  ｺ: "コ",
  ｻ: "サ",
  ｼ: "シ",
  ｽ: "ス",
  ｾ: "セ",
  ｿ: "ソ",
  ﾀ: "タ",
  ﾁ: "チ",
  ﾂ: "ツ",
  ﾃ: "テ",
  ﾄ: "ト",
  ﾅ: "ナ",
  ﾆ: "ニ",
  ﾇ: "ヌ",
  ﾈ: "ネ",
  ﾉ: "ノ",
  ﾊ: "ハ",
  ﾋ: "ヒ",
  ﾌ: "フ",
  ﾍ: "ヘ",
  ﾎ: "ホ",
  ﾏ: "マ",
  ﾐ: "ミ",
  ﾑ: "ム",
  ﾒ: "メ",
  ﾓ: "モ",
  ﾔ: "ヤ",
  ﾕ: "ユ",
  ﾖ: "ヨ",
  ﾗ: "ラ",
  ﾘ: "リ",
  ﾙ: "ル",
  ﾚ: "レ",
  ﾛ: "ロ",
  ﾜ: "ワ",
  ｦ: "ヲ",
  ﾝ: "ン",
  ｧ: "ァ",
  ｨ: "ィ",
  ｩ: "ゥ",
  ｪ: "ェ",
  ｫ: "ォ",
  ｯ: "ッ",
  ｬ: "ャ",
  ｭ: "ュ",
  ｮ: "ョ",
  "｡": "。",
  "､": "、",
  ｰ: "ー",
  "｢": "「",
  "｣": "」",
  "･": "・",
  " ": "　",
};

/**
 * 全角/半角変換アクション
 */
export class FullHalfConversionAction implements IAction {
  name: string;
  actionProps: IActionProperty[];
  props: IConversionProps;
  constructor() {
    this.name = "全角/半角変換";
    this.actionProps = [];
    this.props = {
      field: { code: "" },
      conversion: "",
      verName: { name: "" },
    };
    this.register();
  }

  /**
   * アクションの実行を呼び出す
   * @param actionNode
   * @param event
   * @returns
   */
  async process(
    actionNode: IActionNode,
    event: any,
    context: IContext
  ): Promise<IActionResult> {
    let result = {
      canNext: true,
      result: false,
    };
    try {
      //属性設定を取得する
      this.actionProps = actionNode.actionProps;
      if (
        !("field" in actionNode.ActionValue) &&
        !("conversion" in actionNode.ActionValue) &&
        !("verName" in actionNode.ActionValue)
      ) {
        return result;
      }

      this.props = actionNode.ActionValue as IConversionProps;

      //条件式の計算結果を取得
      const record = event.record;
      if (!(this.props.field.code in record)) {
        throw new Error(
          `フィールド「${this.props.field.code}」が見つかりません。`
        );
      }
      //
      const value = record[this.props.field.code]?.value;

      //条件分岐
      //未入力時は何も処理をせず終了
      if (value === undefined || value === "") {
        record[this.props.field.code].error = null;
      }
      if (this.props.conversion === "全角") {
        context.variables[this.props.verName.name] = this.toFullWidth(value);
      }
      if (this.props.conversion === "半角") {
        context.variables[this.props.verName.name] = this.toHalfWidth(value);
      } else {
        record[this.props.field.code].error = null;
      }
      //resultプロパティ指定
      result = {
        canNext: true,
        result: true,
      };
      return result;

      //例外処理
    } catch (error) {
      context.errors.handleError(error, actionNode);
      result.canNext = false;
      return result;
    }
  }

  // 半角から全角に変換
  toFullWidth(str: string): string {
    //半角の英数字と記号を検索し、半角から全角に変換（半角コードに 0xFEE0 を足して全角にする）
    let retStr = str.replace(/[A-Za-z0-9!-~]/g, function (s) {
      return String.fromCharCode(s.charCodeAt(0) + 0xfee0);
      //半角カタカナなどを検索し、全角に変換するためのマッピングオブジェクト（halfWidthToFullWidthMap）で全角文字に変換
    });
    retStr = retStr.replace(/[\uFF61-\uFF9F ]/g, function (s) {
      return halfWidthToFullWidthMap[s] || s;
    });
    return retStr;
  }

  toHalfWidth(str: string): string {
    //全角の英数字や記号を検索し、全角から半角に変換します（全角コードから 0xFEE0 を引いて半角にする）
    let retStr = str.replace(/[！-～]/g, function (s) {
      return String.fromCharCode(s.charCodeAt(0) - 0xfee0);
      //全角片仮名記号スペースなどを検索し、半角に変換するためのマッピングオブジェクト( halfWidthToFullWidthMap )で半角文字に変換
    });
    retStr = retStr.replace(/[ガ-ヴァ-ン。、ー「」・　]/g, function (s) {
      return fullWidthToHalfWidthMap[s] || s;
    });
    return retStr;
  }

    register(): void {
    actionAddins[this.name] = this;
    }
}
new FullHalfConversionAction();
