/*
 * Copyright 2013 Yuichiro Moriguchi
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package net.morilib.sh;

import java.io.IOException;
import java.io.PrintStream;
import java.util.List;

import net.morilib.sh.misc.XtraceStream;

public class ShToken {

	private static enum S1 { INIT, ESC1, SQUT, DQUT, ESC2 }

	/**
	 * 
	 */
	public static final ShToken PIPE = new ShToken() {

		public int precedence() {
			return 10;
		}

		public String toString() {
			return "|";
		}

	};

	/**
	 * 
	 */
	public static final ShToken BG = new ShToken() {

		public int precedence() {
			return 50;
		}

		public String toString() {
			return "&";
		}

	};

	/**
	 * 
	 */
	public static final ShToken FG = new ShToken() {

		public int precedence() {
			return 50;
		}

		public boolean isEndOfLine() {
			return true;
		}

		public String toString() {
			return ";";
		}

	};

	/**
	 * 
	 */
	public static final ShToken CASEEND = new ShToken() {

		public int precedence() {
			return 50;
		}

		public String toString() {
			return ";;";
		}

	};

	/**
	 * 
	 */
	public static final ShToken NEWLINE = new ShToken() {

		public int precedence() {
			return 50;
		}

		public boolean isEndOfLine() {
			return true;
		}

		public String toString() {
			return "\\n";
		}

	};

	/**
	 * 
	 */
	public static final ShToken EOF = new ShToken() {

		public int precedence() {
			return 50;
		}

		public String toString() {
			return "<eof>";
		}

	};

	/**
	 * 
	 */
	public static final ShToken AND = new ShToken() {

		public int precedence() {
			return 30;
		}

		public String toString() {
			return "&&";
		}

	};

	/**
	 * 
	 */
	public static final ShToken OR = new ShToken() {

		public int precedence() {
			return 40;
		}

		public String toString() {
			return "||";
		}

	};

	/**
	 * 
	 */
	public static final ShToken PAREN_B = new ShToken() {

		public String toString() {
			return "(";
		}

	};

	/**
	 * 
	 */
	public static final ShToken PAREN_E = new ShToken() {

		public int precedence() {
			return 50;
		}

		public String toString() {
			return ")";
		}

	};

	/**
	 * 
	 * @return
	 */
	public boolean isString() {
		return false;
	}

	/**
	 * 
	 * @return
	 */
	public boolean isEndOfLine() {
		return false;
	}

	/**
	 * 
	 * @param keyword
	 * @return
	 */
	public boolean equalsKeyword(String keyword) {
		return false;
	}

	/**
	 * 
	 * @return
	 */
	public int precedence() {
		return -1;
	}

	/**
	 * 
	 * @return
	 */
	public List<ShToken> replaceBracket() {
		throw new UnsupportedOperationException();
	}

	/**
	 * 
	 * @param env
	 * @param s
	 * @return
	 */
	public static String replaceTilde(ShEnvironment env, String s) {
		if(s.equals("~")) {
			return env.find("HOME");
		} else if(s.startsWith("~/")) {
			return s.replaceFirst("^~", env.find("HOME"));
		} else {
			return s;
		}
	}

	/**
	 * 
	 * @param run
	 * @return
	 */
	public ShToken replaceTilde(ShEnvironment run) {
		throw new UnsupportedOperationException();
	}

	/**
	 * 
	 * @param env
	 * @return
	 */
	public List<ShToken> replaceParameter(ShEnvironment env,
			PrintStream err) {
		throw new UnsupportedOperationException();
	}

	/**
	 * 
	 * @param env
	 * @param run
	 * @return
	 */
	public ShToken replaceCommand(ShEnvironment env,
			ShFileSystem fs, ShRuntime run,
			XtraceStream p) throws IOException, ShSyntaxException {
		throw new UnsupportedOperationException();
	}

	/**
	 * 
	 * @param env
	 * @return
	 */
	public ShToken replaceArithmetic(
			ShEnvironment env) throws ShSyntaxException {
		throw new UnsupportedOperationException();
	}

	/**
	 * 
	 * @param ifs
	 * @return
	 */
	public List<String> splitWord(String ifs) {
		throw new UnsupportedOperationException();
	}

	/**
	 * 
	 * @return
	 */
	public boolean isFileRedirector() {
		return false;
	}

	/**
	 * 
	 * @return
	 */
	public boolean isDescriptorCopier() {
		return false;
	}

	/**
	 * 
	 * @return
	 */
	public boolean isHereDocument() {
		return false;
	}

	/**
	 * 
	 * @param name
	 * @return
	 */
	public static boolean isWildcard(String name) {
		S1 stat = S1.INIT;
		int c;

		for(int i = 0; i < name.length(); i++) {
			c = name.charAt(i);
			switch(stat) {
			case INIT:
				if(c == '*')   return true;
				if(c == '[')   return true;
				if(c == '?')   return true;
				if(c == '\'')       stat = S1.SQUT;
				else if(c == '\"')  stat = S1.DQUT;
				else if(c == '\\')  stat = S1.ESC1;
				break;
			case SQUT:
				if(c == '\'')  stat = S1.INIT;
				break;
			case DQUT:
				if(c == '\"')       stat = S1.INIT;
				else if(c == '\\')  stat = S1.ESC2;
				break;
			case ESC1:
				stat = S1.INIT;
				break;
			case ESC2:
				stat = S1.DQUT;
				break;
			}
		}
		return false;
	}

	/**
	 * 
	 * @return
	 */
	public boolean isWildcard() {
		return false;
	}

	/**
	 * 
	 * @param value
	 * @return
	 */
	public static boolean isBind(String value) {
		int c;

		for(int i = 0; i < value.length(); i++) {
			c = value.charAt(i);
			if(i > 0 && c == '=') {
				return true;
			} else if(!ShLexer.isId(c)) {
				return false;
			}
		}
		return false;
	}

	/**
	 * 
	 * @return
	 */
	public boolean isBind() {
		return false;
	}

	/**
	 * 
	 * @param env
	 * @param fs
	 * @param run
	 * @param err
	 * @param p
	 * @param v
	 * @throws IOException
	 * @throws ShSyntaxException
	 */
	public static void bindVariable(ShEnvironment env,
			ShFileSystem fs, ShRuntime run, PrintStream err,
			XtraceStream p,
			String v) throws IOException, ShSyntaxException {
		int x = v.indexOf('=');
		String s, t;

		s = v.substring(0, x);
		t = x < v.length() - 1 ? v.substring(x + 1) : "";
		if(env.isReadonly(s)) {
			err.print(s);
			err.println(": readonly variable");
		} else {
			env.bind(s, ShTrees.substitute(env, run, fs, err, p,
					new ShString(t)).toString());
		}
	}

	/**
	 * 
	 * @param env
	 * @param fs
	 * @param run
	 * @param err
	 * @param p
	 * @throws IOException
	 * @throws ShSyntaxException
	 */
	public void bindVariable(ShEnvironment env, ShFileSystem fs,
			ShRuntime run, PrintStream err,
			XtraceStream p) throws IOException, ShSyntaxException {
		throw new UnsupportedOperationException();
	}

}
