package tmcsim.cadsimulator;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.logging.Level;
import java.util.logging.Logger;
import junit.framework.TestCase;
import static org.mockito.Mockito.mock;
import tmcsim.cadsimulator.viewer.CADConsoleViewer;
import tmcsim.common.CADEnums;
import tmcsim.common.ScriptException;
import tmcsim.common.SimulationException;
import tmcsim.interfaces.CADClientInterface;
import tmcsim.interfaces.SimulationManagerInterface;

/**
 * Test of CADSimulator Console
 *
 * @author jdalbey
 */
public class CADSimulatorConsoleTest extends TestCase
{

    private static CADServer app = null;
    private CADConsoleViewer console;
    private StringWriter sw;

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

    public void setUp() throws Exception
    {
        super.setUp();
        writeConfigData();
        // Since CADSimulator has registry, we musn't instantiate it more than once
        if (app == null)
        {
            try
            {
                app = new CADServer("config.txt");
            } catch (Exception ex)
            {
                fail("Couldn't launch CADSimulator");
            }
        }
        console = (CADConsoleViewer) app.theViewer;
        sw = new StringWriter();
        console.setWriter(sw);
    }

    @Override
    public void tearDown() throws java.io.IOException
    {
        File removeMe = new File("config.txt");
        removeMe.delete();
        removeMe = new File("pconfig.txt");
        removeMe.delete();
        removeMe = new File("empty.txt");
        removeMe.delete();
    }

    /**
     * compare StringWriter contents against expected
     */
    private void verify(String msg, String expect)
    {
        String result = sw.toString().trim();
        result = result.replaceAll("\n", ",");
        String fullExpect = expect.trim();
        fullExpect = fullExpect.replaceAll("\n", ",");
//        System.out.println(fullExpect);
//        System.out.println(result.substring(result.length() - fullExpect.length(), result.length()));
//        String diff = StringUtils.difference(fullExpect, result);
        boolean match = result.endsWith(fullExpect);
        assertTrue(msg + ": " + result, match);
    }

    public static void pause(int millis)
    {
        try
        {
            Thread.sleep(millis);
        } catch (InterruptedException ex)
        {
        }
    }

    /**
     * The tests must be all run in one method, because the order matters. As
     * separate methods, we couldn't control which is executed first.
     *
     * @throws java.io.IOException
     * @throws SimulationException
     * @throws ScriptException
     */
    public void testAll() throws java.io.IOException, SimulationException, ScriptException
    {
        CADConsoleViewer console = (CADConsoleViewer) app.theViewer;
        String expected1 =
                "--- CAD Simulator ---\n"
                + "Elapsed Simulation Time     : 0:00:00\n"
                + "Status                      : No Script\n"
                + "Connected CAD Terminals     : 0\n"
                + "Simulation Manager Connected: No\n"
                + "Connected to Paramics       : No\n"
                + "Network Loaded              : None\n"
                + "-- Info Messages --\n\n"
                + "-- Error Messages --";
        System.out.println("setVisible");
        console.setVisible(true);
        verify("Initial output incorrect: ", expected1);
        String expected2 =
                "--- CAD Simulator ---\n"
                + "Elapsed Simulation Time     : 0:00:00\n"
                + "Status                      : No Script\n"
                + "Connected CAD Terminals     : 1\n"
                + "Simulation Manager Connected: No\n"
                + "Connected to Paramics       : No\n"
                + "Network Loaded              : None\n"
                + "-- Info Messages --\n\n"
                + "-- Error Messages --\n\n";

        System.out.println("connect one");
        CADClientInterface ci = mock(CADClientInterface.class);
        app.theCoordinator.registerForCallback(ci);
        verify("connected 1 terminal output incorrect: ", expected2);
        String expected3 =
                "--- CAD Simulator ---\n"
                + "Elapsed Simulation Time     : 0:00:00\n"
                + "Status                      : No Script\n"
                + "Connected CAD Terminals     : 2\n"
                + "Simulation Manager Connected: No\n"
                + "Connected to Paramics       : No\n"
                + "Network Loaded              : None\n"
                + "-- Info Messages --\n\n"
                + "-- Error Messages --\n\n";
        System.out.println("connect two");
        app.theCoordinator.registerForCallback(ci);
        verify("connected 2 terminals output incorrect: ", expected3);
        System.out.println("disconnect");
        app.theCoordinator.unregisterForCallback(ci);
        verify("disconnect terminal output incorrect: ", expected2);
        app.theCoordinator.unregisterForCallback(ci);
        String expected4 =
                "--- CAD Simulator ---\n"
                + "Elapsed Simulation Time     : 0:00:00\n"
                + "Status                      : No Script\n"
                + "Connected CAD Terminals     : 0\n"
                + "Simulation Manager Connected: Yes\n"
                + "Connected to Paramics       : No\n"
                + "Network Loaded              : None\n"
                + "-- Info Messages --\n\n"
                + "-- Error Messages --\n\n";
        System.out.println("sim mgr connect");
        SimulationManagerInterface si = mock(SimulationManagerInterface.class);
        app.theCoordinator.registerForCallback(si);
        verify("sim mgr connected output incorrect: ", expected4);
        String expected5 =
                "--- CAD Simulator ---\n"
                + "Elapsed Simulation Time     : 0:00:00\n"
                + "Status                      : No Script\n"
                + "Connected CAD Terminals     : 0\n"
                + "Simulation Manager Connected: Yes\n"
                + "Connected to Paramics       : No\n"
                + "Network Loaded              : None\n"
                + "-- Info Messages --\n"
                + ". = Console Info Message.\n"
                + "-- Error Messages --\n\n";
        System.out.println("Info msg");
        Logger cadSimLogger = Logger.getLogger("tmcsim.cadsimulator");
        cadSimLogger.logp(Level.INFO, "", "", "Console Info Message.");
        verify("Info message output incorrect: ", expected5);
        String expected7 =
                "--- CAD Simulator ---\n"
                + "Elapsed Simulation Time     : 0:00:00\n"
                + "Status                      : No Script\n"
                + "Connected CAD Terminals     : 0\n"
                + "Simulation Manager Connected: Yes\n"
                + "Connected to Paramics       : No\n"
                + "Network Loaded              : None\n"
                + "-- Info Messages --\n"
                + ". = Console Info Message.\n"
                + "-- Error Messages --\n"
                + "Someclass.Somemethod = Something bad happened.\n";
        System.out.println("Error msg");
        cadSimLogger = Logger.getLogger("tmcsim.cadsimulator");
        cadSimLogger.logp(Level.SEVERE, "Someclass", "Somemethod", "Something bad happened.");
        verify("Error message output incorrect: ", expected7);
        String expected6 =
                "--- CAD Simulator ---\n"
                + "Elapsed Simulation Time     : 0:00:00\n"
                + "Status                      : No Script\n"
                + "Connected CAD Terminals     : 0\n"
                + "Simulation Manager Connected: Yes\n"
                + "Connected to Paramics       : Yes\n"
                + "Network Loaded              : None\n"
                + "-- Info Messages --\n"
                + ". = Console Info Message.\n"
                + "-- Error Messages --\n"
                + "Someclass.Somemethod = Something bad happened.\n";
        System.out.println("Paramics connect");
        app.theCoordinator.setParamicsStatus(CADEnums.PARAMICS_STATUS.CONNECTED);
        pause(500);
        pause(500);
        verify("paramics connected should be yes", expected6);
        String expected8 =
                "--- CAD Simulator ---\n"
                + "Elapsed Simulation Time     : 0:00:00\n"
                + "Status                      : Ready\n"
                + "Connected CAD Terminals     : 0\n"
                + "Simulation Manager Connected: Yes\n"
                + "Connected to Paramics       : Yes\n"
                + "Network Loaded              : None\n"
                + "-- Info Messages --\n"
                + ". = Console Info Message.\n"
                + "-- Error Messages --\n"
                + "Someclass.Somemethod = Something bad happened.\n";
        String expected9 =
                "--- CAD Simulator ---\n"
                + "Elapsed Simulation Time     : 0:00:01\n"
                + "Status                      : Running\n"
                + "Connected CAD Terminals     : 0\n"
                + "Simulation Manager Connected: Yes\n"
                + "Connected to Paramics       : Yes\n"
                + "Network Loaded              : None\n"
                + "-- Info Messages --\n"
                + ". = Console Info Message.\n"
                + "-- Error Messages --\n"
                + "Someclass.Somemethod = Something bad happened.\n";
        System.out.println("Sim status");
        // Load a script file - to put status at Ready
        String autoloadScriptname = "scripts/one-incident.xml";
        app.theCoordinator.loadScriptFile(new File(autoloadScriptname));
        pause(500);
        verify("Status should be 'ready'", expected8);
        // startSimulation to put status at Running
        app.theCoordinator.startSimulation();
        pause(500);
        verify("Status should be 'running', time should be 0:01", expected9);
    }
//    public void testNetworkID()
//    {
//        String expected10 =
//                "--- CAD Simulator ---\n"
//                + "Elapsed Simulation Time     : 0:00:00\n"
//                + "Status                      : No Script\n"
//                + "Connected CAD Terminals     : 0\n"
//                + "Simulation Manager Connected: No\n"
//                + "Connected to Paramics       : No\n"
//                + "Network Loaded              : 17\n"
//                + "-- Info Messages --\n\n"
//                + "-- Error Messages --\n\n";
//        // this will tell the model it has a new network ID
//        cadmodel.setParamicsNetworkLoaded("17");
//        cadmodel.setParamicsStatus(CADEnums.PARAMICS_STATUS.LOADED);
//        pause(500);
//        verify("network id should be 17", expected10);
//    }
//    ByteArrayOutputStream bos;
//    PrintStream ps;
    static final String configData =
            "CADClientPort          = 4444 \n"
            + "CoordinatorRMIPort     = 4445 \n"
            + "CADRmiPort             = 4446 \n"
            + "UserInterface          = tmcsim.cadsimulator.viewer.CADConsoleViewer\n"
            + "ParamicsProperties     = pconfig.txt\n"
            + "ATMSProperties         = empty.txt\n"
            + "MediaProperties        = empty.txt\n";
    static final String paramicsData = "ParamicsCommHost = 127.0.0.1\n"
            + "ParamicsCommPort       = 4450\n"
            + "IncidentUpdateInterval = 30\n"
            + "IncidentUpdateFile     = exchange.xml\n"
            + "ParamicsStatusInterval = 15\n"
            + "ParamicsStatusFile     = paramics_status.xml\n"
            + "CameraStatusInterval   = 30\n"
            + "CameraStatusFile       = camera_status.xml\n";
    static final String cardfileURL = "http://pastebin.com/raw/Yr26nfp7";
    static final String smallXMLURL = "http://pastebin.com/raw/Eqj2N5qD";
    /*
     * Creating instance of app must be done only once or you get registry
     * bind problems, and code Written in Constructor is Executed
     * before each Test Method
     */

    private void writeConfigData()
    {
        // Declare a stream to the output
//        bos = new ByteArrayOutputStream();
//        ps = new PrintStream(bos);
        // Redirect the standard output
//        System.setOut(ps);
        writedata("config.txt", configData);
        writedata("pconfig.txt", paramicsData);
        writedata("empty.txt", "");
        writeScriptfiles();
    }

    private void writeScriptfiles()
    {
        new File("scripts").mkdir();
        writedata("scripts/Cardfile.xml", cardfileData);
        writedata("scripts/one-incident.xml", oneincidentXML);
    }

    // Write the test data to a file
    private void writedata(String filename, String data)
    {
        File cardFile = new File(filename);
        // If a cardfile exists, leave it
        if (!cardFile.exists())
        {
            PrintWriter writer = null;
            try
            {
                writer = new PrintWriter(new FileWriter(filename));
                writer.println(data);
                writer.close();
            } catch (Exception ex)
            {
                ex.printStackTrace();
            }
        }
    }
    private static final String cardfileData =
            "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
            + "<!--Please do not modify titles. Note that these titles are not"
            + "sent into the actual screen. If titles are to be modified,"
            + "they need to be changed in CardfileHandler.java  -->"
            + ""
            + ""
            + ""
            + "<CARDFILE> "
            + "	<TAB title = \"Coastal Division Units\">"
            + "		<CARDFILE_OBJ name = \"Name\" >"
            + "			<ADDRESS>Address</ADDRESS>"
            + "			<CITY>City</CITY>"
            + "			<STATE>State</STATE>"
            + "			<ZIP>Zip</ZIP>"
            + "			<PHONE1>Phone1</PHONE1>"
            + "			<PHONE2>Phone2</PHONE2>"
            + "			<FAX>Fax</FAX>"
            + "		</CARDFILE_OBJ>"
            + "		"
            + "		<CARDFILE_OBJ  name = \"Name2\" >"
            + "			<ADDRESS>Address2</ADDRESS>"
            + "			<CITY>City2</CITY>"
            + "			<STATE>State2</STATE>"
            + "			<ZIP>Zip2</ZIP>"
            + "			<PHONE1>Phone12</PHONE1>"
            + "			<PHONE2>Phone22</PHONE2>"
            + "			<FAX>Fax2</FAX>"
            + "		</CARDFILE_OBJ>"
            + "		"
            + "	</TAB>"
            + "	"
            + "	<TAB title = \"Police/Sheriff/Coroner\">"
            + "	"
            + "		<CARDFILE_OBJ  name = \"Name\" >"
            + "			<ADDRESS>Address</ADDRESS>"
            + "			<CITY>City</CITY>"
            + "			<STATE>State</STATE>"
            + "			<ZIP>Zip</ZIP>"
            + "			<PHONE1>Phone1</PHONE1>"
            + "			<PHONE2>Phone2</PHONE2>"
            + "			<FAX>Fax</FAX>"
            + "		</CARDFILE_OBJ>"
            + "		"
            + "	</TAB>"
            + "	"
            + "	<TAB title = \"Courts\">"
            + "		"
            + "		"
            + "		"
            + "	</TAB>"
            + "	"
            + "	<TAB title = \"Public Transportation\">"
            + "		"
            + "		"
            + "		"
            + "	</TAB>"
            + "	"
            + "	<TAB title = \"GG Other\">"
            + "		"
            + "		"
            + "		"
            + "	</TAB>"
            + "	"
            + "	<TAB title = \"MY Misc\">"
            + "		"
            + "		"
            + "		"
            + "	</TAB>"
            + "	"
            + "	<TAB title = \"SL Misc\">"
            + "		"
            + "		"
            + "		"
            + "	</TAB>"
            + "	"
            + "	<TAB title = \"VT Misc\">"
            + "		"
            + "		"
            + "		"
            + "	</TAB>"
            + "	"
            + "	<TAB title = \"CHP Offices\">"
            + "		"
            + "		"
            + "		"
            + "	</TAB>"
            + "	"
            + "	<TAB title = \"State Agencies/Facilities\">"
            + "		"
            + "		"
            + "		"
            + "	</TAB>"
            + "	"
            + "	<TAB title = \"Government Officials\">"
            + "		"
            + "		"
            + "		"
            + "	</TAB>"
            + "	"
            + "	<TAB title = \"Federal Agencies\">"
            + "		"
            + "		"
            + "		"
            + "	</TAB>"
            + "	"
            + "	<TAB title = \"Fire/EMS\">"
            + "		"
            + "		"
            + "		"
            + "	</TAB>"
            + "	"
            + "	<TAB title = \"Jails\">"
            + "		"
            + "		"
            + "		"
            + "	</TAB>"
            + "	"
            + "	<TAB title = \"Hospitals/Med Centers\">"
            + "		"
            + "		"
            + "		"
            + "	</TAB>"
            + "	"
            + "	<TAB title = \"Tow Companies\">"
            + "		"
            + "		"
            + "		"
            + "	</TAB>"
            + "	"
            + "	<TAB title = \"CalTrans\">"
            + "		"
            + "		"
            + "		"
            + "	</TAB>"
            + "	"
            + "	<TAB title = \"County Roads\">"
            + "		"
            + "		"
            + "		"
            + "	</TAB>"
            + "	"
            + "	<TAB title = \"Utilities\">"
            + "		"
            + "		"
            + "		"
            + "	</TAB>"
            + "	"
            + "	<TAB title = \"Animal Control\">"
            + "		"
            + "		"
            + "		"
            + "	</TAB>"
            + "	"
            + "	<TAB title = \"Airports\">"
            + "		"
            + "		"
            + "		"
            + "	</TAB>"
            + "	"
            + "	<TAB title = \"Credit Cards\">"
            + "		"
            + "		"
            + "		"
            + "	</TAB>"
            + "	"
            + "	<TAB title = \"GG Crisis Shelters\">"
            + "		"
            + "		"
            + "		"
            + "	</TAB>"
            + "	"
            + "	<TAB title = \"Ranges\">"
            + "		"
            + "		"
            + "		"
            + "	</TAB>"
            + "	"
            + "	<TAB title = \"Hotlines\">"
            + "		"
            + "		"
            + "		"
            + "	</TAB>"
            + "	"
            + "	<TAB title = \"Hwy Patrols OOS\">"
            + "		"
            + "		"
            + "		"
            + "	</TAB>"
            + "	"
            + "	<TAB title = \"Parks/Recreation\">"
            + "		"
            + "		"
            + "		"
            + "	</TAB>"
            + "	"
            + "	<TAB title = \"Shelters\">"
            + "		"
            + "		"
            + "		"
            + "	</TAB>"
            + "	"
            + "	<TAB title = \"SL County Services\">"
            + "		"
            + "		"
            + "		"
            + "	</TAB>"
            + "	"
            + "	<TAB title = \"SL Resources\">"
            + "		"
            + "		"
            + "		"
            + "	</TAB>"
            + "	"
            + "	<TAB title = \"Truck/Tire Repair\">"
            + "		"
            + "		"
            + "		"
            + "	</TAB>"
            + "	"
            + "	<TAB title = \"MCC Employees\">"
            + "		"
            + "		"
            + "		"
            + "	</TAB>"
            + "	"
            + "	<TAB title = \"Gate Access Codes\">"
            + "		"
            + "		"
            + "		"
            + "	</TAB>"
            + "	"
            + "	<TAB title = \"VT Call Signs\">"
            + "		"
            + "		"
            + "		"
            + "	</TAB>"
            + "	"
            + "	<TAB title = \"SLCC Employees\">"
            + "		"
            + "		"
            + "		"
            + "	</TAB>"
            + ""
            + "</CARDFILE>";
    private static final String oneincidentXML =
            "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>"
            + ""
            + "<TMC_SCRIPT title=\"One Incident Simulation\">"
            + ""
            + "	<SCRIPT_EVENT>"
            + "		<TIME_INDEX>00:00:00</TIME_INDEX>"
            + "		<INCIDENT LogNum=\"100\">Media Log</INCIDENT>		"
            + "		"
            + "		<CAD_DATA>"
            + "			<HEADER_INFO>"
            + "				<Type>Media</Type>"
            + "				<Beat>"
            + "				</Beat>"
            + "				<TruncLoc>"
            + "				</TruncLoc>"
            + "				<FullLoc>"
            + "				</FullLoc>"
            + "			</HEADER_INFO>			"
            + "			"
            + "			<CAD_INCIDENT_EVENT>	"
            + "			</CAD_INCIDENT_EVENT>		"
            + "			"
            + "		</CAD_DATA>				"
            + "		"
            + "	</SCRIPT_EVENT>	"
            + "</TMC_SCRIPT>";
}
