package scriptbuilder.structures;

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.util.ArrayList;
import java.util.Observable;
import java.util.Observer;
import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertTrue;
import static junit.framework.Assert.fail;
import junit.framework.TestCase;
import org.apache.commons.io.FileUtils;
import scriptbuilder.structures.events.ATMSEvaluationEvent;
import scriptbuilder.structures.events.AudioEvent;
import scriptbuilder.structures.events.CHPRadioEvent;
import scriptbuilder.structures.events.TMTRadioEvent;

/**
 *
 * @author Bryan McGuffin
 */
public class SimulationScriptTest extends TestCase implements Observer
{

    private boolean updateFlag = false;

    public SimulationScriptTest(String testName)
    {
        super(testName);
    }

    /**
     * Test of update method, of class SimulationScript.
     */
    public void testUpdate()
    {
        System.out.println("update");
        SimulationScript instance = new SimulationScript();

        updateFlag = false;
        assertFalse(updateFlag);

        instance.addObserver(this);
        instance.update();
        assertTrue(updateFlag);
    }

    /**
     * Test of broadcastEvent method, of class SimulationScript.
     */
    public void testBroadcastEvent_ScriptIncidentSliceChangedEvent()
    {
        System.out.println("broadcastEvent");
        ScriptIncident.SliceChangedEvent ev = new ScriptIncident.SliceChangedEvent(null);
        SimulationScript instance = new SimulationScript();

        updateFlag = false;
        assertFalse(updateFlag);

        instance.addObserver(this);
        instance.broadcastEvent(ev);
        assertTrue(updateFlag);
    }

    /**
     * Test of broadcastEvent method, of class SimulationScript.
     */
    public void testBroadcastEvent_ScriptIncidentIncidentFocusedEvent()
    {
        System.out.println("broadcastEvent");
        ScriptIncident.IncidentFocusedEvent ev = new ScriptIncident.IncidentFocusedEvent(null);
        SimulationScript instance = new SimulationScript();

        updateFlag = false;
        assertFalse(updateFlag);

        instance.addObserver(this);
        instance.broadcastEvent(ev);
        assertTrue(updateFlag);
    }

    /**
     * Test of loadScriptFromFile method, of class SimulationScript.
     */
    public void testLoadScriptFromFile()
    {
        System.out.println("loadScriptFromFile");
        File inFile = new File("test/scriptbuilder/structures/test_input_file.xml");
        SimulationScript instance = new SimulationScript();
        assertEquals(0, instance.incidentCount());

        instance.loadScriptFromFile(inFile);
        assertEquals(6, instance.incidentCount());
    }

    /**
     * Test of saveScriptToFile method, of class SimulationScript.
     */
    public void testSaveScriptToFile()
    {
        //This is basically identical to the integration test for saving and loading
        System.out.println("saveScriptToFile");
        try
        {
            File inFile = new File("test/scriptbuilder/structures/test_input_file.xml");
            assertTrue(inFile.exists());

            File outFile = new File("test/scriptbuilder/structures/test_output_file.xml");
            if (outFile.exists())
            {
                outFile.delete();
            }
            assertFalse(outFile.exists());

            outFile.createNewFile();

            assertTrue(outFile.exists());

            SimulationScript script = new SimulationScript();

            //Read in from test_input_file.xml
            script.loadScriptFromFile(inFile);

            //Save to test_output_file.xml
            script.saveScriptToFile(outFile);

            assertTrue(inFile.exists());
            assertTrue(outFile.exists());

            //Check to see if the two files are identical
            boolean result = FileUtils.contentEquals(inFile, outFile);

            assertTrue(result);
            //If so, data model does in fact read in all data and write it back in the correct format
        }
        catch (IOException ex)
        {
            fail("There was an IO exception. Check file names and locations.");
        }
    }

    /**
     * Test of toXML method, of class SimulationScript.
     */
    public void testToXML()
    {
        try
        {
            System.out.println("toXML");
            File inFile = new File("test/scriptbuilder/structures/test_input_file.xml");
            assertTrue(inFile.exists());
            SimulationScript instance = new SimulationScript();

            instance.loadScriptFromFile(inFile);

            String expResult = "";

            byte[] data = Files.readAllBytes(inFile.toPath());

            expResult = new String(data);
            String result = instance.toXML();
            assertEquals(expResult, result);
        }
        catch (IOException ex)
        {
            fail("There was an IO exception. Check file names and locations.");
        }
    }

    /**
     * Test of arrangeAllSlices method, of class SimulationScript.
     */
    public void testAllSlices()
    {
        System.out.println("allSlices");
        SimulationScript instance = new SimulationScript();

        instance.incidents.set(0, new ScriptIncident(121, null, null, instance));

        instance.incidents.set(1, new ScriptIncident(101, null, null, instance));

        ScriptEvent ev1_101 = new AudioEvent();

        ScriptEvent ev2_101 = new CHPRadioEvent();

        ScriptEvent ev1_121 = new TMTRadioEvent();

        ScriptEvent ev2_121 = new ATMSEvaluationEvent();

        instance.incidents.get(1).addNewEvent(ev1_101, 25);//Fourth
        instance.incidents.get(1).addNewEvent(ev2_101, 0);//Earliest; higher index. Second

        instance.incidents.get(0).addNewEvent(ev1_121, 0);//Earliest; lowest index. First
        instance.incidents.get(0).addNewEvent(ev2_121, 10);//Third

        ArrayList<TimeSlice> result = instance.arrangeAllSlices();
        assertEquals(4, result.size());
        assertEquals(ev1_121, result.get(0).events.get(0));
        assertEquals(ev2_101, result.get(1).events.get(0));
        assertEquals(ev2_121, result.get(2).events.get(0));
        assertEquals(ev1_101, result.get(3).events.get(0));

    }

    /**
     * Test of absoluteLength method, of class SimulationScript.
     */
    public void testAbsoluteLength()
    {
        System.out.println("absoluteLength");
        SimulationScript instance = new SimulationScript();
        int result = instance.absoluteLength();
        assertEquals(0, result);

        instance.incidents.set(0, new ScriptIncident(101, null, null, instance));
        instance.incidents.get(0).updateLength();
        assertEquals(0, instance.incidents.get(0).offset);
        assertEquals(0, instance.incidents.get(0).length);
        result = instance.absoluteLength();
        assertEquals(0, result);

        instance.incidents.get(0).addNewEvent(new AudioEvent(), 0);
        instance.incidents.get(0).updateLength();
        assertEquals(0, instance.incidents.get(0).offset);
        assertEquals(1, instance.incidents.get(0).length);
        result = instance.absoluteLength();
        assertEquals(1, result);

        instance.incidents.get(0).setOffset(10);
        instance.incidents.get(0).updateLength();
        assertEquals(10, instance.incidents.get(0).offset);
        assertEquals(1, instance.incidents.get(0).length);
        result = instance.absoluteLength();
        assertEquals(11, result);

        ((ScriptEvent) instance.incidents.get(0).slices.get(0).events.get(0)).length = 45;
        instance.incidents.get(0).updateLength();
        assertEquals(10, instance.incidents.get(0).offset);
        assertEquals(45, instance.incidents.get(0).length);
        result = instance.absoluteLength();
        assertEquals(55, result);
    }

    @Override
    public void update(Observable o, Object arg)
    {
        updateFlag = true;
    }

    /**
     * Test of incidentCount method, of class SimulationScript.
     */
    public void testIncidentCount()
    {
        System.out.println("incidentCount");
        SimulationScript instance = new SimulationScript();
        int result = instance.incidentCount();
        assertEquals(0, result);
        instance.incidents.set(0, new ScriptIncident(101, null, null, instance));
        result = instance.incidentCount();
        assertEquals(1, result);

    }

}
