/*
101 国の機関
値「101」は、行政機関、裁判所及び国会の機関に係る情報であることを意味する。

201 地方公共団体
値「201」は、地方自治法第１条の３において定義されている普通地方公共団体及び特別地方公共団体に係る情報であることを意味する。

301 株式会社 値「301」は、株式会社の情報であることを意味する。
302 有限会社 値「302」は、特例有限会社の情報であることを意味する。
303 合名会社 値「303」は、合名会社の情報であることを意味する。
304 合資会社 値「304」は、合資会社の情報であることを意味する。
305 合同会社 値「305」は、合同会社の情報であることを意味する。
399 その他の設立登記法人
値「399」は、株式会社（301）、有限会社（302）、合名会社（303）、合資会社（304）及び合同会社（305）以外の法令の規定により設立の登記をすることに
よって成立する法人の情報であることを意味する。

401 外国会社等
値「401」は、外国、外国の行政区画及び外国会社並びに法律又は条約の規定により認許された外国法人の情報であることを意味する。

499 その他

株式・有限・合名・合資・合同は表記と種別が一致するのでよい

*/

const codes = {
  "301": {
    "@type": "コード型",
    "識別値": "301",
    "表記": "株式会社"
  },
  "302": {
    "@type": "コード型",
    "識別値": "302",
    "表記": "有限会社"
  },
  "303": {
    "@type": "コード型",
    "識別値": "303",
    "表記": "合名会社"
  },
  "304": {
    "@type": "コード型",
    "識別値": "304",
    "表記": "合資会社"
  },
  "305": {
    "@type": "コード型",
    "識別値": "305",
    "表記": "合同会社"
  },
  "399": {
    "@type": "コード型",
    "識別値": "399",
    "表記": "その他の設立登記法人"
  }
};

const names = {
  "301": ["株式会社", "株式會社", "(株)", "（株）", "㈱"],
  "302": ["有限会社", "有限會社", "(有)", "㈲", "（有）"],
  "303": ["合名会社", "合名會社"],
  "304": ["合資会社", "合資會社", "（資）"],
  "305": ["合同会社", "合同會社", "（同）"],
  "399": [
    "一般財団法人",
    "一般社団法人",
    "社団法人",
    "医療法人",
    "貸金業協会",
    "学校法人",
    "企業年金基金",
    "企業年金連合会",
    "危険物保安技術協会",
    "行政書士会",
    "漁業共済組合",
    "漁業共済組合連合会",
    "漁業信用基金協会",
    "漁船保険組合",
    "漁船保険中央会",
    "勤労者財産形成基金",
    "軽自動車検査協会",
    "健康保険組合",
    "健康保険組合連合会",
    "原子力発電環境整備機構",
    "高圧ガス保安協会",
    "広域臨海環境整備センター",
    "公益財団法人",
    "公益社団法人",
    "厚生年金基金",
    "更生保護法人",
    "小型船舶検査機構",
    "国家公務員共済組合",
    "国家公務員共済組合連合会",
    "国民健康保険組合",
    "国民健康保険団体連合会",
    "国民年金基金",
    "国民年金基金連合会",
    "市街地再開発組合",
    "自転車競技会",
    "自動車安全運転センター",
    "司法書士会",
    "社会福祉法人",
    "社会保険労務士会",
    "宗教法人",
    "住宅街区整備組合",
    "酒造組合",
    "酒造組合中央会",
    "酒造組合連合会",
    "酒販組合",
    "酒販組合中央会",
    "酒販組合連合会",
    "商工会",
    "商工会議所",
    "商工会連合会",
    "商工組合",
    "商工組合連合会",
    "商品先物取引協会",
    "消防団員等公務災害補償等共済基金",
    "職員団体等",
    "職業訓練法人",
    "信用保証協会",
    "生活衛生同業組合",
    "生活衛生同業組合連合会",
    "税理士会",
    "石炭鉱業年金基金",
    "船員災害防止協会",
    "全国健康保険協会",
    "全国市町村職員共済組合連合会",
    "全国社会保険労務士会連合会",
    "全国農業会議所",
    "損害保険料率算出団体",
    "地方議会議員共済会",
    "地方競馬全国協会",
    "地方公務員共済組合",
    "地方公務員共済組合連合会",
    "地方公務員災害補償基金",
    "中央職業能力開発協会",
    "中央労働災害防止協会",
    "中小企業団体中央会",
    "投資者保護基金",
    "独立行政法人",
    "土地改良事業団体連合会",
    "土地家屋調査士会",
    "都道府県職業能力開発協会",
    "都道府県農業会議",
    "日本行政書士会連合会",
    "日本勤労者住宅協会",
    "日本公認会計士協会",
    "日本司法書士会連合会",
    "日本商工会議所",
    "日本消防検定協会",
    "日本私立学校振興・共済事業団",
    "日本税理士会連合会",
    "日本赤十字社",
    "日本電気計器検定所",
    "日本土地家屋調査士会連合会",
    "日本弁護士連合会",
    "日本弁理士会",
    "日本水先人会連合会",
    "認可金融商品取引業協会",
    "農業共済組合",
    "農業共済組合連合会",
    "農業協同組合中央会",
    "農業協同組合連合会",
    "農業信用基金協会",
    "農水産業協同組合貯金保険機構",
    "負債整理組合",
    "弁護士会",
    "保険契約者保護機構",
    "水先人会",
    "輸出組合",
    "輸入組合",
    "預金保険機構",
    "労働組合",
    "労働災害防止協会",
    "（独）",
    "地方独立行政法人",
    "（地独）",
    "（公財）",
    "（一財）",
    "一般社団",
    "（一社）",
    "（社）",
    "（医）",
    "医療法人社団",
    "（医社）",
    "（公社）",
    "財団法人",
    "（財）",
    "（社福）",
    "（福）",
    "国立大学法人",
    "（大）",
    "（国）",
    "公立大学法人",
    "国立研究開発法人",
    "（学）",
    "特定非営利活動法人",
    "ＮＰＯ法人",
    "（特）",
    "（特非）",
    "協同組合",
    "（協）",
    "企業組合",
    "（企業）",
    "工業組合",
    "（工業）",
    "協業組合",
    "（協業）",
    "（業）",
    "商業組合",
    "（商業）",
    "農業組合",
    "（農業）",
    "（農）",
    "農業共同組合",
    "信用組合",
    "森林組合",
    "保険組合",
    "共済組合",
    "農事組合法人",
    "弁護士法人",
    "社会保険労務士法人",
    "土地家屋調査士法人",
    "税理士法人",
    "行政書士法人",
    "司法書士法人",
    "特許業務法人",
    "監査法人",
    "信用金庫",
    "土地改良区"
  ]
};

const reverse = [];
Object.keys(names).forEach(code => {
  names[code].forEach(name => {
    reverse.push({
      name: name,
      code: code
    });
  });
});
reverse.sort((a, b) => b.name.length - a.name.length);


function log(target, type, message) {
  if (type === "INFO") {
    if (message === undefined) message = "";
    const added = ["組織種別", "組織種別位置"].filter(a => target[a] !== undefined);
    if (added.length === 0) message += "プロパティは追加されませんでした。";
    else message += `プロパティ(${added.join("|")}) が追加されました。`;
  }
  const now = new Date();
  now.setHours(now.getHours() + 9);
  const content = {
    "@type": "hj:更新履歴型",
    "hj:更新者": {
      "@type": "実体型",
      "表記": "IMI法人種別抽出コンポーネント"
    },
    "種別": type,
    "説明": message,
    "日時": {
      "@type": "日時型",
      "標準型日時": now.toISOString().replace(/Z$/, "+09:00")
    }
  };
  if (target["メタデータ"] === undefined) target["メタデータ"] = content;
  else if (Array.isArray(target["メタデータ"])) target["メタデータ"].push(content);
  else target["メタデータ"] = [target["メタデータ"], content];
}


const types = ["法人型", "ic:法人型", "hj:法人型"];

module.exports = function(target) {

  let count = 0;

  const dig = function(focus) {
    if (Array.isArray(focus)) {
      focus.forEach(a => {
        dig(a)
      });
      return;
    }
    if (typeof focus !== 'object') return;

    Object.keys(focus).forEach(key => {
      dig(focus[key]);
    });

    if (focus["表記"] === undefined || types.indexOf(focus["@type"]) === -1) return;

    count++;
    let label = focus["表記"]["@value"] || focus["表記"];
    // 前後の空白は除去する
    label = label.replace(/^[ 　]+/, "").replace(/[ 　]+$/, "");

    //const notes = [];

    //㈹がある場合にはその次の文字をスタートとする
    //if (label.indexOf("㈹") !== -1) {
    //  label = label.substring(label.indexOf("㈹") + 1);
    //  notes.push("表記中の（代）がついた法人を対象として判定しました。")
    //}

    //  途中に※がある場合はコメントとみなし、当該部位を削除する
    //if (label.indexOf("※") > 0) {
    //  label = label.substring(0, label.indexOf("※"));
    //  notes.push("表記中の ※ 以降は削除して判定しました。")
    //}

    const candidate = [];
    reverse.forEach(namecode => {
      const name = namecode.name;
      const code = codes[namecode.code];

      for (let index = label.indexOf(name); index !== -1; index = label.indexOf(name)) {
        if (index === 0) {
          candidate.push({
            "組織種別": code,
            "組織種別位置": "前"
          });
        } else if (index + name.length === label.length) {
          candidate.push({
            "組織種別": code,
            "組織種別位置": "後"
          });
        } else {
          candidate.push({
            "組織種別": code
          });
        }
        label = label.replace(name, " ");
      }
    });

    if (candidate.length === 0) {
      log(focus, "WARNING", "組織種別を判定するフレーズが見つかりませんでした");
    } else if (candidate.length === 1) {
      if (candidate[0]["組織種別位置"])
        focus["組織種別位置"] = candidate[0]["組織種別位置"];
      if (candidate[0]["組織種別"])
        focus["組織種別"] = candidate[0]["組織種別"];
      log(focus, "INFO");
    } else if (candidate.length > 0) {
      log(focus, "WARNING", "表記に複数の法人名が記述されているようです");
    }
  };

  dig(target);

  // JSON-LD Context の付与
  const context = [
    "https://imi.go.jp/ns/core/context.jsonld",
    "http://hojin-info.go.jp/ns/domain/biz/1/context.jsonld"
  ];
  if (target["@context"] === undefined) {
    target["@context"] = context;
  } else if (Array.isArray(target["@context"])) {
    context.forEach(a => {
      if (target["@context"].indexOf(a) === -1) target["@context"].push(a);
    });
  } else if (typeof target["@context"] === 'string') {
    target["@context"] = [target["@context"]];
    context.forEach(a => {
      if (target["@context"].indexOf(a) === -1) target["@context"].push(a);
    });
  } else {
    context.unshift(target["@context"]);
    target["@context"] = context;
  }
  if (count === 0) {
    log(target, "WARNING", "法人型が見つかりませんでした");
  }

  return target;
};
