package hiro.yoshioka.util;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.StringReader;
import java.sql.ResultSet;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import jp.sf.orangesignal.csv.Csv;
import jp.sf.orangesignal.csv.CsvConfig;
import jp.sf.orangesignal.csv.handlers.ResultSetHandler;
import jp.sf.orangesignal.csv.handlers.StringArrayListHandler;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

public class CSVUtil {
	private static Log log = LogFactory.getLog(CSVUtil.class);
	public static final char SEPARETOR_HALF_SPACE = ' ';
	public static final char SEPARETOR_COMMA = ',';
	public static final char SEPARETOR_TAB = '\t';
	public static final char QUOTE_STRING_DOUBLE_QUOTE = '"';
	public static final char QUOTE_STRING_SINGLE_QUOTE = '\'';
	public static CsvConfig QUOTE_DOUBLE_QUOTE_SEPARATE_TAB = new CsvConfig(
			StringUtil.TAB_CHAR, '"', '"');
	public static CsvConfig QUOTE_DOUBLE_QUOTE_SEPARATE_COMMA = new CsvConfig(
			SEPARETOR_COMMA, '"', '"');
	static final Pattern SEPARATOR_PATTERN = Pattern.compile("[\"']?(,|\t)");

	static {
		QUOTE_DOUBLE_QUOTE_SEPARATE_TAB.setIgnoreEmptyLines(true);
		QUOTE_DOUBLE_QUOTE_SEPARATE_COMMA.setIgnoreEmptyLines(true);
	}

	public static boolean save(ResultSet rs, File file, String encoding,
			CsvConfig cfg) {
		ResultSetHandler handler = new ResultSetHandler();
		try {
			Csv.save(rs, new FileOutputStream(file), encoding, cfg, handler);
			return true;
		} catch (Exception e) {
			log.error(e);
		}
		return false;
	}

	public static String[][] splitByAuto_quoteDouble(String target) {
		if (getFrequentlyAppearingSeparetor(target) == SEPARETOR_TAB) {
			return split(target, QUOTE_DOUBLE_QUOTE_SEPARATE_TAB);
		}
		return split(target, QUOTE_DOUBLE_QUOTE_SEPARATE_COMMA);
	}

	public static String[][] splitByTAB_quoteDouble(String target) {
		return split(target, QUOTE_DOUBLE_QUOTE_SEPARATE_TAB);
	}

	public static String[][] splitByTAB_quoteDouble(File target, String encoding) {
		return split(target, encoding, QUOTE_DOUBLE_QUOTE_SEPARATE_TAB);
	}

	public static String[][] split(String target, CsvConfig config) {
		try {
			List<String[]> list = Csv.load(new StringReader(target), config,
					new StringArrayListHandler());
			return list.toArray(new String[list.size()][]);
		} catch (IOException e) {
			log.error(e);
		}
		return StringUtil.EMPTY_STRING_ARRAY2;
	}

	public static String[][] split(File target, String encoding,
			CsvConfig config) {
		try {
			BufferedReader in = null;
			if (StringUtil.isEmpty(encoding)) {
				in = new BufferedReader(new FileReader(target));
			} else {
				in = new BufferedReader(new InputStreamReader(
						new FileInputStream(target), encoding));
			}
			List<String[]> list = Csv.load(in, config,
					new StringArrayListHandler());
			return list.toArray(new String[list.size()][]);
		} catch (IOException e) {
			log.error(e);
		}
		return StringUtil.EMPTY_STRING_ARRAY2;
	}

	public static CsvConfig parseCsvConfig(String target) {
		CsvConfig ret = new CsvConfig(StringUtil.TAB_CHAR, '"', '"');
		for (String line : StringUtil.getLines(target)) {
			line = line.trim();
			if (line.startsWith("#") || line.length() == 0) {
				continue;
			}
			if (line.charAt(0) == QUOTE_STRING_SINGLE_QUOTE) {
				ret.setQuote(QUOTE_STRING_SINGLE_QUOTE);
			}
			ret.setSeparator(getFrequentlyAppearingSeparetor(line));
			break;
		}
		ret.setIgnoreEmptyLines(true);
		return ret;
	}

	public static char getFrequentlyAppearingSeparetor(String target) {
		Matcher m = SEPARATOR_PATTERN.matcher(target);
		int tab = 0, comma = 0;
		while (m.find()) {
			char c = m.group(1).charAt(0);
			switch (c) {
			case SEPARETOR_TAB:
				tab++;
				break;
			case SEPARETOR_COMMA:
				comma++;
				break;
			}
		}
		if (tab > comma) {
			return SEPARETOR_TAB;
		} else {
			return SEPARETOR_COMMA;
		}
	}
}
