/*
 * Aipo is a groupware program developed by Aimluck,Inc.
 * http://aipostyle.com/
 *
 * Copyright(C) 2013 avanza Co.,Ltd. All rights reserved.
 * http://www.avnz.co.jp/
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 */

package com.aimluck.eip.mail.util;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Reader;

import javax.swing.text.MutableAttributeSet;
import javax.swing.text.html.HTML;
import javax.swing.text.html.HTMLEditorKit;
import javax.swing.text.html.parser.ParserDelegator;

import org.apache.jetspeed.services.logging.JetspeedLogFactoryService;
import org.apache.jetspeed.services.logging.JetspeedLogger;

/**
 * HTMLテキスト抽出処理
 * 
 * 2次開発 要件No.23 テキスト部を持たないメール（HTMLメール）対応
 */
public class HtmlExtractor {

  private static final JetspeedLogger logger = JetspeedLogFactoryService.getLogger(HtmlExtractor.class.getName());

  /**
   * HTMLメールからのテキスト抽出処理
   * 
   * @param isr
   *            メールのボディのストリーム
   * @return テキスト
   * @throws IOException
   */
  public String exec(InputStreamReader isr) throws IOException {
    Reader reader = null;
    String result = "変換失敗";
    try {
      reader = new BufferedReader(isr);
      MyParserCallback cb = new MyParserCallback();
      ParserDelegator pd = new ParserDelegator();
      pd.parse(reader, cb, true);
      result = cb.getResult();
    } catch (Exception e) {
      logger.error("HTMLのパース抽出処理でエラーが発生しました。", e);
    } finally {
      if (reader != null) {
        try {
          reader.close();
        } catch (IOException e) {
          logger.error("HTMLのパース抽出処理でストリームエラーが発生しました。", e);
          throw e;
        }
      }
    }

    return result;
  }

  /**
   * テキスト抽出用コールバック用クラス
   */
  class MyParserCallback extends HTMLEditorKit.ParserCallback {

    /** 改行コード */
    private static final String LINEFEED = "\n";

    /** Aタグのhref属性値 */
    private String aTagRef;

    /** 処理中のタグ */
    private HTML.Tag currentTag;

    /** BLOCKQUOTE内フラグ */
    private boolean isInnerBlockQuote;

    /** A内フラグ */
    private boolean isInnerA;

    /** 結果 */
    private final StringBuffer result = new StringBuffer();

    /**
     * 結果取得
     * 
     * @return 抽出テキスト
     */
    public String getResult() {
      return result.toString();
    }

    /**
     * 開始タグハンドラ
     * 
     * @param tag
     *            タグ
     * @param attr
     *            属性
     * @param pos
     *            位置
     */
    @Override
    public void handleStartTag(HTML.Tag tag, MutableAttributeSet attr, int pos) {
      // System.out.println("handleStartTag()が呼ばれました" + tag);

      currentTag = HTML.getTag(tag.toString());

      if (tag.equals(HTML.Tag.DIV)) {
        result.append(LINEFEED);
      } else if (tag.equals(HTML.Tag.UL)) {
        result.append(LINEFEED);
      } else if (tag.equals(HTML.Tag.LI)) {
        result.append("・");
      } else if (tag.equals(HTML.Tag.P)) {
        result.append(LINEFEED);
      } else if (tag.equals(HTML.Tag.TABLE)) {
        result.append(LINEFEED);
      } else if (tag.equals(HTML.Tag.A)) {
        String ret = (String) attr.getAttribute(HTML.Attribute.HREF);
        // System.out.println(ret +"AタグのHREF属性の値です:" + pos);
        if (ret != null && ret.startsWith("mailto:")) {
          aTagRef = ret.substring(ret.indexOf(":") + 1);
        } else {
          aTagRef = ret;
        }
        isInnerA = true;
      } else if (tag.equals(HTML.Tag.BLOCKQUOTE)) {
        isInnerBlockQuote = true;
      }
    }

    /**
     * 終了タグハンドラ
     * 
     * @param tag
     *            タグ
     * @param attr
     *            属性
     * @param pos
     *            位置
     */
    @Override
    public void handleEndTag(HTML.Tag tag, int pos) {
      // System.out.println("handleEndTag()が呼ばれました:" + tag);

      if (tag.equals(HTML.Tag.DIV)) {
        result.append(LINEFEED);
      } else if (tag.equals(HTML.Tag.UL)) {
        result.append(LINEFEED);
      } else if (tag.equals(HTML.Tag.LI)) {
        result.append(LINEFEED);
      } else if (tag.equals(HTML.Tag.P)) {
        result.append(LINEFEED);
      } else if (tag.equals(HTML.Tag.TABLE)) {
        result.append(LINEFEED);
      } else if (tag.equals(HTML.Tag.TH)) {
        result.append("　");
      } else if (tag.equals(HTML.Tag.TD)) {
        result.append("　");
      } else if (tag.equals(HTML.Tag.TR)) {
        result.append(LINEFEED);
      } else if (tag.equals(HTML.Tag.BLOCKQUOTE)) {
        isInnerBlockQuote = false;
      } else if (tag.equals(HTML.Tag.A)) {
        isInnerA = false;
      }

      currentTag = null;
    }

    /**
     * シンプルタグハンドラ
     * 
     * @param tag
     *            タグ
     * @param attr
     *            属性
     * @param pos
     *            位置
     */
    @Override
    public void handleSimpleTag(HTML.Tag tag, MutableAttributeSet attr, int pos) {
      // System.out.println("handleSimpleTag()が呼ばれました" + tag);
      if (tag.equals(HTML.Tag.BR)) {
        result.append(LINEFEED);
      }
    }

    /**
     * タグ内のテキストハンドラ
     * 
     * @param data
     *            テキスト
     * @param pos
     *            位置
     */
    @Override
    public void handleText(char[] data, int pos) {
      try {
        // &nbsp;を空白に置換しながら文字列に変換
        String s = new String(data).replace("\u00A0", " ");

        if (isInnerBlockQuote) {
          result.append("　");
        }

        if (isInnerA) {
          result.append(s);
          if (aTagRef != null && !"".equals(aTagRef)) {
            // System.out.print("<" + aTagRef + ">");
            result.append("＜" + aTagRef + "＞");
            aTagRef = null;
          }
        } else {
          if (!HTML.Tag.STYLE.equals(currentTag) && !HTML.Tag.SCRIPT.equals(currentTag)) {
            result.append(s);
          }
        }
      } catch (Exception e) {
        logger.error("HTMLからのテキスト抽出処理でエラーが発生しました。", e);
      }
    }
  }
}