package ash.gui.editor.core;
import java.io.File;
import java.io.IOException;
import java.io.FileNotFoundException;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileReader;
import java.io.FileWriter;
import java.awt.Font;
import java.awt.Component;
//import java.awt.FontMetrics;
//import java.awt.event.MouseEvent;
import ash.util.FileUtil;
import ash.gui.core.AshFont;
import ash.gui.core.GUIAdapter;

/*
 * エディタ編集領域
 */
abstract public class AshEditorArea {
	static private File prevFile = GUIAdapter.findFile(".");// 直前の編集ファイル
	private File currentFile = null;					// 現在編集中のファイル
	private boolean modified = false;
	protected Font font = AshFont.getFont();
	protected AshEditorFrame editFrame;

	public AshEditorArea(AshEditorFrame frame) {
		editFrame = frame;
	}

	/*
	 * 各種アクセッサ（主に AshEditorFrame から利用される）
	 */
	File getCurrentDirectory() {
		if(currentFile != null && currentFile.exists())
			prevFile = currentFile;
		return prevFile;
	}
	public File getCurrentFile() {
		return currentFile;
	}
	protected void setCurrentFile(File file) {
		currentFile = file;
		setModified(false);
	}
	void setFileName(String filename) {
		currentFile = new File(filename);
		setModified(true);
	}
	boolean isModified() {
		return modified;
	}
	public void setModified(boolean modified) {
		this.modified = modified;
		String readOnlyMsg = !isEditable() ? "（読み込み専用）" : "";
		String fname =
			(currentFile != null) ? FileUtil.getPath(currentFile) : "(無題)";
		String title = fname + readOnlyMsg;
		if(modified) title += " *";
		editFrame.notifyUpdate(this, title);
	}
	protected void setFont() {
		font = AshFontPanel.updateFont(editFrame, font);
		setFont(font);
	}

	/*
	 * テキストの読み込みと書き出し
	 */
	private static int untitledSeq = 0;
	private static String nextUndefined() {
		return String.format("Untitled%02d", untitledSeq++);
	}
	void newFile() {
		resetDocument();
		setEditable(true);
		File file = getCurrentDirectory();
		if(!file.isDirectory()) file = file.getParentFile();
		file = new File(file, nextUndefined());
		setCurrentFile(file);
	}
	boolean openFile(File file) {
		if(file.isFile()) return openReadFile(file);
		if(file.isDirectory()) {
			file = new File(file, nextUndefined());
		} else if(file.exists()) {
			return false;
		}
		resetDocument();
		setEditable(true);
		setCurrentFile(file);
		return true;
	}
	boolean openReadFile(File file) {
		BufferedReader br = null;
		try {
			br = new BufferedReader(new FileReader(file));
			readDocument(br, file);
			setEditable(file.canWrite());
			setCurrentFile(file);
			return true;
		} catch(FileNotFoundException e) {
			editFrame.showError("読み込みができません", e.toString());
		} catch(IOException e) {
			editFrame.showError("入出力エラーが発生しました", e.toString());
		} finally {
			if(br != null) try { br.close(); } catch(IOException e) {}
		}
		return false;
	}
	boolean writeFile() {
		return writeFile(currentFile);
	}
	boolean writeFile(File file) {
		BufferedWriter bw = null;
		try {
			bw = new BufferedWriter(new FileWriter(file));
			writeDocument(bw, file);
			setEditable(true);
			setCurrentFile(file);
			return true;
		} catch(FileNotFoundException e) {
			editFrame.showError("書き出しができません", e.toString());
		} catch (IOException e) {
			editFrame.showError("入出力エラーが発生しました", e.toString());
		} finally {
			if(bw != null) try { bw.close(); } catch(IOException e) {}
		}
		return false;
	}

	/*
	 * 行移動
	 */
	void gotoLine() {
		while(true) {
			try {
				String ans = editFrame.inputDialog("行番号", "行へ移動");
				if(ans != null) {
					int lineNum = Integer.valueOf(ans).intValue();
					if(!showLine(lineNum - 1))
						editFrame.showMessage("行番号が範囲外です");
				}
				return;
			} catch(NumberFormatException e) {
				editFrame.showError("数字を入力してください", e.toString());
			}
		}
	}

	/**
	 * 編集コンポーネント(JTextやJTable)とのインタフェース
	 */
	abstract protected Component getEditArea();
	abstract protected void setEditable(boolean editable);
	abstract protected boolean isEditable();
	abstract protected boolean isSelectable();
	abstract protected void setRowColumn(int rows, int columns);
	abstract protected void setFont(Font font);
	abstract protected void setTextData(String text);
	abstract public boolean isSelected();
	abstract public String getSelectedText();
	abstract protected int getLineCount();
	abstract protected boolean showLine(int lno);
	abstract protected void copy();
	abstract protected void cut();
	abstract protected void paste();
	abstract protected void delete();
	abstract protected void selectAll();
	abstract protected void resetDocument();
	abstract protected void readDocument(BufferedReader br, File file)
								throws IOException;
	abstract protected void writeDocument(BufferedWriter bw, File file)
								throws IOException;
	/*
	 * アンドゥ、リドゥのアダプタ
	 */
	public void undo() {}
	public void redo() {}
	public boolean canUndo() { return false; }
	public boolean canRedo() { return false; }
}
