package ash.gui.core;
import java.util.List;
import java.util.ArrayList;
import java.io.File;
import java.io.IOException;
import java.io.BufferedWriter;
import java.awt.Component;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import javax.swing.JTextField;
import javax.swing.AbstractButton;
import ash.util.FileUtil;

/**
 * フォームデータの表示を管理する。
 */
public class AshForm extends AshGroupPanel implements ActionListener {
	protected int[] width;
	protected String[] title;
	protected FormModel model;

	public AshForm() {
		super(4, 2);
	}
	public AshForm(int[] width, String[] title, int rows) {
		this();
		reset(width, title, rows);
	}
	public AshForm(int[] width, String[] title, int rows, String fname) {
		this(width, title, rows);
		loadData(fname);
	}
	public void reset(int[] width, String[] title, int rows) {
		this.width = width;
		this.title = title;
		model = new FormModel(this);
		model.setRowSize(rows);
		construct(model.getTable());
	}
	private void construct(List<JTextField[]> table) {
		List<Object> formlist = new ArrayList<Object>();
		setActionListener(this);
		formlist.add((Object)makeTitle());
		Gap g = gap(2);
		for(int i = 0; i < table.size(); i++) {
			formlist.add((Object)g);
			formlist.add((Object)makeLine(i, table));
		}
		setPadding(4, 2);
		form(formlist.toArray());
	}
	private List makeTitle() {
		List<Component> list = new ArrayList<Component>();
		list.add(null);
		for(String s : title) list.add(label(s));
		return list;
	}
	private List makeLine(int lno, List<JTextField[]> table) {
		// 09 [field1] [field2] ... [fieldn] (発言)
		List<Component> list = new ArrayList<Component>();
		list.add(label(String.format("%2d", lno + 1)));
		for(JTextField f : table.get(lno)) list.add(f);
		addComponent(list, lno);
		return list;
	}

	public void loadData(String fname) {
		if(fname != null && !fname.isEmpty())
			model.loadData(fname);
	}
	public void clear(String filler) {
		model.clear(filler);
	}


	/**
	 * makeLine で設定したボタンの押下げ時に呼ばれる。
	 * テーブルの行番号が action として渡される。
	 */
	@Override public void actionPerformed(ActionEvent ae) {
		try {
			String action = ae.getActionCommand();
			AbstractButton b = (AbstractButton)ae.getSource(); // 押されたボタン
			doAction(b.getText(), Integer.parseInt(action));
		} catch(Exception e) {
			System.err.println(e.getMessage());
		}
	}
	/**
	 * Form の最後の列にコンポーネントを追加する。サブクラスでの拡張を想定。
	 * @param lno Form の行番号
	 * @param list この行番号のコンポーネントのリスト
	 */
	protected void addComponent(List<Component> list, int lno) {}
	/**
	 * 追加コンポーネントに対するアクションを処理する。サブクラスでの拡張を想定。
	 * @param text コンポーネントのテキスト
	 * @param lno Form の行番号
	 */
	protected void doAction(String text, int lno) {}
	
	/**
	 * １行分のフィールド配列を作成する。
	 * FormModel のテーブル拡張時に使用される。
	 */
	JTextField[] makeFields() {
		JTextField[] fields = new JTextField[width.length];
		for(int i = 0; i < fields.length; i++)
			fields[i] = field(width[i]);
		return fields;
	}

	/**
	 * テーブルデータを獲得／設定する
	 */
	public String getText(int lno, int column) {
		return getField(lno,column).getText();
	}
	public void setText(int lno, int column, String text) {
		getField(lno,column).setText(text);
	}
	public JTextField getField(int lno, int column) {
		return model.getTable().get(lno)[column];
	}
	public List<JTextField[]> getTable() {
		return model.getTable();
	}
	public List<String[]> getContents() {
		List<String[]> table = new ArrayList<String[]>();
		int rows = model.getTable().size();
		for(int i = 0; i < rows; i++) {
			String[] line = new String[width.length];
			boolean empty = true;
			for(int j = 0; j < width.length; j++) {
				line[j] = getText(i,j).trim();
				if(!line[j].isEmpty()) empty = false;
			}
			if(!empty) table.add(line);
		}
		return table;
	}

	/**
	 * テーブルの内容を tsv形式でファイルに書き出す
	 */
	public void saveData(String fname) {
		model.saveData(fname);
	}
}

/**
 * フォームのデータを JTextField の配列のリストとして管理する。
 * TSV形式(タブ分離形式)でファイルとの間でロード／セーブを行う。
 */
class FormModel {
	private List<JTextField[]> table;	// FormModel で管理するデータ
	private int lineNum = 0;			// データ設定済みの行数
	private AshForm view;				// フォームのビュー

	FormModel(AshForm view) {
		this.view = view;
		table = new ArrayList<JTextField[]>();
	}

	List<JTextField[]> getTable() { return table; }

	/**
	 * テーブルの行数を拡張する
	 * @param rows 拡張後の行数
	 */
	void setRowSize(int rows) {
		for(int i = table.size(); i < rows; i++)
			table.add(view.makeFields());
	}
	/**
	 * テーブルを初期化する。
	 */
	void clear(String filler) {
		for(JTextField[] row : table) {
			for(JTextField field : row) field.setText(filler);
		}
	}
	/**
	 * タブ分離された項目リストのリスト(.tsvファイル）からテーブルを作成する。
	 * @param fname .tsvファイルのファイル名
	 */
	boolean loadData(String fname) {
		String[] memberList = GUIAdapter.readTextFile(fname);
		if(memberList != null) {
			lineNum = 0;
			setRowSize(memberList.length);
			for(String line : memberList) {
				String[] items = line.split("\t");
				addData(items);
			}
			return true;
		}
		return false;
	}
	/**
	 * 一行の項目リストの文字列をフィールドに設定する
	 * @param items 項目リスト
	 */
	void addData(String[] items) {
		if(lineNum == table.size())
			table.add(view.makeFields());
		JTextField fields[] = table.get(lineNum);
		for(int i = 0; i < items.length; i++)
			fields[i].setText(items[i]);
		lineNum++;
	}
	/**
	 * テーブルの内容を tsv形式でファイルに書き出す
	 * @param fname tsv 形式ファイル名
	 */
	boolean saveData(String fname) {
		BufferedWriter writer = null;
		try {
			writer = GUIAdapter.openWriter(fname);
			for(JTextField[] fields : table) {
				CHECK: {
					for(JTextField field : fields) {
						String text = field.getText();
						if(text.length() > 0) break CHECK;
					}
					continue;
				}
				String[] items = new String[fields.length];
				for(int i = 0; i < fields.length; i++) {
					String item = fields[i].getText();
					if(i != 0) writer.write('\t');
					writer.write(item, 0, item.length());
				}
				writer.newLine();
			}
			return true;
		} catch(IOException e) {
			System.err.println(e);
			return false;
		} finally {
			try { if(writer != null) writer.close(); } catch(IOException e) {}
		}
	}
}
