/*
 * 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.awk.code;

import net.morilib.awk.expr.AwkExpression;
import net.morilib.awk.io.AwkFiles;
import net.morilib.awk.namespace.AwkNamespace;
import net.morilib.awk.pattern.AwkMatchState;
import net.morilib.awk.pattern.AwkPattern;
import net.morilib.awk.value.AwkUndefined;
import net.morilib.awk.value.AwkValue;

/**
 * awkiumのアクションをあらわす中間表現です。
 * 
 * @author MORIGUCHI, Yuichiro 2013/03
 */
public class AwkAction implements AwkExecutable {

	static final AwkExpression DEFAULT = new AwkExpression() {

		@Override
		public AwkValue eval(AwkNamespace ns, AwkFiles f) {
			f.getStdout().print(ns.referField(0).toString(ns));
			f.getStdout().print(ns.getORS());
			return AwkUndefined.UNDEF;
		}

	};

	private AwkPattern pattern;
	private AwkExpression action;
	private AwkMatchState stat = AwkMatchState.NO_MATCH;
	private transient AwkExpression compiled = null;

	/**
	 * アクションを生成します。
	 * 
	 * @param pattern パターン
	 * @param action  式(文)
	 */
	public AwkAction(AwkPattern pattern, AwkExpression action) {
		this.pattern = pattern;
		this.action  = action;
	}

	/**
	 * アクションを実行します。
	 * 
	 * @see net.morilib.awk.code.AwkExecutable#execute(net.morilib.awk.namespace.AwkNamespace, net.morilib.awk.io.AwkFiles, java.lang.String)
	 */
	public synchronized void execute(AwkNamespace ns, AwkFiles f,
			String s) {
		AwkMatchState m;

		if(compiled == null) {
			compiled = action != null ?
					action.compileInternally() : DEFAULT;
		}

		if(pattern == null) {
			compiled.eval(ns, f);
		} else if(pattern.isRanged()) {
			m = stat;
			stat = pattern.match(ns, f, s, stat);
			if(stat.equals(AwkMatchState.IS_MATCHING) ||
					m.equals(AwkMatchState.IS_MATCHING)) {
				compiled.eval(ns, f);
			}
		} else if(!pattern.match(ns, f, s, stat).isNotMatched()) {
			compiled.eval(ns, f);
		}
	}

	/**
	 * BEGINアクションを実行します。
	 * 
	 * @see net.morilib.awk.code.AwkExecutable#executeBegin(net.morilib.awk.namespace.AwkNamespace, net.morilib.awk.io.AwkFiles)
	 */
	public void executeBegin(AwkNamespace ns, AwkFiles f) {
		if(isBegin())  action.eval(ns, f);
	}

	/**
	 * ENDアクションを実行します。
	 * 
	 * @see net.morilib.awk.code.AwkExecutable#executeEnd(net.morilib.awk.namespace.AwkNamespace, net.morilib.awk.io.AwkFiles)
	 */
	public void executeEnd(AwkNamespace ns, AwkFiles f) {
		if(isEnd())  action.eval(ns, f);
	}

	/* (non-Javadoc)
	 * @see net.morilib.awk.code.AwkExecutable#isBegin()
	 */
	public boolean isBegin() {
		return pattern != null && pattern.isBegin();
	}

	/* (non-Javadoc)
	 * @see net.morilib.awk.code.AwkExecutable#isEnd()
	 */
	public boolean isEnd() {
		return pattern != null && pattern.isEnd();
	}

}
