package scriptbuilder.structures;

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.util.ArrayList;
import static junit.framework.Assert.assertTrue;
import junit.framework.TestCase;
import org.apache.commons.io.FileUtils;
import scriptbuilder.structures.events.*;
import static org.mockito.Mockito.*;
import scriptbuilder.structures.ScriptIncident.IncidentFocusedEvent;
import scriptbuilder.structures.ScriptIncident.SliceChangedEvent;

/**
 *
 * @author Bryan McGuffin
 */
public class ScriptIncidentTest extends TestCase
{

    SimulationScript mockedScript;

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

    /**
     * Test of setCollapsed method, of class ScriptIncident.
     */
    public void testSetCollapsed()
    {
        System.out.println("setCollapsed");
        mockedScript = mock(SimulationScript.class);
        ScriptIncident instance = new ScriptIncident(101, "Test_Incident", "Description", mockedScript);
        assertFalse(instance.collapsed);
        verify(mockedScript, times(0)).update();
        instance.setCollapsed(false);
        assertFalse(instance.collapsed);
        verify(mockedScript, times(1)).update();
        instance.setCollapsed(true);
        assertTrue(instance.collapsed);

        verify(mockedScript, times(2)).update();
    }

    /**
     * Test of setOffset method, of class ScriptIncident.
     */
    public void testSetOffset()
    {
        System.out.println("setOffset");
        mockedScript = mock(SimulationScript.class);
        ScriptIncident instance = new ScriptIncident(101, "Test_Incident", "Description", mockedScript);
        int offset = 10;
        assertEquals(0, instance.offset);
        verify(mockedScript, times(0)).update();
        instance.setOffset(offset);
        assertEquals(10, instance.offset);
        verify(mockedScript, times(1)).update();
        instance.setOffset(0);
        assertEquals(0, instance.offset);
        verify(mockedScript, times(2)).update();
    }

    /**
     * Test of addNewEvent method, of class ScriptIncident.
     */
    public void testAddNewEvent()
    {
        System.out.println("addNewEvent");
        mockedScript = mock(SimulationScript.class);
        ScriptIncident instance = new ScriptIncident(101, "Test_Incident", "Description", mockedScript);
        assertEquals(0, instance.length);
        assertEquals(0, instance.eventCount);
        I_ScriptEvent ev1 = mock(I_ScriptEvent.class);
        when(ev1.getLength()).thenReturn(1);
        I_ScriptEvent ev2 = mock(I_ScriptEvent.class);
        when(ev2.getLength()).thenReturn(4);
        I_ScriptEvent ev3 = mock(I_ScriptEvent.class);
        when(ev3.getLength()).thenReturn(4);
        int start = 0;
        instance.addNewEvent(ev1, start);
        assertEquals(1, instance.length);
        assertEquals(1, instance.eventCount);

        start = 0;
        instance.addNewEvent(ev2, start);
        assertEquals(4, instance.length);
        assertEquals(2, instance.eventCount);

        start = 2;
        instance.addNewEvent(ev3, start);
        assertEquals(6, instance.length);
        assertEquals(3, instance.eventCount);

    }

    /**
     * Test of getSlices method, of class ScriptIncident.
     */
    public void testGetSlices()
    {
        System.out.println("getSlices");
        mockedScript = mock(SimulationScript.class);
        ScriptIncident instance = new ScriptIncident(101, "Test_Incident", "Description", mockedScript);
        //Empty list; no events in incident
        ArrayList<TimeSlice> result = instance.getSlices();
        assertEquals(0, result.size());

        I_ScriptEvent ev1 = mock(I_ScriptEvent.class);
        when(ev1.getLength()).thenReturn(1);

        //One event, one timeslice
        instance.addNewEvent(ev1, 0);
        result = instance.getSlices();
        assertEquals(1, result.size());

        //Two simultaneous events start in the same timeslice
        instance.addNewEvent(ev1, 0);
        result = instance.getSlices();
        assertEquals(1, result.size());

        //A third event starts at a different time so it requires a new timeslice
        instance.addNewEvent(ev1, ev1.getLength() + 100);
        result = instance.getSlices();
        assertEquals(2, result.size());

    }

    /**
     * Test of setSliceActive method, of class ScriptIncident.
     */
    public void testSetSliceActive()
    {
        boolean passFlag = false;
        System.out.println("setSliceActive");
        mockedScript = mock(SimulationScript.class);
        ScriptIncident instance = new ScriptIncident(101, "Test_Incident", "Description", mockedScript);
        int time_a = 0;
        int time_b = 5;
        instance.setSliceActive(time_a);
        verify(mockedScript, never()).broadcastEvent(isA(SliceChangedEvent.class));
        instance.setSliceActive(time_b);
        verify(mockedScript, never()).broadcastEvent(isA(SliceChangedEvent.class));
        instance.addNewEvent(mock(I_ScriptEvent.class), time_a);
        instance.setSliceActive(time_a);
        verify(mockedScript, times(1)).broadcastEvent(isA(SliceChangedEvent.class));
        instance.setSliceActive(time_b);
        verify(mockedScript, times(1)).broadcastEvent(isA(SliceChangedEvent.class));
    }

    /**
     * Test of setIncidentActive method, of class ScriptIncident.
     */
    public void testSetIncidentActive()
    {
        System.out.println("setIncidentActive");
        mockedScript = mock(SimulationScript.class);
        ScriptIncident instance = new ScriptIncident(101, "Test_Incident", "Description", mockedScript);
        verify(mockedScript, never()).broadcastEvent(isA(IncidentFocusedEvent.class));
        instance.setIncidentActive();
        verify(mockedScript, times(1)).broadcastEvent(isA(IncidentFocusedEvent.class));

    }

    /**
     * Test of toString method, of class ScriptIncident.
     */
    public void testToString()
    {
        System.out.println("toString");
        mockedScript = mock(SimulationScript.class);
        ScriptIncident instance = new ScriptIncident(101, "Test_Incident", "Description", mockedScript);
        String expResult = "101 - Test_Incident";
        String result = instance.toString();
        assertEquals(expResult, result);

    }

    /**
     * Test of saveIncidentToFile method, of class ScriptIncident.
     */
    public void testSaveIncidentToFile()
    {
        try
        {
            System.out.println("saveIncidentToFile");
            File inFile = new File("test/scriptbuilder/structures/test_input_file.xml");
            assertTrue(inFile.exists());
            File referenceFile = new File("test/scriptbuilder/structures/single_incident_output_expected.xml");
            assertTrue(referenceFile.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());

            ScriptIncident instance = null;
            SimulationScript script = new SimulationScript();
            script.loadScriptFromFile(inFile);

            for (ScriptIncident inc : script.incidents)
            {
                if (inc != null && inc.number == 187)
                {
                    instance = inc;
                }
            }
            if (instance != null)
            {
                instance.saveIncidentToFile(outFile);
            }

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

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

            assertTrue(result);

        }
        catch (IOException ex)
        {
            fail("There was an IO exception. Check file names and locations.");
        }
    }

    /**
     * Test of toXML method, of class ScriptIncident.
     */
    public void testToXML()
    {
        try
        {
            System.out.println("toXML");
            File inFile = new File("test/scriptbuilder/structures/test_input_file.xml");
            assertTrue(inFile.exists());
            File referenceFile = new File("test/scriptbuilder/structures/single_incident_output_expected.xml");
            assertTrue(referenceFile.exists());
            ScriptIncident instance = null;
            SimulationScript script = new SimulationScript();
            script.loadScriptFromFile(inFile);
            for (ScriptIncident inc : script.incidents)
            {
                if (inc != null && inc.number == 187)
                {
                    instance = inc;
                }
            }

            String expResult;

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

            expResult = new String(data);

            String result = instance.toXML();
            assertEquals(expResult, result);

        }
        catch (Exception ex)
        {
            fail("There was an IO exception. Check file names and locations.");
        }
    }

    /**
     * Test of insertCadData method, of class ScriptIncident.
     */
    public void testInsertCadData()
    {
        System.out.println("insertCadData");
        CadData cad = new CadData();
        mockedScript = mock(SimulationScript.class);
        ScriptIncident instance = new ScriptIncident(100, "test", "test", mockedScript);

        assertEquals(0, instance.slices.size());
        instance.insertCadData(10, cad);
        assertEquals(1, instance.slices.size());
    }
}
