/**
 * Copyright (c) 2003-2005 System Integrator Corporation.
 *                 All Rights Reserved.
 */

package jp.co.sint.mail;

import java.util.Vector;
import java.util.Iterator;
import javax.mail.internet.MimeUtility;

/**
 * @version $Id: SIEncodeToJis.java,v 1.0 2005/05/25 Exp $
 * @author Takahiro Matsuda
 * <br>Description:メール送信にあたり、本文および日本語を含むヘッダをエンコードします。
 * <p>History</p>
 * <p>Author&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Date&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Reason</p>
 *  ============&nbsp;&nbsp;&nbsp;==========&nbsp;&nbsp;===========================<br>
 * Takahiro Matsuda   2005/05/25 17:50:00 Original
*/

public class SIEncodeToJis {

  /**
   * <b>EncodeToJis</b>
   * コンストラクタ
   * @param なし
   * @return なし
   * @throws なし
   */
  public SIEncodeToJis() {
  }

  /**
   * <b>encodeBody</b>
   * メール本文用にエンコードします。
   * @param lBody  本文
   * @return エンコード後の本文
   * @throws なし
   */
  public String encodeBody(String lBody) {
    return(sjisToJis(lBody));
  }

  /**
   * <b>encodeHeader</b>
   * メールヘッダ用にエンコードします。
   * @param lHeader  ヘッダデータ
   * @return エンコード後のヘッダデータ
   * @throws なし
   */
  public String encodeHeader(String lHeader) {
    String ret = null;
    if (lHeader != null && lHeader.length() > 0) {
      String tmp = null;
      Vector buff = new Vector();
      // ヘッダ文字列を13文字で分割（MIMEエンコードの分割対応）
      if (lHeader.length() > 10) {
        for (int i =0; i < lHeader.length();) {
          int endpoint = i + 10;
          if (endpoint > lHeader.length()) {
            endpoint = lHeader.length();
          }
          buff.add(lHeader.substring(i, endpoint));
          i = endpoint;
        }
      } else {
        buff.add(lHeader);
      }
      ret = "";
      Iterator iter = buff.iterator();
      while(iter.hasNext()) {
        // SJIS-JIS変換
        tmp = sjisToJis((String)iter.next());
        if (tmp != null && tmp.length() > 0 && tmp.indexOf("\u001B") != -1) {
          // Base64エンコード
          try {
            while(tmp.indexOf("\u001B") != -1) {
              int start = tmp.indexOf("\u001B");
              int end = tmp.indexOf("\u001B", start + 1) + 3;
              if (end == -1) {
                end = tmp.length();
              }
              String mimeStr = MimeUtility.encodeText(tmp.substring(start, end), "ISO-2022-JP", "B");
              tmp = tmp.substring(0, start) + mimeStr + tmp.substring(end);
            }
          } catch(Exception ex) { }
        }
        ret = ret + tmp;
      }
	}
    return(ret);
  }

  /**
   * <b>sjisToJis</b>
   * ユニコード文字列をMS932化後にJIS化
   * @param lStr  対象データ
   * @return 変換後のデータ
   * @throws なし
   */
  private String sjisToJis(String lStr) {
    // JIS ENCODING
    // START  JIS (to JIS)    ESC $ B
    // END    JIS (to ASCII)  ESC ( B
    String ret = null;
    char[] sjis = null;
    try {
      sjis = byteToChar(lStr.getBytes("MS932"));
    } catch(Exception ex) {
    }
    if (sjis != null && sjis.length > 0) {
      boolean inSJIS = false;
      Vector vec = new Vector();
      for (int i = 0; i < sjis.length; i++) {
        if (i == (sjis.length - 1)) {             // 配列最後の文字の処理
          if (!isSJIS(sjis[i], (char)0, true)) {  // SJISではない（SJISの場合はスキップ）
            if (inSJIS) {
              vec.add(new Character((char)0x1b));
              vec.add(new Character((char)'('));
              vec.add(new Character((char)'B'));
              inSJIS = false;
            }
            vec.add(new Character(sjis[i]));
          }
        } else if (isSJIS(sjis[i], sjis[i+1], false)) {  // もしSJISだったら
          if (!inSJIS) {
            vec.add(new Character((char)0x1b));
            vec.add(new Character((char)'$'));
            vec.add(new Character((char)'B'));
            inSJIS = true;
          }
          // SJIS to JIS
          int upChar = (int)sjis[i];
          int lwChar = (int)sjis[i+1];
          int upOffset = 176;
          int lwOffset = 126;
          int ajust = 0;
          if (lwChar < 159) {       // アジャストの変更
            ajust = 1;
          }
          if (upChar < 160) {       // オフセットの変更
            upOffset = 112;
          }
          if (ajust == 1) {         // オフセットの変更
            if (lwChar > 127) {
              lwOffset = 32;
            } else {
              lwOffset = 31;
            }
          }
          int jis1 = ((upChar - upOffset) << 1) - ajust;
          int jis2 = lwChar - lwOffset;
          char char1 = (char)jis1;
          char char2 = (char)jis2;
          vec.add(new Character(char1));
          vec.add(new Character(char2));
          i++;
        } else {                                  // SJISではない場合
          if (inSJIS) {
            vec.add(new Character((char)0x1b));
            vec.add(new Character((char)'('));
            vec.add(new Character((char)'B'));
            inSJIS = false;
          }
          vec.add(new Character(sjis[i]));
        }
      }
      if (inSJIS) {
        vec.add(new Character((char)0x1b));
        vec.add(new Character((char)'('));
        vec.add(new Character((char)'B'));
      }
      ret = vectorToString(vec);
    }
    return(ret);
  }

  /**
   * <b>isSJIS</b>
   * ユニコード文字列をMS932化後にJIS化
   * @param hi			上位バイト
   * @param low			下位バイト
   * @param only1st		true:上位バイトのみ評価、false:上位、下位バイトを評価
   * @return true:Shift-JISコードである	false:Shift-JISコードではない
   * @throws なし
   */
  private boolean isSJIS(char hi, char low, boolean only1st) {
    boolean ret = false;
    if ((hi >= 0x81 && hi <= 0x9f) || (hi >= 0xe0 && hi <= 0xef)) {
      if (only1st) {
        ret = true;
      } else if ((low >= 0x40 && low <= 0x7e) || (low >= 0x80 && low <= 0xfc)) {
        ret = true;
      }
    }
    return(ret);
  }

  /**
   * <b>vectorToString</b>
   * Vectorオブジェクトに格納された文字データをString化
   * @param lVec		元データ
   * @return 変換後の文字データ
   * @throws なし
   */
  private String vectorToString(Vector lVec) {
    String ret = null;
    if (lVec != null && lVec.size() > 0) {
      StringBuffer strBuff = new StringBuffer();
      Iterator iter = lVec.iterator();
      while(iter.hasNext()) {
        strBuff.append(((Character)iter.next()).charValue());
      }
      ret = strBuff.toString();
    }
    return(ret);
  }

  /**
   * <b>byteToChar</b>
   * byte配列をchar配列に変換
   * @param lByte		元データ
   * @return 変換後のchar配列
   * @throws なし
   */
  private char[] byteToChar(byte[] lByte) {
    char[] ret = null;
    if (lByte != null && lByte.length > 0) {
      ret = new char[lByte.length];
      for (int i = 0; i < lByte.length; i++) {
        ret[i] = (char)lByte[i];
        ret[i] = (char)(ret[i] & 0x00ff);
      }
    }
    return(ret);
  }
}