/*
 * FileFormat.java
 * 
 * Author: http://www.hrtdotnet.jp/
 * 
 */
package jp.hrtdotnet.java.text;

import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.text.AttributedCharacterIterator;
import java.text.FieldPosition;
import java.text.Format;
import java.text.MessageFormat;
import java.text.ParseException;
import java.text.ParsePosition;

/**
 * テキストファイルの内容のMessageFormatとして扱います。
 * @version 2.1
 * @author hrtdotnet.jp
 * <br>http://www.hrtdotnet.jp/
 * @since 2.1
 */
public class FileFormat extends Format{

    /**
     * 
     */
    private static final long serialVersionUID = 4128314642659824789L;

    private MessageFormat messageFormat = null;
    private String formatText = null;
    protected static final int DEFAULT_BUFFER_SIZE = 8192;

    /**
     * コンストラクタ。
     * 文字列の文字コードはデフォルトの文字コード、改行コードはファイルの改行コードとなります。
     * 
     * @param file ファイル
     * @param fileCharsetName ファイルの文字コード
     * @throws UnsupportedEncodingException 文字コードがサポート外
     * @throws FileNotFoundException ファイルが存在しない
     * @throws IOException ファイルIOエラー
     */
    public FileFormat(File file, String fileCharsetName)
            throws UnsupportedEncodingException, FileNotFoundException, IOException {

        //引数チェック
        if (file == null) {
            throw new NullPointerException("file is null.");
        } else if (fileCharsetName == null) {
            throw new NullPointerException("file-charset-name is null.");
        } else if (fileCharsetName.length() == 0) {
            throw new IllegalArgumentException("file-charset-name is empty-string.");
        }

        //ファイルであることのチェック
        if (file.isFile() == false) {
            throw new IOException("file-object is not a file.");
        }
        
        StringBuffer formatTextBuffer = new StringBuffer();
        InputStreamReader reader = null;
        try {
            int length = 0;
            int offset = 0;
            reader = new InputStreamReader(new FileInputStream(file));
            char[] ch = new char[DEFAULT_BUFFER_SIZE];
            //DEFAULT_BUFFER_SIZEバイト分の読み込み
            while ((length = reader.read(ch, offset, DEFAULT_BUFFER_SIZE)) > 0) {
                char[] ch2 = new char[length];
                System.arraycopy(ch, 0, ch2, 0, length);
                formatTextBuffer.append(ch2);
            }
            
        } finally {
            if (reader != null) {
                reader.close();
            }
        }
        //ファイルの文字コードを指定し、デフォルトの文字コードに変換
        this.formatText = new String(formatTextBuffer.toString().getBytes(fileCharsetName));
        this.messageFormat = new MessageFormat(formatTextBuffer.toString());
    }

    /**
     * コンストラクタ。
     * 文字列の文字コードはデフォルトの文字コード、改行コードは指定した改行コードとなります。
     * 
     * @param file ファイル
     * @param fileCharsetName ファイルの文字コード
     * @param formatLineSeparator フォーマット文字列の改行コード
     * @throws UnsupportedEncodingException 文字コードがサポート外
     * @throws FileNotFoundException ファイルが存在しない
     * @throws IOException ファイルIOエラー
     */
    public FileFormat(File file, String fileCharsetName, String formatLineSeparator)
            throws UnsupportedEncodingException, FileNotFoundException, IOException {
        this(file, fileCharsetName);

        if (formatLineSeparator == null) {
            throw new NullPointerException("format-line-separator is null.");
        } else if (formatLineSeparator.length() == 0) {
            throw new IllegalArgumentException("format-line-separator is empty-string.");
        }
        
        BufferedReader br = null;
        StringBuffer formatTextBuffer = new StringBuffer();
        try {
            //ファイルの改行コードの判別はBufferedReader.readLineで行う
            br = new BufferedReader(new InputStreamReader(new ByteArrayInputStream(this.formatText.getBytes())));
            String line = br.readLine();
            if (line != null) {
                formatTextBuffer.append(line);
            }
            while ((line = br.readLine()) != null) {
                formatTextBuffer.append(formatLineSeparator);
                formatTextBuffer.append(line);
            }
            char end = this.formatText.charAt(this.formatText.length() - 1);
            if (end == '\r' || end == '\n') {
                formatTextBuffer.append(formatLineSeparator);
            }
        } finally {
            if (br != null) {
                br.close();
            }
        }
        this.formatText = new String(formatTextBuffer.toString());
        this.messageFormat = new MessageFormat(formatTextBuffer.toString());
    }

    /*
     * (非 Javadoc)
     * @see java.text.Format#format(java.lang.Object, java.lang.StringBuffer, java.text.FieldPosition)
     */
    public StringBuffer format(Object obj, StringBuffer toAppendTo,
            FieldPosition pos) {
        return this.messageFormat.format(obj, toAppendTo, pos);
    }

    /*
     * (非 Javadoc)
     * @see java.text.Format#parseObject(java.lang.String, java.text.ParsePosition)
     */
    public Object parseObject(String source, ParsePosition pos) {
        return this.messageFormat.parseObject(source, pos);
    }

    /*
     * (非 Javadoc)
     * @see java.text.Format#formatToCharacterIterator(java.lang.Object)
     */
    public AttributedCharacterIterator formatToCharacterIterator(Object obj) {
        return this.messageFormat.formatToCharacterIterator(obj);
    }

    /*
     * (非 Javadoc)
     * @see java.text.Format#parseObject(java.lang.String)
     */
    public Object parseObject(String source) throws ParseException {
        return this.messageFormat.parseObject(source);
    }

    /*
     * (非 Javadoc)
     * @see java.text.Format#clone()
     */
    public Object clone() {
        FileFormat other = (FileFormat)super.clone();
        other.formatText = new String(this.formatText);
        other.messageFormat = (MessageFormat)messageFormat.clone();
        return other;
    }

}
