package ca.ucalgary.services.test;

import ca.ucalgary.services.LegacyService;
import ca.ucalgary.seahawk.services.MobyClient;
import ca.ucalgary.seahawk.services.test.MobyClientTestCase;

import org.biomoby.service.test.MobyServletTestCase;
import org.biomoby.service.test.ServletTester;
import org.biomoby.shared.MobyDataType;
import org.biomoby.shared.data.*;

import junit.framework.*;

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

public class LegacyServiceTestCase extends MobyServletTestCase{
    private final static String TEST_BINARY_DATA1 = "ca/ucalgary/services/test/mobyTest1.png";
    private final static String TEST_BINARY_DATA2 = "ca/ucalgary/services/test/mobyTest2.png";
    private final static String MOBY_PNG_DATATYPE = "PNGFormatImage";

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

    /**
     * Loads a binary file, then tests it against a regex, creates a MOBY object, and
     * then the new object is compared to the original file data (they should be
     * identical byte arrays.
     */
    public void testBinaryRegex(){
	System.setProperty(MobyClient.RESOURCE_SYSTEM_PROPERTY, 
			   LegacyService.TEXT_RULES_DEFAULT_RESOURCE);
	MobyClient mobyClient = null;
	try{
	    mobyClient = new MobyClient();
	} catch(Exception e){
	    e.printStackTrace();
	    fail("Could not initialize MobyClient, got exception: " + e);
	}

	URL u1 = getClass().getClassLoader().getResource(TEST_BINARY_DATA1);
	assertNotNull("Cannot find the binary test data resource " + TEST_BINARY_DATA1 +
		 "), please make sure your class path is specified correctly", u1);
	URL u2 = getClass().getClassLoader().getResource(TEST_BINARY_DATA2);
	assertNotNull("Cannot find the binary test data resource " + TEST_BINARY_DATA2 +
		      "), please make sure your class path is specified correctly", u2);

	Map<String, byte[]> binaryDataParts = new HashMap<String, byte[]>();
	try{
	    binaryDataParts.put(u1.toString(), getURLData(u1));
	} catch(Exception e){
	    e.printStackTrace();
	    fail("Could not read data from URL (" + u1 + "), got exception: " + e);
	}
	assertNotNull("The binary test data resource " + u1.toString() + " could not be loaded",
		      binaryDataParts.get(u1.toString()));

	try{
	    binaryDataParts.put(u2.toString(), getURLData(u2));
	} catch(Exception e){
	    e.printStackTrace();
	    fail("Could not read data from URL (" + u2 + "), got exception: " + e);
	}   
	assertNotNull("The binary test data resource " + u2.toString() + " could not be loaded",
		      binaryDataParts.get(u2.toString()));
	// Check that the byte holder class works okay
	MobyDataBytes byteObject = null;
	try{
	    byteObject = new MobyDataBytes("foo", binaryDataParts.get(u2.toString()));
	} catch(Exception e){
	    e.printStackTrace();
	    fail("Could not build a MobyDataBytes object from a byte array: "+ e);
	}
	assertTrue("The MobyDataBytes object does not return the same byte array " +
		   "as given in its constructor (data corruption occured)",
		   Arrays.equals(byteObject.getBytes(), binaryDataParts.get(u2.toString())));

	MobyDataObjectSet pngCollectionTemplate = new MobyDataObjectSet("test", 
						      new MobyDataObject[]{new MobyDataComposite(MOBY_PNG_DATATYPE)});
	MobyDataInstance mdi = null;
	try{
	    mdi = mobyClient.getMobyObject(binaryDataParts, pngCollectionTemplate);
	} catch(Exception e){
	    e.printStackTrace();
	    fail("Could not create Moby Object Collection from binary data map, got exception: " +e); 
	}

	assertTrue("The two PNG images loaded should have been returned as a " +
		   "MobyDataObjectSet, but were not ("+mdi.getClass().getName()+")", 
		   mdi instanceof MobyDataObjectSet);
	MobyDataObjectSet objSet = (MobyDataObjectSet) mdi;
	assertTrue("The MobyDataObjectSet returned from processing the two PNG files " +
		   "did not have the expected size of 2 (was " +objSet.size()+")",
		   objSet.size() == 2);
	assertTrue("The MobyDataObjectSet returned from processing the two PNG files" +
		   " did not return a datatype (was null)",
		   objSet.getDataType() != null);		   
	assertTrue("The MobyDataObjectSet returned from processing the two PNG files" +
		   "did not have the expected data type " + MOBY_PNG_DATATYPE + ", found " +
		   objSet.getDataType().getName(),
                   objSet.getDataType().inheritsFrom(pngCollectionTemplate.getDataType()));

	// Check to make sure neither the name nor the contents have been corrupted
	for(MobyDataObject mobyObject: objSet){
	    assertTrue("A returned MobyDataObject was not of the expected type MobyDataBytes " + 
		       "(found "+mobyObject.getClass().getName()+")", mobyObject instanceof MobyDataBytes);

	    byte[] origBytes = binaryDataParts.get(mobyObject.getName());
	    assertNotNull("A member of the returned MobyDataObjectSet did not have a name" +
			  "corresponding to a name in the input map (the offending name is " +
			  mobyObject.getName()+")", origBytes);
	    byte[] objBytes = ((MobyDataBytes) mobyObject).getBytes();
	    assertTrue("The original binary data and the MOBY representation have different " +
		       "lengths ("+origBytes.length+" and " +objBytes.length+" respectively)", 
		       origBytes.length == objBytes.length);
	    //TODO: Check each byte...
	}
    }

    private byte[] getURLData(URL u) throws Exception{
	InputStream urlStream = u.openStream();
	byte[] byteBufferChunk = new byte[1024];
	ByteArrayOutputStream byteBuffer = new ByteArrayOutputStream();
	for(int r = urlStream.read(byteBufferChunk, 0, 1024);
	    r != -1;
	    r = urlStream.read(byteBufferChunk, 0, 1024)){
	    byteBuffer.write(byteBufferChunk, 0, r);
	}
	return byteBuffer.toByteArray();
    }

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

	TestSuite suite = new TestSuite();
 	suite.addTest(new LegacyServiceTestCase("testBinaryRegex"));
        return suite;
    }

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