/*
 * 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;

import java.io.IOException;

import net.morilib.awk.parser.AwkParser;
import net.morilib.awk.pattern.AwkMatchState;
import net.morilib.awk.pattern.AwkPattern;

public class AwkPatternTest extends AwkTestCase {

	static final AwkMatchState N = AwkMatchState.NO_MATCH;
	static final AwkMatchState I = AwkMatchState.IS_MATCHING;
	static final AwkMatchState D = AwkMatchState.MATCHED;

	void mts(String l, String s) {
		try {
			ns0.setField(s);
			assertFalse(AwkParser.parsePattern(lex(l)).match(ns0, fs0, s, AwkMatchState.NO_MATCH).isNotMatched());
		} catch (IOException e) {
			throw new RuntimeException(e);
		}
	}

	void nmt(String l, String s) {
		try {
			ns0.setField(s);
			assertTrue(AwkParser.parsePattern(lex(l)).match(ns0, fs0, s, AwkMatchState.NO_MATCH).isNotMatched());
		} catch (IOException e) {
			throw new RuntimeException(e);
		}
	}

	AwkPattern cpl(String l) {
		try {
			return AwkParser.parsePattern(lex(l));
		} catch (IOException e) {
			throw new RuntimeException(e);
		}
	}

	AwkMatchState mts(AwkPattern p, String d, AwkMatchState t, AwkMatchState s) {
		AwkMatchState z;

		ns0.setField(d);
		assertEquals(z = p.match(ns0, fs0, d, t), s);
		return z;
	}

	static void bgn(String l) {
		try {
			assertTrue(AwkParser.parsePattern(lex(l)).isBegin());
		} catch (IOException e) {
			throw new RuntimeException(e);
		}
	}

	static void end(String l) {
		try {
			assertTrue(AwkParser.parsePattern(lex(l)).isEnd());
		} catch (IOException e) {
			throw new RuntimeException(e);
		}
	}

	static void nbg(String l) {
		try {
			assertFalse(AwkParser.parsePattern(lex(l)).isBegin());
		} catch (IOException e) {
			throw new RuntimeException(e);
		}
	}

	static void ned(String l) {
		try {
			assertFalse(AwkParser.parsePattern(lex(l)).isEnd());
		} catch (IOException e) {
			throw new RuntimeException(e);
		}
	}

	public void testRanged01() {
		AwkMatchState z = AwkMatchState.NO_MATCH;
		AwkPattern p = cpl("/a+/, /b+/");

		z = mts(p, "bbbbb", z, N);
		z = mts(p, "baaab", z, D);
		z = mts(p, "aaaaa", z, D);
		z = mts(p, "", z, D);
		z = mts(p, "abbba", z, D);
		z = mts(p, "bbbba", z, D);
	}

	public void testRanged02() {
		AwkMatchState z = AwkMatchState.NO_MATCH;
		AwkPattern p = cpl("/a+/, /b+/");

		z = mts(p, "bbbbb", z, N);
		z = mts(p, "aaaaa", z, I);
		z = mts(p, "aaaaa", z, I);
		z = mts(p, "", z, I);
		z = mts(p, "abbba", z, D);
		z = mts(p, "bbbba", z, D);
	}

	public void testSimple01() {
		mts("/a+/", "aaaaa");
		mts("/a+/", "baaaaa");
		mts("/a+/", "aaaab");
		mts("/a+/", "baaaab");
		nmt("/a+/", "bbb");
		nmt("/a+/", "");
		bgn("BEGIN");
		nbg("END");
		nbg("/a+/");
		end("END");
		ned("BEGIN");
		ned("/a+/");
	}

	public void testSimple02() {
		mts("$1 == \"bbb\"", "  bbb ccc  ddd  ");
		nmt("$1 != \"bbb\"", "  bbb ccc  ddd  ");
		mts("$2 == \"ccc\"", "  bbb ccc  ddd  ");
		mts("$3 == \"ddd\"", "  bbb ccc  ddd  ");
	}

	public void testSimple03() {
		mts("/^$/", "");
		nmt("/^$/", "aaaa");
	}

	public void testAnd() {
		mts("/a+/ && /b+/", "aaabbb");
		nmt("/a+/ && /b+/", "aaa");
		nmt("/a+/ && /b+/", "bbb");
		nmt("/a+/ && /b+/", "ccc");
	}

	public void testOr() {
		mts("/a+/ || /b+/", "aaabbb");
		mts("/a+/ || /b+/", "aaa");
		mts("/a+/ || /b+/", "bbb");
		nmt("/a+/ || /b+/", "ccc");
	}

	public void testAndOr() {
		mts("/a+/ && /b+/ || /c+/", "aaabbb");
		mts("/a+/ && /b+/ || /c+/", "ccc");
		nmt("/a+/ && (/b+/ || /c+/)", "ccc");
		mts("/a+/ && (/b+/ || /c+/)", "aaaccc");
		mts("/a+/ && (/b+/ || /c+/)", "aaabbb");
		mts("!/a+/ && !/b+/ || !/c+/", "cccddd");
		mts("!/a+/ && !(/b+/ || /c+/)", "ddd");
		nmt("!/a+/ && !(/b+/ || /c+/)", "cccddd");
	}

	public void testNot() {
		nmt("!/a+/", "aaaaa");
		mts("!/a+/", "bbbbv");
		mts("!/^$/", "aa");
		nmt("!/^$/", "");
	}

}
