package junkutil.common;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.nio.channels.FileChannel;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

/**
 * ファイル操作
 * @author Hiroyuki Shiota
 */
public class FileUtil {
	/**
	 * システムの改行コード
	 */
	private static final String ln = System.getProperty(SystemKey.LINE_SEPARATOR);
	
	/**
	 * プライベートコンストラクタ
	 */
	private FileUtil() {
	}
	
	/**
	 * 存在を確認する
	 * @param filename
	 * @return
	 */
	public static boolean exists(String filename) {
		return new File(filename).exists();
	}
	
	/**
	 * テキストを読み込む
	 * @param filename - ファイル名
	 * @return テキスト
	 * @throws IOException
	 */
	public static String readFile(String filename) throws IOException {
		return readFile(filename, null);
	}
	
	/**
	 * テキストを読み込む
	 * @param filename - ファイル名
	 * @param encoding - エンコーディング
	 * @return テキスト
	 * @throws IOException
	 */
	public static String readFile(String filename, String encoding) throws IOException {
		BufferedReader br = null;
		StringBuffer result = new StringBuffer();;
		try {
			if (encoding != null) {
				br = new BufferedReader(new InputStreamReader(new FileInputStream(filename), encoding));
			} else {
				br = new BufferedReader(new InputStreamReader(new FileInputStream(filename)));
			}
			String line;
			List temp = new ArrayList();
			while ((line = br.readLine()) != null) {
				temp.add(line);
			}
			for (int i = 0; i < temp.size(); i++) {
				result.append((String)temp.get(i));
				if (i+1 < temp.size()) result.append(ln);
			}
		} finally {
			try { br.close(); } catch (Exception ee) {}
		}
		return new String(result);
	}
	
	/**
	 * 全行を読み込む
	 * @param filename - ファイル名
	 * @return リスト
	 * @throws IOException
	 */
	public static List readLines(String filename) throws IOException {
		return readLines(filename, null);
	}
	
	/**
	 * 全行を読み込む
	 * @param filename - ファイル名
	 * @return リスト
	 * @throws IOException
	 */
	public static List readLines(String filename, String encoding) throws IOException {
		BufferedReader br = null;
		ArrayList result = null;
		try {
			if (encoding != null) {
				br = new BufferedReader(new InputStreamReader(new FileInputStream(filename), encoding));
			} else {
				br = new BufferedReader(new InputStreamReader(new FileInputStream(filename)));
			}
			String line;
			result = new ArrayList();
			while ((line = br.readLine()) != null) {
				result.add(line);
			}
		} finally {
			try { br.close(); } catch (Exception ee) {}
		}
		return result;
	}
	
	/**
	 * 複数行を新規に書き出す
	 * @param filename - ファイル名
	 * @param list - 行
	 */
	public static void writeLines(String filename, List list) throws IOException {
		writeLines(filename, list, null, false);
	}
	
	/**
	 * 複数行を新規に書き出す
	 * @param filename - ファイル名
	 * @param encoding - エンコーディング
	 * @param list - 行
	 */
	public static void writeLines(String filename, List list, String encoding) throws IOException {
		writeLines(filename, list, encoding, false);
	}
	
	/**
	 * 複数行を追加で書き出す
	 * @param filename - ファイル名
	 * @param list - 行
	 */
	public static void appendLines(String filename, List list) throws IOException {
		writeLines(filename, list, null, true);
	}
	
	/**
	 * 複数行を追加で書き出す
	 * @param filename - ファイル名
	 * @param list - 行
	 * @param encoding - エンコーディング
	 */
	public static void appendLines(String filename, List list, String encoding) throws IOException {
		writeLines(filename, list, encoding, true);
	}
	
	/**
	 * ファイルを書き出す
	 * @param filename - ファイル名
	 * @param list - 行
	 * @param encoding - エンコーディング
	 * @param append - 追加フラグ
	 * @throws IOException
	 */
	private static void writeLines(String filename, List list, String encoding, boolean append) throws IOException {
		BufferedWriter bw = null;
		try {
			if (encoding != null) {
				bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(filename, append), encoding));
			} else {
				bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(filename, append)));
			}
			for (int i = 0; i < list.size(); i++) {
				String line = (String)list.get(i);
				bw.write(line);
				bw.newLine();
			}
			bw.flush();
		} finally {
			try { if (bw != null) bw.close(); } catch (Exception ee) {}
		}
	}

	/**
	 * テキストを新規に書き出す
	 * @param filename - ファイル名
	 * @param text - テキスト
	 * @throws IOException
	 */
	public static void writeFile(String filename, String text) throws IOException {
		writeFile(filename, text, null, false);
	}

	/**
	 * テキストを新規に書き出す
	 * @param filename - ファイル名
	 * @param text - テキスト
	 * @param encoding - エンコーディング
	 * @throws IOException
	 */
	public static void writeFile(String filename, String text, String encoding) throws IOException {
		writeFile(filename, text, encoding, false);
	}

	/**
	 * テキストを追加で書き出す
	 * @param filename - ファイル名
	 * @param text - テキスト
	 * @throws IOException
	 */
	public static void appendFile(String filename, String text) throws IOException {
		writeFile(filename, text, null, true);
	}
	
	/**
	 * テキストを追加で書き出す
	 * @param filename - ファイル名
	 * @param text - テキスト
	 * @param encoding - エンコーディング
	 * @throws IOException
	 */
	public static void appendFile(String filename, String text, String encoding) throws IOException {
		writeFile(filename, text, encoding, true);
	}
	
	/**
	 * テキストを書き出す
	 * @param filename - ファイル名
	 * @param text - テキスト
	 * @param encoding - エンコーディング
	 * @param append - 追加フラグ
	 * @throws IOException
	 */
	private static void writeFile(String filename, String text, String encoding, boolean append) throws IOException {
		BufferedWriter bw = null;
		try {
			if (encoding != null) {
				bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(filename, append), encoding));
			} else {
				bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(filename, append)));
			}
			bw.write(text);
			bw.flush();
		} finally {
			try { if (bw != null) bw.close(); }
			catch (Exception ee) { }
		}
	}

	/**
	 * 行を新規に一行書き出す
	 * @param filename - ファイル名
	 * @param line - 一行
	 * @throws IOException
	 */
	public static void writeLine(String filename, String line) throws IOException {
		writeLine(filename, line, null, false);
	}
	
	/**
	 * 行を新規に一行書き出す
	 * @param filename - ファイル名
	 * @param line - 一行
	 * @param encoding - エンコーディング
	 * @throws IOException
	 */
	public static void writeLine(String filename, String line, String encoding) throws IOException {
		writeLine(filename, line, encoding, false);
	}
	
	/**
	 * 行を追加で一行書き出す
	 * @param filename - ファイル名
	 * @param line - 一行
	 * @throws IOException
	 */
	public static void appendLine(String filename, String line) throws IOException {
		writeLine(filename, line, null, true);
	}
	
	/**
	 * 行を追加で一行書き出す
	 * @param filename - ファイル名
	 * @param line - 一行
	 * @param encoding - エンコーディング
	 * @throws IOException
	 */
	public static void appendLine(String filename, String line, String encoding) throws IOException {
		writeLine(filename, line, encoding, true);
	}
	
	/**
	 * 行を一行書き出す
	 * @param filename - ファイル名
	 * @param line - 一行
	 * @param encoding - エンコーディング
	 * @param append - 追加フラグ
	 * @throws IOException
	 */
	private static void writeLine(String filename, String line, String encoding, boolean append) throws IOException {
		BufferedWriter bw = null;
		try {
			if (encoding != null) {
				bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(filename, append), encoding));
			} else {
				bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(filename, append)));
			}
			bw.write(line);
			bw.write(ln);
			bw.flush();
		} finally {
			try { if (bw != null) bw.close(); } catch (Exception ee) {}
		}
	}
	
	/**
	 * ファイルをコピーする
	 * @param from
	 * @param to
	 * @throws IOException
	 */
	public static void copy(String from, String to) throws IOException {
		FileChannel fromChanell = new FileInputStream(from).getChannel();
		FileChannel toChannel = new FileOutputStream(to).getChannel();
		try {
			fromChanell.transferTo(0, fromChanell.size(), toChannel);
		} finally {
			fromChanell.close();
			toChannel.close();
		}
	}
	
}
