package hiro.yoshioka.ast.sql.util;

import hiro.yoshioka.ast.sql.RowColumn;
import hiro.yoshioka.util.StringUtil;

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

public class BackWord {
	public static int LEVEL_SCHEMA = 1;
	public static int LEVEL_TABLE = 2;
	public static int LEVEL_COLUMN = 3;
	protected Log fLogger = LogFactory.getLog(this.getClass());

	String fTargetText;

	RowColumn fCursol;

	String[] words;

	boolean hasDot;

	boolean endOfDot;

	int offset;

	public BackWord(String targetText, RowColumn cursol) {
		offset = -1; // 余計に1足した値がRowCOlumnで指定されるから
		fTargetText = targetText;
		fCursol = cursol;
		if (fLogger.isDebugEnabled()) {
			fLogger.debug("TARGET[" + fTargetText + "]");
		}
		String back = backWord(fCursol, fTargetText);
		endOfDot = back.endsWith(".");
		if (hasDot) {
			words = back.split("[.]");
		} else {
			words = new String[] { back };
		}
	}

	/**
	 * 
	 * @param level
	 *            LEVEL_SCHEMA:1, LEVEL_TABLE:2, LEVEL_COLUMN:3
	 * @return 0:SCHEMA 1:TABLE 2:COLUMN
	 */
	public String[] getWords(int level) {
		String[] ret = new String[level];
		switch (level) {
		case 1:
			ret[0] = words[0];
			break;
		case 2:
			if (words.length == 1) {
				ret[0] = StringUtil.EMPTY_STRING;
				ret[1] = words[0];
			} else {
				ret[0] = words[0];
				ret[1] = words[1];
			}
			break;
		case 3:
			if (words.length >= 3) {
				for (int i = 0; i < ret.length; i++) {
					ret[i] = words[i];
				}
			} else if (words.length == 2) {
				ret[0] = StringUtil.EMPTY_STRING;
				ret[1] = words[0];
				ret[2] = words[1];
			} else {
				ret[0] = StringUtil.EMPTY_STRING;
				ret[1] = StringUtil.EMPTY_STRING;
				ret[2] = words[0];
			}
			break;
		}
		return ret;
	}

	public String backWord(RowColumn rl, String text) {
		String lsp = StringUtil.getThisLineSeparator(text);
		rl.fLineData = text.split(lsp, -1);
		for (int i = 0; i < rl.fLineData.length; i++) {
			if (i == rl._row - 1) {
				if (rl._column == 1) {
					offset += 1;
					return "";
				}
				if (rl._column - 2 > rl.fLineData[i].length()) {
					return "";
				}

				offset += rl._column;
				int docOffset = rl._column - 2;
				if (fLogger.isDebugEnabled()) {
					fLogger.debug("back[" + docOffset + "]:"
							+ rl.fLineData[i].charAt(docOffset) + " LINE[" + i
							+ "] LEN[" + rl.fLineData[i].length() + "]>"
							+ rl.fLineData[i]);
				}
				StringBuffer ret = new StringBuffer();
				for (; docOffset >= 0; docOffset--) {
					if (Character.isLetterOrDigit(rl.fLineData[i]
							.charAt(docOffset))
							|| (rl.fLineData[i].charAt(docOffset) == '_')) {
						ret.insert(0, rl.fLineData[i].charAt(docOffset));
					} else if (rl.fLineData[i].charAt(docOffset) == '.') {
						hasDot = true;
						ret.insert(0, rl.fLineData[i].charAt(docOffset));
					} else {
						break;
					}
				}

				return ret.toString();

			}
			offset += rl.fLineData[i].length() + lsp.length();
		}
		return "";
	}

	public int getOffset() {
		return offset;
	}

	public BackWord getNextBackWord() {
		RowColumn rc = fCursol.back();
		rc._column -= getAll().length();
		BackWord ret = new BackWord(fTargetText, rc);
		return ret;
	}

	public String getLastWord() {
		return words[words.length - 1];
	}

	public String getAll() {
		StringBuilder buf = new StringBuilder();
		for (int i = 0; i < words.length; i++) {
			if (i > 0) {
				buf.append(".");
			}
			buf.append(words[i]);
		}
		return buf.toString();
	}

	public boolean isFollow() {
		return getLastWord().trim().length() != 0;
	}

	public boolean startsWithOrFollow(String keys[]) {
		for (int i = 0; i < keys.length; i++) {
			if (keys[i].toUpperCase().startsWith(getLastWord().toUpperCase())) {
				return true;
			}
		}
		return isFollow();
	}

	public boolean startsWithOrNotFollow(String keys[]) {
		for (int i = 0; i < keys.length; i++) {
			if (keys[i].toUpperCase().startsWith(getLastWord().toUpperCase())) {
				return true;
			}
		}
		return !isFollow();
	}

	public boolean endOfDot() {
		return endOfDot;
	}

	public int getReplacementOffset(boolean useDotFlg) {
		if (useDotFlg && endOfDot) {
			return offset;
		}
		return offset - getLastWord().length();
	}

	public int getReplacementLength(boolean useDotFlg) {
		if (useDotFlg && endOfDot) {
			return 0;
		}
		return getLastWord().length();
	}

	public String toString() {
		return "back[" + getAll() + "] Flg:" + isFollow();
	}

}
