/*
 * MasterTest.java
 *
 * Created on 22. elokuuta 2005, 16:04
 */

package tests;

import tests.io.ParserUnitTest;
import tests.distributions.*;
import tests.generator.*;

import PIANOS.Generator;
import PIANOS.exceptions.*;
import PIANOS.datastructures.*;
import PIANOS.io.*;

import java.util.ArrayList;
import java.io.*;

/**
 *
 *
 */
public class MasterTest {
    
    public static void main(String[] args) throws Exception{
        
        String userDistFileName = "tests/cancer/user_dist.f90";
        String modelFileName = null;
        String initialValueFileName = null;
        String simulationFileName = null;
        String proposalFileName = null;
        String updateFileName = null;
        String toOutputFileName = null;
        String lastValueFileName = null;
        
        ParserUnitTest put = new ParserUnitTest(userDistFileName, false);
        ArrayList<Boolean> putresult = put.parseVariableUnitTest();
        int i = 0;
        boolean nonefailed = true;
        for (Boolean b : putresult){
            ++i;
            if (!b) {
                System.out.println("ParserUnitTest: Test "+ i + " failed!");
                nonefailed = false;
            }
        }
        if (nonefailed)
            System.out.println("ParserUnitTest: All tests successful");
        
        // testing for some Parser error conditions...
        
        System.out.println("Testing some Parser error conditions");
       
        
         // rubbish instead of thinning count in simulation
        userDistFileName = "tests/intentionally_broken/user_dist.f90";
        modelFileName = "tests/intentionally_broken/model.txt";
        initialValueFileName = "tests/intentionally_broken/initial_values.txt";
        simulationFileName = "tests/intentionally_broken/simulation_broken.txt";
        proposalFileName = "tests/intentionally_broken/proposals.txt";
        updateFileName = "tests/intentionally_broken/update.txt";
        toOutputFileName = "tests/intentionally_broken/to_output.txt";
        lastValueFileName = "tests/intentionally_broken/last_values.txt";
        
        String expected = "In tests/intentionally_broken/simulation_broken.txt: " +
                "Not an integer on line 7";
        String condition = "Not an integer as thinning";
        
        parserError(condition, expected, userDistFileName, modelFileName, initialValueFileName,
                simulationFileName, proposalFileName, updateFileName, toOutputFileName, lastValueFileName);
        
        // rubbish instead of burn-in
        userDistFileName = "tests/intentionally_broken/user_dist.f90";
        modelFileName = "tests/intentionally_broken/model.txt";
        initialValueFileName = "tests/intentionally_broken/initial_values.txt";
        simulationFileName = "tests/intentionally_broken/simulation_broken2.txt";
        proposalFileName = "tests/intentionally_broken/proposals.txt";
        updateFileName = "tests/intentionally_broken/update.txt";
        toOutputFileName = "tests/intentionally_broken/to_output.txt";
        lastValueFileName = "tests/intentionally_broken/last_values.txt";
        
        expected = "In tests/intentionally_broken/simulation_broken2.txt: " +
                "Not an integer on line 5";
        condition = "Not an integer as burn-in";
        
        parserError(condition, expected, userDistFileName, modelFileName, initialValueFileName,
                simulationFileName, proposalFileName, updateFileName, toOutputFileName, lastValueFileName);
        
        
        // too many tokens after ?? output in to_output
        userDistFileName = "tests/intentionally_broken/user_dist.f90";
        modelFileName = "tests/intentionally_broken/model.txt";
        initialValueFileName = "tests/intentionally_broken/initial_values.txt";
        simulationFileName = "tests/intentionally_broken/simulation.txt";
        proposalFileName = "tests/intentionally_broken/proposals.txt";
        updateFileName = "tests/intentionally_broken/update.txt";
        toOutputFileName = "tests/intentionally_broken/to_output_more.txt";
        lastValueFileName = "tests/intentionally_broken/last_values.txt";
        
        expected = "In tests/intentionally_broken/to_output_more.txt: ?? output " +
                "outputFileName summaryFileName expected on line 3";
        condition = "Too many names after ?? output";
        
        parserError(condition, expected, userDistFileName, modelFileName, initialValueFileName,
                simulationFileName, proposalFileName, updateFileName, toOutputFileName, lastValueFileName);
        
        // too few tokens after ?? output in to_output
        userDistFileName = "tests/intentionally_broken/user_dist.f90";
        modelFileName = "tests/intentionally_broken/model.txt";
        initialValueFileName = "tests/intentionally_broken/initial_values.txt";
        simulationFileName = "tests/intentionally_broken/simulation.txt";
        proposalFileName = "tests/intentionally_broken/proposals.txt";
        updateFileName = "tests/intentionally_broken/update.txt";
        toOutputFileName = "tests/intentionally_broken/to_output_less.txt";
        lastValueFileName = "tests/intentionally_broken/last_values.txt";
        
        expected = "In tests/intentionally_broken/to_output_less.txt: " +
                "'?? output outputFileName summaryFileName' expected on line 3";
        condition = "Too few names after ?? output";
        
        parserError(condition, expected, userDistFileName, modelFileName, initialValueFileName,
                simulationFileName, proposalFileName, updateFileName, toOutputFileName, lastValueFileName);
        
        // too few initial values in the file
        userDistFileName = "tests/intentionally_broken/user_dist.f90";
        modelFileName = "tests/intentionally_broken/model.txt";
        initialValueFileName = "tests/intentionally_broken/initial_values_mis.txt";
        simulationFileName = "tests/intentionally_broken/simulation.txt";
        proposalFileName = "tests/intentionally_broken/proposals.txt";
        updateFileName = "tests/intentionally_broken/update.txt";
        toOutputFileName = "tests/intentionally_broken/to_output.txt";
        lastValueFileName = "tests/intentionally_broken/last_values.txt";
        
        expected = "In tests/intentionally_broken/initial_values_mis.txt: " +
                "Not enough initial values, expected 1:21 1:4";
        condition = "Too few initial values";
        
        parserError(condition, expected, userDistFileName, modelFileName, initialValueFileName,
                simulationFileName, proposalFileName, updateFileName, toOutputFileName, lastValueFileName);
        
        
        // too few lines of initial values in the file
        userDistFileName = "tests/intentionally_broken/user_dist.f90";
        modelFileName = "tests/intentionally_broken/model.txt";
        initialValueFileName = "tests/intentionally_broken/initial_values_misline.txt";
        simulationFileName = "tests/intentionally_broken/simulation.txt";
        proposalFileName = "tests/intentionally_broken/proposals.txt";
        updateFileName = "tests/intentionally_broken/update.txt";
        toOutputFileName = "tests/intentionally_broken/to_output.txt";
        lastValueFileName = "tests/intentionally_broken/last_values.txt";
        
        expected = "In tests/intentionally_broken/initial_values_misline.txt: " +
                "Not enough initial values, expected 1:21 1:4";
        condition = "Too few lines of initial values";
        
        parserError(condition, expected, userDistFileName, modelFileName, initialValueFileName,
                simulationFileName, proposalFileName, updateFileName, toOutputFileName, lastValueFileName);
        
        //  initial values file is missing initial values for some instances
        userDistFileName = "tests/intentionally_broken/user_dist.f90";
        modelFileName = "tests/intentionally_broken/model.txt";
        initialValueFileName = "tests/intentionally_broken/initial_values_mis2.txt";
        simulationFileName = "tests/intentionally_broken/simulation.txt";
        proposalFileName = "tests/intentionally_broken/proposals.txt";
        updateFileName = "tests/intentionally_broken/update.txt";
        toOutputFileName = "tests/intentionally_broken/to_output.txt";
        lastValueFileName = "tests/intentionally_broken/last_values.txt";
        
        expected = "In tests/intentionally_broken/initial_values_mis2.txt: " +
                "Variable x is missing an initial value for (21, 1)";
        condition = "Missing initial values";
        
        parserError(condition, expected, userDistFileName, modelFileName, initialValueFileName,
                simulationFileName, proposalFileName, updateFileName, toOutputFileName, lastValueFileName);
        
        
        // missing distribution for a data variable with missing values:
        userDistFileName = "tests/intentionally_broken/user_dist.f90";
        modelFileName = "tests/intentionally_broken/model_mis.txt";
        initialValueFileName = "tests/intentionally_broken/initial_values.txt";
        simulationFileName = "tests/intentionally_broken/simulation.txt";
        proposalFileName = "tests/intentionally_broken/proposals.txt";
        updateFileName = "tests/intentionally_broken/update.txt";
        toOutputFileName = "tests/intentionally_broken/to_output.txt";
        lastValueFileName = "tests/intentionally_broken/last_values.txt";
        
        expected = "Variable northerness has missing values but has no distribution";
        condition = "Missing distribution for a data variable with missing values";
        
        parserError(condition, expected, userDistFileName, modelFileName, initialValueFileName,
                simulationFileName, proposalFileName, updateFileName, toOutputFileName, lastValueFileName);
        
        
        // missing proposal distribution for a data variable with missing values:
        userDistFileName = "tests/intentionally_broken/user_dist.f90";
        modelFileName = "tests/intentionally_broken/model_mis2.txt";
        initialValueFileName = "tests/intentionally_broken/initial_values.txt";
        simulationFileName = "tests/intentionally_broken/simulation.txt";
        proposalFileName = "tests/intentionally_broken/proposals.txt";
        updateFileName = "tests/intentionally_broken/update.txt";
        toOutputFileName = "tests/intentionally_broken/to_output.txt";
        lastValueFileName = "tests/intentionally_broken/last_values.txt";
        
        expected = "Variable northerness has missing values but has no proposal " +
                "distribution";
        condition = "Missing proposal distribution for a data variable with missing values";
        
        parserError(condition, expected, userDistFileName, modelFileName, initialValueFileName,
                simulationFileName, proposalFileName, updateFileName, toOutputFileName, lastValueFileName);
        
        
        // just a missing proposal distribution
        
        userDistFileName = "tests/intentionally_broken/user_dist.f90";
        modelFileName = "tests/intentionally_broken/model.txt";
        initialValueFileName = "tests/intentionally_broken/initial_values.txt";
        simulationFileName = "tests/intentionally_broken/simulation.txt";
        proposalFileName = "tests/intentionally_broken/proposals_mis.txt";
        updateFileName = "tests/intentionally_broken/update.txt";
        toOutputFileName = "tests/intentionally_broken/to_output.txt";
        lastValueFileName = "tests/intentionally_broken/last_values.txt";
        
        expected = "Stochastic variable x has no proposal distribution";
        condition = "Missing proposal distribution works as expected";
        
        parserError(condition, expected, userDistFileName, modelFileName, initialValueFileName,
                simulationFileName, proposalFileName, updateFileName, toOutputFileName, lastValueFileName);
        
        
        
        // cancer model
        
        userDistFileName = "tests/cancer/user_dist.f90";
        modelFileName = "tests/cancer/model.txt";
        initialValueFileName = "tests/cancer/initial_values.txt";
        simulationFileName = "tests/cancer/simulation.txt";
        proposalFileName = "tests/cancer/proposals.txt";
        updateFileName = "tests/cancer/update.txt";
        toOutputFileName = "tests/cancer/to_output.txt";
        lastValueFileName = "tests/cancer/last_values.txt";
        
        testRun(userDistFileName, modelFileName, initialValueFileName, simulationFileName, proposalFileName,
                updateFileName, toOutputFileName, lastValueFileName);
        
        // the simple bird model with spatial dependency
        
        userDistFileName = "tests/model_proto_spat/user_dist.f90";
        modelFileName = "tests/model_proto_spat/model.txt";
        initialValueFileName = "tests/model_proto_spat/initial_values.txt";
        simulationFileName = "tests/model_proto_spat/simulation.txt";
        proposalFileName = "tests/model_proto_spat/proposals.txt";
        updateFileName = "tests/model_proto_spat/update.txt";
        toOutputFileName = "tests/model_proto_spat/to_output.txt";
        lastValueFileName = "tests/model_proto_spat/last_values.txt";
        
        testRun(userDistFileName, modelFileName, initialValueFileName, simulationFileName, proposalFileName,
                updateFileName, toOutputFileName, lastValueFileName);
        
        // the simple bird model without spatial dependency
        
        userDistFileName = "tests/model01/user_dist.f90";
        modelFileName = "tests/model01/model.txt";
        initialValueFileName = "tests/model01/initial_values.txt";
        simulationFileName = "tests/model01/simulation.txt";
        proposalFileName = "tests/model01/proposals.txt";
        updateFileName = "tests/model01/update.txt";
        toOutputFileName = "tests/model01/to_output.txt";
        lastValueFileName = "tests/model01/last_values.txt";
        
        testRun(userDistFileName, modelFileName, initialValueFileName, simulationFileName, proposalFileName,
                updateFileName, toOutputFileName, lastValueFileName);
        
        
        userDistFileName = "tests/model02/user_dist.f90";
        modelFileName = "tests/model02/model.txt";
        initialValueFileName = "tests/model02/initial_values.txt";
        simulationFileName = "tests/model02/simulation.txt";
        proposalFileName = "tests/model02/proposals.txt";
        updateFileName = "tests/model02/update.txt";
        toOutputFileName = "tests/model02/to_output.txt";
        lastValueFileName = "tests/model02/last_values.txt";
        
        testRun(userDistFileName, modelFileName, initialValueFileName, simulationFileName, proposalFileName,
                updateFileName, toOutputFileName, lastValueFileName);
        
        userDistFileName = "tests/model04/user_dist_test.f90";
        modelFileName = "tests/model04/model.txt";
        initialValueFileName = "tests/model04/initial_values.txt";
        simulationFileName = "tests/model04/simulation.txt";
        proposalFileName = "tests/model04/proposals.txt";
        updateFileName = "tests/model04/update.txt";
        toOutputFileName = "tests/model04/to_output.txt";
        lastValueFileName = "tests/model04/last_values.txt";
        
        testRun(userDistFileName, modelFileName, initialValueFileName, simulationFileName, proposalFileName,
                updateFileName, toOutputFileName, lastValueFileName);
        
        
        // Models for testing purposes only
        
        System.out.println("Models for testing purposes only");
        
        System.out.println("All stochastical");
        // All stochastical
        userDistFileName = "tests/model_all_stoc/user_dist.f90";
        modelFileName = "tests/model_all_stoc/model.txt";
        proposalFileName = "tests/model_all_stoc/proposals.txt";
        
        AcceptationTest.test(userDistFileName, modelFileName, proposalFileName);
        
        System.out.println("All functional");
        // All functional
        userDistFileName = "tests/model_all_func/user_dist.f90";
        modelFileName = "tests/model_all_func/model.txt";
        proposalFileName = "tests/model_all_func/proposals.txt";
        
        AcceptationTest.test(userDistFileName, modelFileName, proposalFileName);
        
        // All spatial deps models
        userDistFileName = "tests/model_all_spat/user_dist.f90";
        proposalFileName = "tests/model_all_spat/simple1p.txt";
        modelFileName = "tests/model_all_spat/simple1.txt";
        AcceptationTest.test(userDistFileName, modelFileName, proposalFileName);
        modelFileName = "tests/model_all_spat/simple2.txt";
        proposalFileName = "tests/model_all_spat/simple2p.txt";
        AcceptationTest.test(userDistFileName, modelFileName, proposalFileName);
        modelFileName = "tests/model_all_spat/cross1.txt";
        proposalFileName = "tests/model_all_spat/cross1p.txt";
        AcceptationTest.test(userDistFileName, modelFileName, proposalFileName);
        modelFileName = "tests/model_all_spat/cross2.txt";
        proposalFileName = "tests/model_all_spat/cross2p.txt";
        AcceptationTest.test(userDistFileName, modelFileName, proposalFileName);
        modelFileName = "tests/model_all_spat/dia1.txt";
        proposalFileName = "tests/model_all_spat/dia1p.txt";
        AcceptationTest.test(userDistFileName, modelFileName, proposalFileName);
        modelFileName = "tests/model_all_spat/dia2.txt";
        proposalFileName = "tests/model_all_spat/dia2p.txt";
        AcceptationTest.test(userDistFileName, modelFileName, proposalFileName);
        modelFileName = "tests/model_all_spat/three1.txt";
        proposalFileName = "tests/model_all_spat/three1p.txt";
        AcceptationTest.test(userDistFileName, modelFileName, proposalFileName);
        modelFileName = "tests/model_all_spat/three2.txt";
        proposalFileName = "tests/model_all_spat/three2p.txt";
        AcceptationTest.test(userDistFileName, modelFileName, proposalFileName);
        modelFileName = "tests/model_all_spat/crossc1.txt";
        proposalFileName = "tests/model_all_spat/crossc1p.txt";
        AcceptationTest.test(userDistFileName, modelFileName, proposalFileName);
        modelFileName = "tests/model_all_spat/crossc2.txt";
        proposalFileName = "tests/model_all_spat/crossc2p.txt";
        AcceptationTest.test(userDistFileName, modelFileName, proposalFileName);
        
        System.out.println("Testing exceptions:");
        try{
            throw new IllegalParametersException("");
        } catch (IllegalParametersException e) {
            System.out.println(e); }
        
        try{
            throw new InvalidProposalException("");
        } catch (InvalidProposalException e) {
            System.out.println(e); }
        
        try{
            throw new InvalidModelException("");
        } catch (InvalidModelException e) {
            System.out.println(e); }
        System.out.println("End of testing exceptions");
        
        System.out.println("Distribution tests");
        //Distribution tester
        DistributionTester.run();
    }
    
    private static void testRun(String userDistFileName, String modelFileName, String initialValueFileName,
            String simulationFileName, String proposalFileName, String updateFileName,
            String toOutputFileName, String lastValueFileName) throws MissingFunctionException,
            SyntaxException, InvalidModelException, IllegalParametersException, InvalidProposalException,
            MissingDistributionException, IOException {
        
        System.out.println("Calling AcceptationTest");
        
        AcceptationTest.test(userDistFileName, modelFileName, proposalFileName);
        AcceptationFormulaTest.test(userDistFileName, modelFileName, simulationFileName,
                proposalFileName, updateFileName, toOutputFileName);
        Generator.writeProgram(userDistFileName, modelFileName, initialValueFileName,
                simulationFileName, proposalFileName, updateFileName,
                toOutputFileName , lastValueFileName);
        
        System.out.println("Testing toStrings:");
        
        DistributionFactory factory = null;
        ComputationalModel model = null;
        try{
            factory = new DistributionFactory(userDistFileName);
            model = ComputationalModelParser.readModel(modelFileName, initialValueFileName,
                    simulationFileName, proposalFileName, updateFileName, toOutputFileName, factory);
            System.out.println("Model information:");
            System.out.println(model);
        } catch (Exception e){
            e.printStackTrace();
            System.exit(1);
        }
    }
    
    private static void parserError(String condition, String expected, String userDistFileName,
            String modelFileName, String initialValueFileName, String simulationFileName,
            String proposalFileName, String updateFileName, String toOutputFileName, String lastValueFileName)
            throws MissingFunctionException, SyntaxException, InvalidModelException,
            IllegalParametersException, InvalidProposalException, MissingDistributionException, IOException{
        try{
            parserRun(userDistFileName, modelFileName, initialValueFileName, simulationFileName,
                    proposalFileName, updateFileName, toOutputFileName, lastValueFileName);
        } catch (Exception e){
            if (e.getMessage().equals(expected) == false){
                System.out.println(e);
                System.exit(1);
            } else {
                System.out.println(condition + " works as expected");
            }
        }
    }
    
    private static void parserRun(String userDistFileName, String modelFileName, String initialValueFileName,
            String simulationFileName, String proposalFileName, String updateFileName,
            String toOutputFileName, String lastValueFileName) throws MissingFunctionException,
            SyntaxException, InvalidModelException, IllegalParametersException, InvalidProposalException,
            MissingDistributionException, IOException {
        
        DistributionFactory factory = null;
        ComputationalModel model = null;
        
        factory = new DistributionFactory(userDistFileName);
        model = ComputationalModelParser.readModel(modelFileName, initialValueFileName,
                simulationFileName, proposalFileName, updateFileName, toOutputFileName, factory);
        System.out.println("Model information:");
        System.out.println(model);
    }
}
