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

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.PrintStream;
import java.io.StringReader;
import java.math.BigDecimal;

import junit.framework.TestCase;

public class DcTest extends TestCase {

	void eqn(String s, String t) {
		DcModel v = new DcDefaultModel(System.in, System.out);
		DcParser<DcModel> p = new DcParser<DcModel>(
				DcInterpreter.getInstance(), v);

		try {
			p.parse(new StringReader(s));
			assertEquals(new BigDecimal(t), v.pop());
		} catch (IOException e) {
			throw new RuntimeException(e);
		}
	}

	void eqs(String s, String t) {
		DcModel v = new DcDefaultModel(System.in, System.out);
		DcParser<DcModel> p = new DcParser<DcModel>(
				DcInterpreter.getInstance(), v);

		try {
			p.parse(new StringReader(s));
			assertEquals(t, v.pop());
		} catch (IOException e) {
			throw new RuntimeException(e);
		}
	}

	void eqp(String s, String t) {
		ByteArrayOutputStream ous = new ByteArrayOutputStream();
		PrintStream ps = new PrintStream(ous);
		DcModel v = new DcDefaultModel(System.in, ps);
		DcParser<DcModel> p = new DcParser<DcModel>(
				DcInterpreter.getInstance(), v);

		try {
			p.parse(new StringReader(s));
			assertEquals(t, new String(ous.toByteArray()));
		} catch (IOException e) {
			throw new RuntimeException(e);
		}
	}

	void eqb(String s, String t) {
		ByteArrayOutputStream ous = new ByteArrayOutputStream();
		PrintStream ps = new PrintStream(ous);
		DcModel v = new DcDefaultModel(System.in, ps);
		DcParser<DcModel> p = new DcParser<DcModel>(
				DcInterpreter.getInstance(), v);

		try {
			p.parse(new StringReader(s));
			assertEquals(t, new String(ous.toByteArray(), "ISO-8859-1"));
		} catch (IOException e) {
			throw new RuntimeException(e);
		}
	}

	public void testDc001() {
		eqn("1", "1");
		eqn("12", "12");
		eqn("12.1", "12.1");
		eqn("12.5", "12.5");
		eqn("12.6", "12.6");
		eqn("_1", "-1");
		eqn(".5", "0.5");
		eqn("_.5", "-0.5");
	}

	public void testDc002() {
		eqn("72 2+", "74");
		eqn("2 72+", "74");
		eqn("72 2-", "70");
		eqn("2 72-", "-70");
		eqn("72 2*", "144");
		eqn("2 72*", "144");
		eqn("72 2/", "36");
		eqn("2 72/", "0");
		eqn("72 30%", "12");
		eqn("30 72%", "30");
		eqn("5 2^", "25");
		eqn("2 5^", "32");
	}

	public void testDc003() {
		eqn("7 6 5++", "18");
		eqn("7 6 5-+", "8");
		eqn("7 6 5+-", "-4");
		eqn("7 6 5++8-", "10");
	}

	public void testDc004() {
		eqn("72 30~-", "-10");
	}

	public void testDc005() {
		eqn("2 5 7|", "4");
	}

	public void testDc006() {
		eqn("841v", "29");
		eqn("961v", "31");
	}

	public void testDc007() {
		eqn("3d+", "6");
		eqn("3dd++", "9");
	}

	public void testDc008() {
		eqn("3 4r-", "1");
	}

	public void testDc009() {
		eqn("2sA3sBlBlA-", "1");
	}

	public void testDc010() {
		eqn("2SA3SALALA-", "1");
	}

	public void testDc011() {
		eqn("4k1", "1");
		eqn("4kK", "4");
		eqn("4k8.41v", "2.9000");
		eqn("4k2v", "1.4142");
		eqn("4k4 3/", "1.3333");
		eqn("4k5 3/", "1.6667");
	}

	public void testDc012() {
		eqs("[haruka]", "haruka");
		eqs("[haruka[SR]]", "haruka[SR]");
		eqs("[]", "");
	}

	public void testDc013() {
		eqs("32a", " ");
		eqs("[haruka]a", "h");
	}

	public void testDc014() {
		eqn("[7 6 5++]x", "18");
		eqn("[7 6 [5 7 3++]x++]x", "28");
		eqn("[7 6 5++]x[5 7 3++]x+", "33");
	}

	public void testDc015() {
		eqn("[7 6 5++]sA0 2 7<A",  "18");
		eqn("[7 6 5++]sA0 2 7!<A", "0");
		eqn("[7 6 5++]sA0 2 7>A",  "0");
		eqn("[7 6 5++]sA0 2 7!>A", "18");
		eqn("[7 6 5++]sA0 2 7=A",  "0");
		eqn("[7 6 5++]sA0 2 7!=A", "18");

		eqn("[7 6 5++]sA0 7 7<A",  "0");
		eqn("[7 6 5++]sA0 7 7!<A", "18");
		eqn("[7 6 5++]sA0 7 7>A",  "0");
		eqn("[7 6 5++]sA0 7 7!>A", "18");
		eqn("[7 6 5++]sA0 7 7=A",  "18");
		eqn("[7 6 5++]sA0 7 7!=A", "0");

		eqn("[7 6 5++]sA0 7 2<A",  "0");
		eqn("[7 6 5++]sA0 7 2!<A", "18");
		eqn("[7 6 5++]sA0 7 2>A",  "18");
		eqn("[7 6 5++]sA0 7 2!>A", "0");
		eqn("[7 6 5++]sA0 7 2=A",  "0");
		eqn("[7 6 5++]sA0 7 2!=A", "18");
	}

	public void testDc016() {
		eqn("3q9", "3");
		eqn("[3q9]x4+", "7");
		eqn("[[3q9]xq9]x4+", "7");
	}

	public void testDc017() {
		eqn("[[[[4 1Q9]x4+]x4+]x4+]x4+", "20");
		eqn("[[[[4 2Q9]x4+]x4+]x4+]x4+", "16");
		eqn("[[[[4 3Q9]x4+]x4+]x4+]x4+", "12");
		eqn("[[[[4 4Q9]x4+]x4+]x4+]x4+", "8");
		eqn("[[[[4 5Q9]x4+]x4+]x4+]x4+", "8");
	}

	public void testDc018() {
		eqn("765Z", "3");
		eqn("[haruka]Z", "6");
		eqn("4k765.73Z", "5");
	}

	public void testDc019() {
		eqn("765X", "0");
		eqn("[haruka]X", "0");
		eqn("4k765.73X", "2");
	}

	public void testDc020() {
		eqn("# comment\n1", "1");
	}

	public void testDc021() {
		eqp("765p", "765\r\n");
		eqp("4k765.73p", "765.73\r\n");
		eqp("765n", "765");
		eqp("4k765.73n", "765.73");
	}

	public void testDc022() {
		eqp("[765]P", "765");
		eqb("765P", "\u0002\u00fd");
	}

	public void testDc201() {
		eqn( "0R4k4 3/", "1.3333");
		eqn( "1R4k4 3/", "1.3334");
		eqn("_1R4k4 3/", "1.3333");

		eqn( "0R4k5 3/", "1.6667");
		eqn( "1R4k5 3/", "1.6667");
		eqn("_1R4k5 3/", "1.6666");
	}

}
