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

import java.util.Collections;

import net.morilib.automata.DFA;
import net.morilib.automata.NFAState;
import net.morilib.automata.dfa.ConvertedDFA;
import net.morilib.automata.dfa.DFAs;
import net.morilib.automata.regular.BasicRegex;
import net.morilib.nina.NinaParser;
import junit.framework.TestCase;

public class NinaSubAutomataTest extends TestCase {

	static void mat(NinaPattern m, String s) {
		NinaMatcher x;

		x = m.matcher(s);
		assertTrue(x.matches());
	}

	static void nmt(NinaPattern m, String s) {
		NinaMatcher x;

		x = m.matcher(s);
		assertFalse(x.matches());
	}

	static void drv(String s, boolean pause) {
		DFA<Object, NFAState, Void> d;
		NinaNFA n;
		NFABuilder a;
		NinaParser m;
		BasicRegex b;
		Quadro q;
		NinaAction o;

		q = Quadro.read("A", s, Collections.<String>emptyList());
		a = new NFABuilder();
		m = new NinaParser(q, a, Collections.<String, String>emptyMap(),
				new NinaSubautomata("a"),
				new NinaConsoleStub(), new NinaConsoleStub());
		try {
			while((o = m.step()) == null) {
				if(pause) {
//					System.in.read();
					m.printTrace(System.out);
				}
			}
			n = (NinaNFA)o.getMachine();
			System.out.print(n);
			d = ConvertedDFA.convertDFA(n);
			b = DFAs.convertToRegex(d);
			System.out.println(b);
			System.out.println("-------------------------------");
		} catch(Exception e) {
			m.printTrace(System.out);
			throw new RuntimeException(e);
		}
	}

	@SuppressWarnings("unchecked")
	static void drvd(String s, boolean pause) {
		DFA<Object, Object, Void> d;
		DFABuilder a;
		NinaParser m;
		BasicRegex b;
		Quadro q;
		Object o;

		q = Quadro.read("A", s, Collections.<String>emptyList());
		a = new DFABuilder();
		m = new NinaParser(q, a, Collections.<String, String>emptyMap(),
				new NinaSubautomata("a"),
				new NinaConsoleStub(), new NinaConsoleStub());
		try {
			while((o = m.step()) == null) {
				if(pause) {
//					System.in.read();
					m.printTrace(System.out);
				}
			}
			d = (DFA<Object, Object, Void>)o;
			b = DFAs.convertToRegex(d);
			System.out.println(b);
			System.out.println("-------------------------------");
		} catch(Exception e) {
			m.printTrace(System.out);
			throw new RuntimeException(e);
		}
	}

	public void test0001() {
		String s =
				"#machine NFABuilder\n" +
				" =======         @*****\n" +
				" =aaa  >--{t01}-->aa  *\n" +
				" ==^====         **v***\n" +
				"   \\--b------------/  \n" +
				"";
		drv(s, false);
	}

	public void test0002() {
		String s =
				"#machine NFABuilder\n" +
				" =======         @*****\n" +
				" =aaa  >--{t02}-->aa  *\n" +
				" =======         ******\n" +
				"";
		drv(s, false);
	}

	public void test0003() throws Exception {
		NinaPattern m;

		m = Nina.patternResource(
				"/net/morilib/nina/lib/t03.nina",
				Collections.<String, String>emptyMap(),
				new NinaSubautomata("a"),
				Collections.<String>emptyList(),
				new NinaConsoleStub());
		mat(m, "1");
		mat(m, "1+2");
		mat(m, "1+2+3");
		mat(m, "1+2*3+3");
	}

//	public void test0011() {
//		String s =
//				"#machine DFABuilder\n" +
//				" =======         ***   @@@\n" +
//				" =aaa  >--{d01}--> >-c-> @\n" +
//				" =======         ***   @@@\n" +
//				"";
//		drvd(s, false);
//	}
//
//	public void test0012() {
//		NinaPattern m;
//		String s =
//				"#machine DFABuilder\n" +
//				" =======         ***   @@@\n" +
//				" =aaa  >--{d01}--> >-c-> @\n" +
//				" =^=====         *v*   @@@\n" +
//				"  \\------d--------/\n" +
//				"";
//
//		m = Nina.pattern(s, Collections.<String, String>emptyMap(),
//				new NinaSubautomata("a"));
//		mat(m, "ac");
//		mat(m, "adbc");
//		mat(m, "adbdac");
//		nmt(m, "ad");
//	}
//
//	public void test0013() {
//		String s =
//				"#machine DFABuilder\n" +
//				" =======         ***   @@@\n" +
//				" =aaa  >--{d01}--> >-c-> @\n" +
//				" =v=====         *^*   @@@\n" +
//				"  \\------d--------/\n" +
//				"";
//
//		try {
//			Nina.pattern(s, Collections.<String, String>emptyMap(),
//					new NinaSubautomata("a"));
//			fail();
//		} catch(NinaException e) {
//			e.printStackTrace();  // ok
//		}
//	}
//
//	public void test0014() {
//		String s =
//				"#machine DFABuilder\n" +
//				"  /------d--------\\\n" +
//				" =^=====         *v*   @@@\n" +
//				" =aaa  >--{d01}--> >-c-> @\n" +
//				" =======         ***   @@@\n" +
//				"";
//
//		try {
//			Nina.pattern(s, Collections.<String, String>emptyMap(),
//					new NinaSubautomata("a"));
//			fail();
//		} catch(NinaException e) {
//			e.printStackTrace();  // ok
//		}
//	}
//
//	public void test0015() {
//		NinaPattern m;
//		String s =
//				"#machine DFABuilder\n" +
//				"  /------d--------------\\\n" +
//				" =^=====         ***   @v@\n" +
//				" =aaa  >--{d01}--> >-c->c@\n" +
//				" =======         ***   @@@\n" +
//				"";
//
//		m = Nina.pattern(s, Collections.<String, String>emptyMap(),
//				new NinaSubautomata("a"));
//		mat(m, "d");
//		mat(m, "ac");
//		nmt(m, "ad");
//	}

	public void test0021() {
		NinaPattern m;
		String s =
				"#machine NFABuilder\n" +
				" =======                @*****\n" +
				" =aaa  >--{t06(a,'b')}-->aa  *\n" +
				" =======                ******\n" +
				"";

		m = Nina.pattern("A", s, Collections.<String, String>emptyMap(),
				new NinaSubautomata("a"),
				new NinaConsoleStub());
		mat(m, "a");
		mat(m, "aba");
	}

	public void test0022() {
		NinaPattern m;
		String s =
				"#machine NFABuilder\n" +
				" @@@@@@@                ======\n" +
				" @aaa  <--{t06(a,'b')}--<aa  =\n" +
				" @@@@@@@                ======\n" +
				"";

		m = Nina.pattern("A", s, Collections.<String, String>emptyMap(),
				new NinaSubautomata("a"),
				new NinaConsoleStub());
		mat(m, "a");
		mat(m, "aba");
	}

	public void test0031() {
		NinaPattern m;
		String s =
				"#machine NFABuilder\n" +
				"  /------d--------------\\\n" +
				" =^=====         ***   @v@\n" +
				" =aaa  >--{d01}--> >-c->c@\n" +
				" =======         ***   @@@\n" +
				"";

		m = Nina.pattern("A", s, Collections.<String, String>emptyMap(),
				new NinaSubautomata("a"),
				new NinaConsoleStub());
		mat(m, "d");
		mat(m, "ac");
		nmt(m, "ad");
	}

	public void test0032() {
		NinaPattern m;
		String s =
				"#machine NFABuilder\n" +
				"  /------d--------------\\\n" +
				" =^=====         ***   @v@\n" +
				" =aaa  >--{d01}--> >-c->c@\n" +
				" =^=====         *v*   @@@\n" +
				"  \\------e--------/" +
				"";

		m = Nina.pattern("A", s, Collections.<String, String>emptyMap(),
				new NinaSubautomata("a"),
				new NinaConsoleStub());
		mat(m, "d");
		mat(m, "ac");
		mat(m, "aebc");
		mat(m, "aebed");
		nmt(m, "ad");
	}

}
