package sdsi;

import sdsi.sexp.*;
import java.io.*;
import Tools.Options;

/**
 * This class has a bunch of test cases to verify my implementation
 * of Tags.
 */
public class TagTest {
	static String[] examples = {
	"star",			"(tag *)",
	"null",			"(tag (* null))",
	"shortlist",	"(tag (cat dog))",
	"longlist",		"(tag (cat dog mouse))",
	"starlist",		"(tag (cat (*) mouse))",
	"otherlist",	"(tag (rat dog mouse))",
	"set1",			"(tag (* set cat dog mouse))",
	"set2",			"(tag (* set rat dog mouse))",
	"set3",			"(tag (* set dog mouse))",
	"range1",		"(tag (* range alpha gt cat))",
	"range2",		"(tag (* range alpha ge cat))",
	"range3",		"(tag (* range alpha lt mouse))",
	"range4",		"(tag (* range alpha le mouse))",
	"rtestlow",		"(tag bat)",
	"rtestge",		"(tag cat)",
	"rtestmid1",	"(tag cats)",
	"rtestmid2",	"(tag hat)",
	"rtestmid3",	"(tag mous)",
	"rtestle",		"(tag mouse)",
	"rtesthi",		"(tag skunk)",
	"range5",		"(tag (* range alpha gt cat le mouse))",
	"range6",		"(tag (* range alpha le mouse gt cat ))",
	"prefix1",		"(tag (* prefix sk))",
	"prefix2",		"(tag (* prefix skun))",
	"skunk",		"(tag skunk)"
	};
	static int getNumExamples() {
		return examples.length/2;
	}
	static String[] getExample(int i) {
		return new String[] {
			examples[i*2+0],
			examples[i*2+1] };
	}
	static String getExample(String name) {
		for (int i=0; i<getNumExamples(); i++) {
			if (getExample(i)[0].equals(name)) {
				return getExample(i)[1];
			}
		}
		return "";
	}
	static Tag getExampleTag(String name) {
		try {
			String sexpStr = getExample(name);
			PushbackInputStream pis = new PushbackInputStream(
				new ByteArrayInputStream(sexpStr.getBytes()));
			Sexp sexp = Sexp.parse(pis);
			Tag tag = new Tag((SexpList) sexp);
			return tag;
		} catch (Exception ex) {
			ex.printStackTrace();
		}
		return null;
	}

	static String[] relationships = {
	"star",			"shortlist",	">",
	"shortlist",	"longlist",		">",
	"longlist",		"otherlist",	"!=",
	"longlist",		"starlist",		"<",
	"set1",			"set2",			"!=",
	"set1",			"set3",			">",
	"set2",			"set3",			">",

	"range1",		"rtestlow",		"!=",
	"range1",		"rtestge",		"!=",
	"range1",		"rtestmid1",	">",
	"range1",		"rtestmid2",	">",
	"range1",		"rtestmid3",	">",
	"range1",		"rtestle",		">",
	"range1",		"rtesthi",		">",

	"range2",		"rtestlow",		"!=",
	"range2",		"rtestge",		">",
	"range2",		"rtestmid1",	">",
	"range2",		"rtestmid2",	">",
	"range2",		"rtestmid3",	">",
	"range2",		"rtestle",		">",
	"range2",		"rtesthi",		">",

	"range3",		"rtestlow",		">",
	"range3",		"rtestge",		">",
	"range3",		"rtestmid1",	">",
	"range3",		"rtestmid2",	">",
	"range3",		"rtestmid3",	">",
	"range3",		"rtestle",		"!=",
	"range3",		"rtesthi",		"!=",

	"range4",		"rtestlow",		">",
	"range4",		"rtestge",		">",
	"range4",		"rtestmid1",	">",
	"range4",		"rtestmid2",	">",
	"range4",		"rtestmid3",	">",
	"range4",		"rtestle",		">",
	"range4",		"rtesthi",		"!=",

	"prefix1",		"prefix2",		">",
	"prefix2",		"skunk",		">"
	};
	static int getNumRelationships() {
		return relationships.length/3;
	}
	static String[] getRelationship(int i) {
		return new String[] {
			relationships[i*3+0],
			relationships[i*3+1],
			relationships[i*3+2] };
	}

	static String[] intersections = {
	"star",			"shortlist",	"shortlist",
	"shortlist",	"longlist",		"longlist",
	"longlist",		"otherlist",	"null",
	"longlist",		"starlist",		"longlist",
	"set1",			"set2",			"set3",
	"range1",		"range2",		"range1",
	"range3",		"range4",		"range3",
	"range1",		"range4",		"range5",
	"range5",		"range6",		"range5",
	"prefix1",		"prefix2",		"prefix2",
	"prefix1",		"skunk",		"skunk",
	"prefix2",		"skunk",		"skunk"
	};
	static int getNumIntersections() {
		return intersections.length/3;
	}
	static String[] getIntersection(int i) {
		return new String[] {
			intersections[i*3+0],
			intersections[i*3+1],
			intersections[i*3+2] };
	}

	static String[] resultTable = { "!=", ">", "<", "==" };

	static boolean testRelationships(Options opts) {
		boolean error = false;
		for (int ri = 0; ri<getNumRelationships(); ri++) {
			String[] rel = getRelationship(ri);
			Tag tag0 = getExampleTag(rel[0]);
			Tag tag1 = getExampleTag(rel[1]);
			int val=0;
			if (opts.getBoolean("verbose")) {
				System.out.println();
				System.out.println("Testing "
					+rel[0]+": "+tag0.toReadableString(72));
				System.out.println("     vs "
					+rel[1]+": "+tag1.toReadableString(72));
				System.out.println("Intersection is: "
					+tag0.intersect(tag1).toReadableString(72));
			}
			if (tag0.hasSubset(tag1)) {
				val|=1;
			}
			if (tag1.hasSubset(tag0)) {
				val|=2;
			}
			String result = resultTable[val];
			if (opts.getBoolean("verbose")) {
				System.out.println("result is: "+result);
			}
			if (!result.equals(rel[2])) {
				System.out.println(rel[0]+" "+result+" "+rel[1]
					+"; expected "+rel[2]);
				error = true;
			}
		}
		return error;
	}

	static boolean testIntersections(Options opts) {
		boolean error = false;
		for (int ii = 0; ii<getNumIntersections(); ii++) {
			String[] intExample = getIntersection(ii);
			Tag tag0 = getExampleTag(intExample[0]);
			Tag tag1 = getExampleTag(intExample[1]);
			Tag tag2 = getExampleTag(intExample[2]);

			String tagName2 = tag2.toReadableString(72);

			Tag tag01 = tag0.intersect(tag1);
			Tag tag10 = tag1.intersect(tag0);

			String tagName01 = tag01.toReadableString(72);
			String tagName10 = tag10.toReadableString(72);

			if (opts.getBoolean("verbose")) {
				System.out.println();
				System.out.println("tag0 "+intExample[0]
					+": "+tag0.toReadableString(72));
				System.out.println("tag1 "+intExample[1]
					+": "+tag1.toReadableString(72));
				System.out.println("want "+intExample[2]
					+": "+tagName2);
				System.out.println("got 0 ^ 1: "+tagName01);
				System.out.println("got 1 ^ 0: "+tagName10);
			}
			if (!tag01.equals(tag2)) {
				System.out.println("case 0 ^ 1 "+tagName01);
				System.out.println("does not intersect to expected "+tagName2);
				error = true;
			}
			if (!tag10.equals(tag2)) {
				System.out.println("case 1 ^ 0 "+tagName10);
				System.out.println("does not intersect to expected "+tagName2);
				error = true;
			}
		}
		return error;
	}

	static Tag checkIntersect(Tag tag0, Tag tag1, Tag tag2) {
		return tag0.intersect(tag1);
	}

	public static void main(String[] args) {
		boolean error = false;
		Options opts = new Options(args) {
			public void defineOptions() {
				programName = "TagTest";
				defineOption("verbose",
					"Report results verbosely (set =true)", "0");
			}
		};
		try {
			if (testRelationships(opts)) {
				error = true;
			}
			if (testIntersections(opts)) {
				error = true;
			}
		} catch (Exception ex) {
			ex.printStackTrace();
			error = true;
		}
		if (error) {
			System.err.println("some test failed; exit code -2");
			System.exit(-2);
		}
	}
}
