/**
 * Tests all of the major functionality of MobyClient, the text-to-MOBY converter.
 */

package ca.ucalgary.seahawk.services.test;

import ca.ucalgary.seahawk.services.MobyClient;
import org.biomoby.shared.*;
import org.biomoby.shared.data.*;

import junit.framework.*;

import java.io.*;
import java.net.URL;

public class MobyClientTestCase extends TestCase{
    public static final String TEST_RULES_RESOURCE1 = "ca/ucalgary/seahawk/services/test/mobyRules1.xml";
    public static final String TEST_HASDATA = "fee  fie\tfoe\tfum\ndee\n";
    public static final int TEST_HASDATA_NUMOBJS = 2;
    public static final String TEST_HASDATA_CLASSNAME = "tableRow";
    public static final String TEST_HASDATA_MEMBERNAME = "cell";
    public static final String TEST_HASDATA_MEMBERS1_CLASS = "String";
    public static final int TEST_HASDATA_MEMBERS1_COUNT = 4;
    public static final int TEST_HASDATA_MEMBERS2_COUNT = 1;

    public static final String TEST_RULES_RESOURCE2 = "ca/ucalgary/seahawk/services/test/mobyRules2.xml";
    public static final int TEST_INHERIT_NUMOBJS = 1;
    public static final String TEST_INHERIT_CLASSNAME = "table";

    public static final String TEST_RULES_RESOURCE3 = "ca/ucalgary/seahawk/services/test/mobyRules3.xml";
    public static final String TEST_INHERITMEMBER_RESOURCE = "ca/ucalgary/seahawk/services/test/embossChargeOutput.txt";
    public static final int TEST_INHERITMEMBER_NUMOBJS = 1;
    public static final String TEST_INHERITMEMBER_CLASSNAME = "ProteinChargeTable";
    
    private MobyClient client;

    public MobyClientTestCase(String name){
	super(name);
    }

    /**
     * Sets up the test fixture.
     * Called before every test case method.
     */
    public void setUp(){
    }

    public void testRegexHASRelation(){
	System.setProperty(MobyClient.RESOURCE_SYSTEM_PROPERTY, 
			   TEST_RULES_RESOURCE1);
	try{
	    client = new MobyClient();
	} catch(Exception e){
	    e.printStackTrace();
	    fail("Could not initialize MobyClient (with rules file "+
		 TEST_RULES_RESOURCE1+") due to exception: " + e);
	}

	MobyDataObject[] results = client.getMobyObjects(TEST_HASDATA);

	assertTrue("MobyClient found "+ results.length +" objects, but we expected "+TEST_HASDATA_NUMOBJS, 
		   TEST_HASDATA_NUMOBJS == results.length);
	assertNotNull("First object returned by MobyClient was null, expected a valid object", results[0]);
	assertNotNull("Second object returned by MobyClient was null, expected a valid object", results[1]);
	assertTrue("First object returned by MobyClient was not a composite object "+
		   "(instance of MobyDataComposite) as expected",
		   results[0] instanceof MobyDataComposite);
	assertTrue("Second object returned by MobyClient was not a composite object "+
		   "(instance of MobyDataComposite) as expected",
		   results[1] instanceof MobyDataComposite);

	MobyDataType dataType = results[0].getDataType();
	assertNotNull("The MOBY data type of the first object returned by MobyClient was null" +
		      ", expected a valid data type",
		      dataType);
	assertTrue("The data type of the object returned by MobyClient (" +
		   dataType.getName() + ") was not the expected value: "+TEST_HASDATA_CLASSNAME,
		   TEST_HASDATA_CLASSNAME.equals(dataType.getName()));
	assertTrue("The data type of the second object returned by MobyClient " +
		   "did not match that of the first as expected", dataType.equals(results[1].getDataType()));
	
	// First, we should make sure the ontology was been changed on us...
	MobyRelationship memberRelation = dataType.getChild(TEST_HASDATA_MEMBERNAME);
	assertNotNull("Data type "+TEST_HASDATA_CLASSNAME+" does not have a member named " +
		      TEST_HASDATA_MEMBERNAME + ", please adjust either this test, or the " +
		      "data type ontology.",
		      memberRelation);
	assertTrue("Member "+TEST_HASDATA_MEMBERNAME+" of data type is not defined with a HAS " +
		   "relationship as expected, please adjust either this test, or the data type ontology.",
		   memberRelation.getRelationshipType() == Central.iHAS);

	// We're okay on the data type definitions, go and check the values
	MobyDataInstance data = ((MobyDataComposite) results[0]).get(TEST_HASDATA_MEMBERNAME);
	assertNotNull("MobyClient returned an instance (#1 of 2) of "+TEST_HASDATA_CLASSNAME+
		      " without the member " + TEST_HASDATA_MEMBERNAME +
		      ", but such an instance was expected", 
		      data);
	// Check the data type
	assertTrue("The member "+TEST_HASDATA_MEMBERNAME+" of object " + TEST_HASDATA_CLASSNAME +
		   " is not represented by a MobyDataObjectVector (for HAS relationships) as expected",
		   data instanceof MobyDataObjectVector);
	// Check cardinality
	assertTrue("The member "+TEST_HASDATA_MEMBERNAME+" of object " + TEST_HASDATA_CLASSNAME +
		   "(#1 of 2) had " + ((MobyDataObjectVector) data).size() + " instances, but " + 
		   TEST_HASDATA_MEMBERS1_COUNT + " were expected",
		   TEST_HASDATA_MEMBERS1_COUNT == ((MobyDataObjectVector) data).size());
	// Check that the data type is correct
	MobyDataType hasMemberDataType = ((MobyDataObjectVector) data).get(0).getDataType();
	assertNotNull("The data type of the HAS member was unexpectedly null", hasMemberDataType);
	assertTrue("The data type of the HAS member ("+hasMemberDataType.getName()+
		   ") was not the expected one (" + TEST_HASDATA_MEMBERS1_CLASS, 
		   TEST_HASDATA_MEMBERS1_CLASS.equals(hasMemberDataType.getName()));

	// We're okay on the data type definitions, go and check the values
        data = ((MobyDataComposite) results[1]).get(TEST_HASDATA_MEMBERNAME);
	assertNotNull("MobyClient returned an instance (#2 of 2) of "+TEST_HASDATA_CLASSNAME+
		      " without the member " + TEST_HASDATA_MEMBERNAME +
		      ", but such an instance was expected", 
		      data);
	// Check the data type
	assertTrue("The member "+TEST_HASDATA_MEMBERNAME+" of object " + TEST_HASDATA_CLASSNAME +
		   "(#2 of 2) is not represented by a MobyDataObject (for HAS relationships) as expected",
		   data instanceof MobyDataObject);

    }

    public void testRegexInheritance(){
	System.setProperty(MobyClient.RESOURCE_SYSTEM_PROPERTY, 
			   TEST_RULES_RESOURCE2);
	try{
	    client = new MobyClient();
	} catch(Exception e){
	    e.printStackTrace();
	    fail("Could not initialize MobyClient (with rules file "+
		 TEST_RULES_RESOURCE2+") due to exception: " + e);
	}

	MobyDataType targetType = MobyDataType.getDataType(TEST_INHERIT_CLASSNAME);
	assertNotNull("Couldn't find the test data type " + TEST_INHERIT_CLASSNAME +
		      " in the data type ontology, please update the test case", 
		      targetType);
	MobyDataObject[] results = null;
	try{
	    results = client.getMobyObjects(TEST_HASDATA.getBytes(), targetType);
	} catch(Exception e){
	    e.printStackTrace();
	    fail("Could not build an object with " + TEST_INHERIT_CLASSNAME + 
		 " data type from the test data due to exception: " + e);
	}
	
	assertNotNull("getMobyObject() unexpected returned null", results);
	assertTrue("getMobyObject() returned bad array, expected length of "+
		   TEST_INHERIT_NUMOBJS+", but got " + results.length, 
		   results.length == TEST_INHERIT_NUMOBJS);
	assertTrue("The data instance returned by getMobyObjects() (" +
		   results[0].getDataType().getName()+") does not " +
		   "inherit from the requested type ("+TEST_INHERIT_CLASSNAME+")",
		   results[0].getDataType().inheritsFrom(targetType));
	results[0].setXmlMode(MobyDataInstance.SERVICE_XML_MODE);
	try{
	    MobyDataUtils.toXMLDocument(System.err, new MobyContentInstance(results[0], "param1"));
	} catch(Exception e){
	    e.printStackTrace();
	    fail("Could not serialize the "+TEST_INHERIT_CLASSNAME+
		 " created by getMobyObjects() to XML due to exception: " + e);
	}
    }

    public void testMemberInheritance(){
	URL u = getClass().getClassLoader().getResource(TEST_INHERITMEMBER_RESOURCE);
	StringBuffer testDataStringBuffer = new StringBuffer();
	try{
	    LineNumberReader reader = new LineNumberReader(new InputStreamReader(u.openStream()));
	    for(String line = reader.readLine(); line != null; line = reader.readLine()){
		testDataStringBuffer.append(line+"\n");
	    }	    
	} catch(Exception e){
	    e.printStackTrace();
	    fail("Could not read data from test data resource (" + u + "): " + e);
	}

	System.setProperty(MobyClient.RESOURCE_SYSTEM_PROPERTY, 
			   TEST_RULES_RESOURCE3);
	try{
	    client = new MobyClient();
	} catch(Exception e){
	    e.printStackTrace();
	    fail("Could not initialize MobyClient (with rules file "+
		 TEST_RULES_RESOURCE2+") due to exception: " + e);
	}

	MobyDataType targetType = MobyDataType.getDataType(TEST_INHERITMEMBER_CLASSNAME);
	assertNotNull("Couldn't find the test data type " + TEST_INHERITMEMBER_CLASSNAME +
		      " in the data type ontology, please update the test case", 
		      targetType);
	MobyDataObject[] results = null;
	try{
	    results = client.getMobyObjects(testDataStringBuffer.toString().getBytes(), targetType);
	} catch(Exception e){
	    e.printStackTrace();
	    fail("Could not build an object with " + TEST_INHERITMEMBER_CLASSNAME + 
		 " data type from the test data due to exception: " + e);
	}
	
	assertNotNull("getMobyObject() unexpected returned null", results);
	assertTrue("getMobyObject() returned bad array, expected length of "+
		   TEST_INHERITMEMBER_NUMOBJS+", but got " + results.length, 
		   results.length == TEST_INHERITMEMBER_NUMOBJS);
	assertTrue("The data instance returned by getMobyObjects() (" +
		   results[0].getDataType().getName()+") does not " +
		   "inherit from the requested type ("+TEST_INHERITMEMBER_CLASSNAME+")",
		   results[0].getDataType().inheritsFrom(targetType));
	results[0].setXmlMode(MobyDataInstance.SERVICE_XML_MODE);
	try{
	    MobyDataUtils.toXMLDocument(new StringWriter(), new MobyContentInstance(results[0], "param1"));
	} catch(Exception e){
	    e.printStackTrace();
	    fail("Could not serialize the "+TEST_INHERITMEMBER_CLASSNAME+
		 " created by getMobyObjects() to XML due to exception: " + e);
	}
    }

    /**
     * @return a test suite for all the test methods of this test case.
     */
    public static Test suite() {

	TestSuite suite = new TestSuite();
 	suite.addTest(new MobyClientTestCase("testRegexHASRelation"));
 	suite.addTest(new MobyClientTestCase("testRegexInheritance"));
 	suite.addTest(new MobyClientTestCase("testMemberInheritance"));
        return suite;
    }

    public static void main(String[] args){
	junit.textui.TestRunner.run(suite());
    }
}
