/*
 * ParserUnitTest.java
 *
 * Created on 16. elokuuta 2005, 13:17
 */

package tests.io;

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

import java.io.*;
import java.util.ArrayList;
import java.util.HashMap;
/**
 *
 * @author Eemil Lagerspetz
 * This is a test class for the Parser.
 * Runs tests for the parser methods bottom-up.
 */
public class ParserUnitTest {
    
    private boolean ok;
    private boolean debug;
    private int i;
    private DistributionFactory fact;
    private ArrayList<Boolean> tests;
    
    public static void main(String[] args) throws SyntaxException{
        ParserUnitTest put = null;
        if (args.length == 2){
            if (args[1].equals("debug")){
                put = new ParserUnitTest(args[0], true);
                put.commandLineParseVariableUnitTest();
            } else{
                put = new ParserUnitTest(args[0], false);
                put.commandLineParseVariableUnitTest();
            }
        } else if (args.length == 1){
            put = new ParserUnitTest(args[0], false);
            put.commandLineParseVariableUnitTest();
        } else {
            System.out.println("One or two command-line parameters expected.");
        }
    }
    
    private void next(){
        this.i++;
    }
    
    private void result(boolean success){
        this.ok = success;
    }
    
    public ParserUnitTest(String factFile, boolean debug){
        this.i = 0;
        this.ok = false;
        this.debug = debug;
        this.tests = new ArrayList<Boolean>();
        try{
            this.fact = new DistributionFactory(factFile);
        }catch (Exception e){
            System.out.println(e.getMessage());
            System.exit(1);
        }
    }
    
    private Variable parseVariableTest(File file, boolean integer, String toParse,
            HashMap<String, Variable> variableMapper, String expected) throws SyntaxException{
        Variable var = null;
        next();
        this.ok = false;
        if (this.debug)
            System.out.println("Test "+ i + ":");
        try{
            var = ComputationalModelParser.parseVariable(file, integer, toParse, variableMapper, fact);
            
            
        } catch (Exception e){
            if (this.debug){
                System.out.println("\tGot:\t\t"+ e.getMessage());
                System.out.println("\tExpected:\t"+ expected);
            }
            if (e.getMessage().equals(expected))
                ok = true;
        }
        if (expected != null){
            if (ok)
                this.tests.add(true);
            else
                this.tests.add(false);
        }
        return var;
    }
    
    private void testIt() throws SyntaxException{
        
        // userDistFile, modelFile, initialValuesFile, simulationFile, proposalFile,
        // updateFile, outputFile
        HashMap<String, Variable> variableMapper = new HashMap<String, Variable>();
        String expected = null;
        Variable var = null;
      //1  
        expected = "In null: Invalid variable name on line 0";
        parseVariableTest(null, false, "(som?erubbish)", variableMapper, expected);
        //2
        expected = "In null: No column definition, expression or distribution found for variable" +
                " on line 0";
        parseVariableTest(null, false, "alpha", variableMapper, expected);
        //3
        expected = "In null: Invalid column number on line 0";
        parseVariableTest(null, false, "alpha()", variableMapper, expected);
        //4
        expected = "In null: Invalid column number on line 0";
        parseVariableTest(null, false, "alpha(10rub?bish )", variableMapper, expected);
        //5
        expected = "In null: Invalid column number on line 0";
        parseVariableTest(null, false, "alpha(15.23)", variableMapper, expected);
        //6
        expected = "In null: Invalid column number on line 0 (columns start at 1)";
        parseVariableTest(null, false, "alpha(-1)", variableMapper, expected);
        
        //7
        var = parseVariableTest(null, false, "alpha(2)", variableMapper, null);
        
        ok = true;
        if (var.getName().equals("alpha") == false)
            ok = false;
        if (var.isInteger() == true)
            ok = false;
        if (var.isData() == false)
            ok = false;
        if (var.isFunctional() == true)
            ok = false;
        if (var.getColumn() != 2)
            ok = false;
        
        if (ok)
            this.tests.add(true);
        else
            this.tests.add(false);
        
        // 8
        var = parseVariableTest(null, false, "alpha(*)", variableMapper, null);
        
        ok = true;
        if (var.getName().equals("alpha") == false)
            ok = false;
        if (var.isInteger() == true)
            ok = false;
        if (var.isData() == false)
            ok = false;
        if (var.isFunctional() == true)
            ok = false;
        if (var.getColumn() != -1)
            ok = false;
        
        if (ok)
            this.tests.add(true);
        else
            this.tests.add(false);
        
        // 9 
        var = parseVariableTest(null, false, "alpha = 1.0", variableMapper, null);
        
        ok = true;
        if (var.getName().equals("alpha") == false)
            ok = false;
        if (var.isInteger() == true)
            ok = false;
        if (var.isData() == true)
            ok = false;
        if (var.isFunctional() == false)
            ok = false;
        if (var.getEquation() == null)
            ok = false;
        if (var.getEquation().getEquation()[0].equals("1.0") == false)
            ok = false;
        
        if (ok)
            this.tests.add(true);
        else
            this.tests.add(false);
        
        // 10
        var = parseVariableTest(null, true, "alpha = 1.0", variableMapper, null);
        
        ok = true;
        if (var.getName().equals("alpha") == false)
            ok = false;
        if (var.isInteger() == false)
            ok = false;
        if (var.isData() == true)
            ok = false;
        if (var.isFunctional() == false)
            ok = false;
        if (var.getEquation() == null)
            ok = false;
        if (var.getEquation().getEquation()[0].equals("1.0") == false)
            ok = false;
        
        if (ok)
            this.tests.add(true);
        else
            this.tests.add(false);
        
        // 11
        expected = "Could not find user-defined distribution called \"\".";
        parseVariableTest(null, false, "alpha ~", variableMapper, expected);
        // 12
        expected = "In null: Mismatching parentheses on line 0";
        parseVariableTest(null, false, "al3ph6a ~ continuous_" +
                "uniform(", variableMapper, expected);
        // 13
        expected = "In null: Too few parameters on line 0";
        parseVariableTest(null, false, "alpha98 ~" +
                "continuous_uniform()", variableMapper, expected);
        // 14
        expected = "In null: Parameter 1 on line 0 is not a decimal number or a " +
                "correct variable name";
        parseVariableTest(null, false, "a4lpha ~ continuous_" +
                "uniform( (v 1.8 )", variableMapper, expected);
        // 15
        expected = "In null: Too few parameters on line 0";
        parseVariableTest(null, false, "iota~ " +
                "continuous_uniform (1.0)", variableMapper, expected);
     // 16    
        expected = "In null: Parameter 2 on line 0 is not an integer or a correct variable name";
        parseVariableTest(null, false, "iota~" +
                "discrete_uniform ( 0, 1.0 )", variableMapper, expected);
        // 17
        expected = "In null: Too many parameters on line 0";
        parseVariableTest(null, false,  "iota~" +
                "discrete_uniform ( 0, 1, 18 )", variableMapper, expected);
        // 18 
        expected = "In null: Parameter 1 on line 0 is not defined before it is used";
        parseVariableTest(null, false,   "iota~" +
                "discrete_uniform (gamma, 1)", variableMapper, expected);
        
       // 19
        variableMapper = new HashMap<String, Variable>();
        Variable gamma = new Variable();
        gamma.setName("gamma");
        gamma.setType(false);
        variableMapper.put(gamma.getName(), gamma);
        
        expected = "In null: Parameter 1 on line 0 is not of type INTEGER";
        parseVariableTest(null, false, "iota~" +
                "discrete_uniform (gamma, 1)", variableMapper, expected);
        
        // 20
        variableMapper = new HashMap<String, Variable>();
        gamma = new Variable();
        gamma.setName("gamma");
        gamma.setType(true);
        variableMapper.put(gamma.getName(), gamma);
        
        var = parseVariableTest(null, false, "iota~" +
                "discrete_uniform (gamma, 1)", variableMapper, null);
        
        ok = true;
        if (var.getName().equals("iota") == false)
            ok = false;
        if (var.isInteger() == true)
            ok = false;
        if (var.isData() == true)
            ok = false;
        if (var.isFunctional() == true)
            ok = false;
        if (var.getDependsList().get(0) != gamma)
            ok = false;
        if (var.getDistribution() == null)
            ok = false;
        if (var.getDistribution().getParameter(0) != gamma)
            ok = false;
        
        if (ok)
            this.tests.add(true);
        else
            this.tests.add(false);
        // 21
        variableMapper = new HashMap<String, Variable>();
        expected = "In null: Parameter 1 on line 0 is not defined before it is used";
        parseVariableTest(null, false,   "iota~" +
                "continuous_uniform (gamma, 1.0)", variableMapper, expected);
        
        
        variableMapper = new HashMap<String, Variable>();
        gamma = new Variable();
        gamma.setName("gamma");
        gamma.setType(true);
        variableMapper.put(gamma.getName(), gamma);
        
        //expected = "In null: Parameter 1 on line 0 is not of type REAL";
        // desired behaviour changed: now we want to be able to give integers
        // in the place of reals (the generator must then handle REAL()-casting them.
        
        // 22
        var = parseVariableTest(null, false,   "iota~" +
                "continuous_uniform (gamma, 1.0)", variableMapper, null);
        
         ok = true;
        if (var.getName().equals("iota") == false)
            ok = false;
        if (var.isInteger() == true)
            ok = false;
        if (var.isData() == true)
            ok = false;
        if (var.isFunctional() == true)
            ok = false;
        if (var.getDependsList().get(0) != gamma)
            ok = false;
        if (var.getDistribution() == null)
            ok = false;
        if (var.getDistribution().getParameter(0) != gamma)
            ok = false;
        
        if (ok)
            this.tests.add(true);
        else
            this.tests.add(false);
        
       // 23
        variableMapper = new HashMap<String, Variable>();
        gamma = new Variable();
        gamma.setName("gamma");
        gamma.setType(false);
        variableMapper.put(gamma.getName(), gamma);
        
        var = parseVariableTest(null, false,   "iota~" +
                "continuous_uniform (gamma, 1.0)", variableMapper, null);
        
        ok = true;
        if (var.getName().equals("iota") == false)
            ok = false;
        if (var.isInteger() == true)
            ok = false;
        if (var.isData() == true)
            ok = false;
        if (var.isFunctional() == true)
            ok = false;
        if (var.getDependsList().get(0) != gamma)
            ok = false;
        if (var.getDistribution() == null)
            ok = false;
        if (var.getDistribution().getParameter(0) != gamma)
            ok = false;
        
        if (ok)
            this.tests.add(true);
        else
            this.tests.add(false);
        
        // 24 
        expected = "In null: 'COUNT(&varname)' must be the only element of an equation if it is used" +
                " (line 0)";
        parseVariableTest(null, false, "iota = COUNT (&x) + 24*zeta", variableMapper, expected);
        // 25
        expected = "In null: 'SUM(&varname)' must be the only element of an equation if it is used" +
                " (line 0)";
        parseVariableTest(null, false, "iota = SUM (&x) + 24*zeta", variableMapper, expected);
        
        
        // 26
        variableMapper = new HashMap<String, Variable>();
        ComputationalModelParser.spatAffectedMap = new HashMap<Variable, String>();
        ComputationalModelParser.toBeChecked = new ArrayList<Variable>();
        
        
        var = parseVariableTest(null, false, "iota = SUM (&gamma)", variableMapper, null);
        String affname = ComputationalModelParser.spatAffectedMap.get(var);
        Variable aff = variableMapper.get(affname);
        if (aff == null){
            if (debug){
                System.out.println("Gamma that was not defined was not found, ok");
            }
            tests.add(true);
        } else
            tests.add(false);
        
        // 27
        variableMapper = new HashMap<String, Variable>();
        ComputationalModelParser.spatAffectedMap = new HashMap<Variable, String>();
        ComputationalModelParser.toBeChecked = new ArrayList<Variable>();
        
        gamma = new Variable();
        gamma.setName("gamma");
        gamma.setType(true);
        variableMapper.put(gamma.getName(), gamma);
        
        var = parseVariableTest(null, false, "iota = SUM (&gamma)", variableMapper, null);
        affname = ComputationalModelParser.spatAffectedMap.get(var);
        aff = variableMapper.get(affname);
        ok = true;
        if (aff == null){
            if (debug){
                System.out.println("Gamma that was defined was not found");
            }
            ok = false;
        }
        if (var.getName().equals("iota") == false)
            ok = false;
        if (var.isInteger() == true)
            ok = false;
        if (var.isData() == true)
            ok = false;
        if (var.isFunctional() == false)
            ok = false;
        if (var.isSpatial() == false)
            ok = false;
        if (var.getEquation().getEquation()[0].equals("SUM(&") == false)
            ok = false;
        if (var.getEquation().getEquation()[1].equals("gamma") == false)
            ok = false;
        
        if (ok){
            if (debug){
                System.out.println("Test "+ i + " ok");
            }
            this.tests.add(true);
        } else{
            if (debug){
                System.out.println("Test "+ i + " failed");
            }
            this.tests.add(false);
        }
        
        
        // 28
        variableMapper = new HashMap<String, Variable>();
        
        expected = "In null: Variable 1 on line 0 is not defined before it is used";
        parseVariableTest(null, false, "iota = 24*zeta", variableMapper, expected);
        
        // 29
        variableMapper = new HashMap<String, Variable>();
        ComputationalModelParser.spatAffectedMap = new HashMap<Variable, String>();
        ComputationalModelParser.toBeChecked = new ArrayList<Variable>();
        
        gamma = new Variable();
        gamma.setName("gamma");
        gamma.setType(true);
        variableMapper.put(gamma.getName(), gamma);
        
        var = parseVariableTest(null, false, "iota = 28 * gamma * gamma *BLAH(24)", variableMapper, null);
        ok = true;
        
        if (var.getName().equals("iota") == false)
            ok = false;
        if (var.isInteger() == true)
            ok = false;
        if (var.isData() == true)
            ok = false;
        if (var.isFunctional() == false)
            ok = false;
        if (var.isSpatial() == true)
            ok = false;
        if (var.getEquation().getEquation()[0].equals("28*") == false)
            ok = false;
        if (var.getEquation().getEquation()[1].equals("gamma") == false)
            ok = false;
        if (var.getEquation().getEquation()[2].equals("*") == false)
            ok = false;
        if (var.getEquation().getEquation()[3].equals("gamma") == false)
            ok = false;
        if (var.getEquation().getEquation()[4].equals("*BLAH(24)") == false)
            ok = false;
        
        if (var.getDependsList().get(0) != gamma)
            ok = false;
        if (gamma.getAffectsList().get(0) != var)
            ok = false;
        
        if (ok){
            if (debug){
                System.out.println("Test "+ i + " ok");
            }
            this.tests.add(true);
        } else{
            if (debug){
                System.out.println("Test "+ i + " failed");
            }
            this.tests.add(false);
        }
        
    }
    
    public ArrayList<Boolean> parseVariableUnitTest() throws SyntaxException{
        this.testIt();
        return this.tests;
    }
    
    public void commandLineParseVariableUnitTest()  throws SyntaxException{
        this.testIt();
        
        System.out.println("Ran "+ tests.size() + " tests");
        
        boolean falseFound = false;
        for (int j = 0; j < tests.size(); ++j){
            if (tests.get(j) == false){
                falseFound = true;
                System.out.println("Test "+ (j +1) + " failed");
            }
        }
        if (!falseFound)
            System.out.println("All tests passed.");
        
        
    }
    
    
}
