package ca.ucalgary.services.util.test;

import ca.ucalgary.services.util.XHTMLForm;
import junit.framework.*;

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

public class XHTMLFormTestCase extends TestCase{
    private final static String XHTMLFORM_OSPREY_RESOURCE = "ca/ucalgary/services/util/test/osprey_pcr.html";
    private final static String XHTMLFORM_MESH_RESOURCE = "ca/ucalgary/services/util/test/mesh.html";

    // meta-data tests
    private final static String SERVICE_CATEGORY = "Primers";
    private final static String SERVICE_PROVIDER = "moby.ucalgary.ca";
    private final static String SERVICE_NAME = "CalcPCRPrimers";
    private final static String SERVICE_DESC = "Takes a DNA sequence and calculates PCR probes satisfying a given set of conditions";
    private final static String SERVICE_CONTACT = "gordonp@ucalgary.ca";
    private final static String CENTRAL_ENDPOINT = "http://moby.ucalgary.ca/moby/MOBY-Central.pl";

    // cardinality tests
    private final static int NUM_SERVICES = 1;
    private final static int NUM_PRIMARY_INPUTS = 1;
    private final static int NUM_SECONDARY_INPUTS = 17;
    private final static int NUM_FIXED_INPUTS = 1;
    private final static int NUM_OUTPUTS = 1;
    private final static int NUM_SUBMITS = 2;
    private final static int NUM_IMAGES = 0; // TODO: other form tests, incl. images and checkboxes
    private final static int NUM_FILES = 0;// there are 3 in the form, but class="moby:null" is set for all of them

    // TODO: unit tests for funny stuff like redeclaration of secondaries 
    // and use of same primary input for mltiple form elements

    // param spec tests
    // primary
    private final static String inputHTMLParamName = "input_text";
    private final static String inseq = "sequence:DNASequence";  
    private final static String inseqFormat = "fasta";
    private final static String primers = "primers:Collection(DNASequence)";
    // secondary
    private final static String bias = "product_bias:String:3:[5,3]";
    private final static String dimer_delta_g_max = "dimer_delta_g_max:String:auto (GC% & length based):[auto (GC% & length based),10,11,12,13,14,15,16,17,18]";
    private final static String dna_conc = "dna_conc:Float:0.0002:[0,1]";
    private final static String hairpin_delta_g_max = "hairpin_delta_g_max:String:auto (GC% & length based):[auto (GC% & length based),10,11,12,13,14,15,16,17,18]";
    private final static String interval = "interval:String::";
    private final static String max_prod_len = "MaximumProductLength:Integer:1000:[1,]";
    private final static String melt_temp_diff = "melt_temp_diff:String:2:[0,1,2,3,4,5]";
    private final static String melt_temp_max = "melt_temp_max:String:60:[40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70]";
    private final static String melt_temp_min = "melt_temp_min:String:54:[40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70]";
    private final static String min_prod_len = "MinimumProductLength:Integer:100:[1,]";
    private final static String oligo_length_max = "oligo_length_max:String:23:[15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35]";
    private final static String oligo_length_min = "oligo_length_min:String:18:[15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35]";
    private final static String oligo_length_opt = "oligo_length_opt:String:auto (min/max enforced):[auto (min/max enforced),15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35]";
    private final static String opt_prod_len = "OptimalProductLength:Integer:600:[1,]";
    private final static String salt_conc = "salt_conc:Float:0.05:[0,10]";
    private final static String secondary_delta_g_max = "secondary_delta_g_max:String:auto (based on temp margin):[auto (based on temp margin),10,11,12,13,14,15,16,17,18,19,20]";
    private final static String secondary_melt_margin = "secondary_melt_margin:String:8:[5,6,7,8,9,10,11,12,13,14,15]";
    // fixed
    private final static String foo = "bar";

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

    /**
     * See if the xhtml and moby spec class values are properly parsed
     */
    public void testParsingBasic(){
	loadForm(XHTMLFORM_OSPREY_RESOURCE);
    }

    /**
     * See if the meta data for the service is parsed correctly
     */
    public void testMetaData(){
	XHTMLForm form = loadForm(XHTMLFORM_OSPREY_RESOURCE);
	assertTrue("The service type (" + form.getServiceType() + 
		   ") was not as expected (" + SERVICE_CATEGORY + ")",
		   SERVICE_CATEGORY.equals(form.getServiceType()));
	assertTrue("The service provider URI (" + form.getProviderURI() + 
		   ") was not as expected (" + SERVICE_PROVIDER + ")",
		   SERVICE_PROVIDER.equals(form.getProviderURI()));
	assertTrue("The service contact (" + form.getContactEmail() + 
		   ") was not as expected (" + SERVICE_CONTACT + ")",
		   SERVICE_CONTACT.equals(form.getContactEmail()));
	assertTrue("The service contact (" + form.getServiceDesc() + 
		   ") was not as expected (" + SERVICE_DESC + ")",
		   SERVICE_DESC.equals(form.getServiceDesc()));	
	assertTrue("The central endpoint (" + form.getCentralEndpoint() +
		   ") was not as expected (" + CENTRAL_ENDPOINT + ")",
		   CENTRAL_ENDPOINT.equals(form.getCentralEndpoint()));
    }

    /**
     * See if the values for the parameters are correctly noted (i.e. rules of
     * overriding and defaults are properly applied when combining the HTML spec and
     * the Moby spec).
     */
    public void testLogic(){
	XHTMLForm form = loadForm(XHTMLFORM_OSPREY_RESOURCE);
	String[] serviceNames = form.getServiceNames();
	assertTrue("The number of services defined (" + serviceNames.length +
		   ") was not as expected (" + NUM_SERVICES + ")",
		   NUM_SERVICES == serviceNames.length);

	// Check the Moby-facing specs
	Map<String,String> primaryInputs = form.getPrimaryInputs();
	assertTrue("The number of primary input parameters defined (" + primaryInputs.size() +
		   ") was not as expected (" + NUM_PRIMARY_INPUTS + ")",
		   NUM_PRIMARY_INPUTS == primaryInputs.size());

	// Every primary in should have a legacy text format defined
	Map<String,String> primaryInputFormats = form.getPrimaryInputFormats();
	assertTrue("The number of primary input parameter formats defined (" + primaryInputFormats.size() +
		   ") was not as expected (" + NUM_PRIMARY_INPUTS + ")",
		   NUM_PRIMARY_INPUTS == primaryInputFormats.size());
	
	Map<String,String> secondaryInputs = form.getSecondaryInputs();

	assertTrue("The number of secondary input parameters defined (" + secondaryInputs.size() +
		   ") was not as expected (" + NUM_SECONDARY_INPUTS + ")",
		   NUM_SECONDARY_INPUTS == secondaryInputs.size());

	Map<String,String> outputs = form.getPrimaryOutputs();
	assertTrue("The number of primary output parameters defined (" + outputs.size() +
		   ") was not as expected (" + NUM_OUTPUTS + ")",
		   NUM_OUTPUTS == outputs.size());
	
	// Check the HTML-specific specs
	Map<String,String> fixedParams = form.getFixedParams();
	assertTrue("The number of fixed HTML parameters defined (" + fixedParams.size() +
		   ") was not as expected (" + NUM_FIXED_INPUTS + ")",
		   NUM_FIXED_INPUTS == fixedParams.size());

	Map<String,String> submitParams = form.getSubmitOptions();
	assertTrue("The number of submit parameters defined (" + submitParams.size() +
		   ") was not as expected (" + NUM_SUBMITS + ")",
		   NUM_SUBMITS == submitParams.size());

	Map<String,String> imageParams = form.getImageOptions();
	assertTrue("The number of image parameters defined (" + imageParams.size() +
		   ") was not as expected (" + NUM_IMAGES + ")",
		   NUM_IMAGES == imageParams.size());

	List<String> fileParams = form.getFormFiles();
	assertTrue("The number of file parameters defined (" + fileParams.size() +
		   ") was not as expected (" + NUM_FILES + ")",
		   NUM_FILES == fileParams.size());

	// Check that the parameter values are okay
	assertTrue("The value of the primary parameter 'inseq' (" +
		   primaryInputs.get(inputHTMLParamName) + ") was not the expected value '" + 
		   inseq + "'",
		   inseq.equals(primaryInputs.get(inputHTMLParamName)));
	assertTrue("The value of format for the primary parameter 'inseq' (" +
		   primaryInputFormats.get(inputHTMLParamName) + ") was not the expected value '" + 
		   inseqFormat + "'",
		   inseqFormat.equals(primaryInputFormats.get(inputHTMLParamName)));
	assertTrue("The value of the output parameter 'primers' (" +
		   outputs.get("primers") + ") was not the expected value '" + 
		   primers + "'",
		   primers.equals(outputs.get("primers")));
     
	assertTrue("The value of the secondary parameter 'bias' (" + 
		   secondaryInputs.get("bias") + ") was not the expected value '" + bias + "'", 
		   bias.equals(secondaryInputs.get("bias")));
	assertTrue("The value of the secondary parameter 'dimer_delta_g_max' (" + 
		   secondaryInputs.get("dimer_delta_g_max") + ") was not the expected value '" + 
		   dimer_delta_g_max + "'", 
		   dimer_delta_g_max.equals(secondaryInputs.get("dimer_delta_g_max")));
	assertTrue("The value of the secondary parameter 'dna_conc' (" + 
		   secondaryInputs.get("dna_conc") + ") was not the expected value '" + 
		   dna_conc + "'", 
		   dna_conc.equals(secondaryInputs.get("dna_conc")));
	assertTrue("The value of the secondary parameter 'hairpin_delta_g_max' " +
		   secondaryInputs.get("hairpin_delta_g_max") + ") was not the expected value '" +
		   hairpin_delta_g_max + "'", 
		   hairpin_delta_g_max.equals(secondaryInputs.get("hairpin_delta_g_max")));
	assertTrue("The value of the secondary parameter 'interval' (" + secondaryInputs.get("interval") +
		   ") was not the expected value '" + interval + "'",
		   interval.equals(secondaryInputs.get("interval")));
	assertTrue("The value of the secondary parameter 'max_prod_len' (" + 
		   secondaryInputs.get("max_prod_len") + ") was not the expected value '" +
		   max_prod_len + "'",
		   max_prod_len.equals(secondaryInputs.get("max_prod_len")));
	assertTrue("The value of the secondary parameter 'melt_temp_diff' (" +
		   secondaryInputs.get("melt_temp_diff") + ") was not the expected value '" +
		   melt_temp_diff + "'",
		   melt_temp_diff.equals(secondaryInputs.get("melt_temp_diff")));
	assertTrue("The value of the secondary parameter 'melt_temp_max' (" +
		   secondaryInputs.get("melt_temp_max") + ") was not the expected value '" +
		   melt_temp_max + "'",
		   melt_temp_max.equals(secondaryInputs.get("melt_temp_max")));
	assertTrue("The value of the secondary parameter 'melt_temp_min' (" +
		   secondaryInputs.get("melt_temp_min") + ") was not the expected value '" +
		   melt_temp_min + "'",
		   melt_temp_min.equals(secondaryInputs.get("melt_temp_min")));
	assertTrue("The value of the secondary parameter 'min_prod_len' (" +
		   secondaryInputs.get("min_prod_len") + ") was not the expected value '" +
		   min_prod_len + "'",
		   min_prod_len.equals(secondaryInputs.get("min_prod_len")));
	assertTrue("The value of the secondary parameter 'oligo_length_max' (" +
		   secondaryInputs.get("oligo_length_max") + ") was not the expected value '" +
		   oligo_length_max + "'",
		   oligo_length_max.equals(secondaryInputs.get("oligo_length_max")));
	assertTrue("The value of the secondary parameter 'oligo_length_min' (" +
		   secondaryInputs.get("oligo_length_min") + ") was not the expected value '" +
		   oligo_length_min + "'",
		   oligo_length_min.equals(secondaryInputs.get("oligo_length_min")));
	assertTrue("The value of the secondary parameter 'oligo_length_opt' (" +
		   secondaryInputs.get("oligo_length_opt") + ") was not the expected value '" +
		   oligo_length_opt + "'",
		   oligo_length_opt.equals(secondaryInputs.get("oligo_length_opt")));
	assertTrue("The value of the secondary parameter 'opt_prod_len' (" +
		   secondaryInputs.get("opt_prod_len") + ") was not the expected value '" +
		   opt_prod_len + "'",
		   opt_prod_len.equals(secondaryInputs.get("opt_prod_len")));
	assertTrue("The value of the secondary parameter 'salt_conc' (" +
		   secondaryInputs.get("salt_conc") + ") was not the expected value '" +
		   salt_conc + "'",
		   salt_conc.equals(secondaryInputs.get("salt_conc")));
	assertTrue("The value of the secondary parameter 'secondary_delta_g_max' (" +
		   secondaryInputs.get("secondary_delta_g_max") + ") was not the expected value '" +
		   secondary_delta_g_max + "'",
		   secondary_delta_g_max.equals(secondaryInputs.get("secondary_delta_g_max")));
	assertTrue("The value of the secondary parameter 'secondary_melt_margin' (" +
		   secondaryInputs.get("secondary_melt_margin") + ") was not the expected value '" +
		   secondary_melt_margin + "'",
		   secondary_melt_margin.equals(secondaryInputs.get("secondary_melt_margin")));

    }

    private XHTMLForm loadForm(String rez){
	URL u = getClass().getClassLoader().getResource(rez);
	assertNotNull("Could not find the test HTML form resource ("+rez+")", u);

	XHTMLForm form = null;
	try{
	    form = new XHTMLForm(u);
	} catch(Exception e){
	    e.printStackTrace();
	    fail("Could not load and parse the test input resource ("+u+"): " + e);
	}

	return form;
    }


    private void testSimple(){
	XHTMLForm form = loadForm(XHTMLFORM_MESH_RESOURCE);
	
    }

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

	TestSuite suite = new TestSuite();
	suite.addTest(new XHTMLFormTestCase("testSimple"));
 	suite.addTest(new XHTMLFormTestCase("testParsingBasic"));
 	suite.addTest(new XHTMLFormTestCase("testMetaData"));
 	suite.addTest(new XHTMLFormTestCase("testLogic"));
        return suite;
    }

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