/**
 *
 */

package de.renew.lola2.test;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.FixMethodOrder;
import org.junit.Test;
import org.junit.runners.MethodSorters;

import CH.ifa.draw.io.DrawingFileHelper;
import CH.ifa.draw.io.StatusDisplayer;
import de.renew.draw.storables.ontology.Drawing;
import de.renew.gui.CPNDrawing;
import de.renew.lola2.LolaFileCreator;
import de.renew.lola2.analysis.LolaResult;
import de.renew.lola2.analysis.LolaResultStatus;
import de.renew.lola2.analysis.PropertyAnalyzer;

import static org.junit.Assert.assertEquals;


/** Tests properties of the given sample rnw files against the desired properties.
 *  This test can be run from junit/eclipse as well as ant task.
 *
 * @author Cabac
 *
 */
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
public class NetPropertiesTest implements StatusDisplayer {
    static private File[] _files;
    static private Map<String, File> _netFiles = new HashMap<String, File>();
    //    static private Map<String, CPNDrawing> _netDrawings = new HashMap<String, CPNDrawing>();
    static private PropertyAnalyzer _analyzer;
    static private List<ExpectedNetResult> _expectedResults = new ArrayList<>();
    static private String _hereName;
    static private int _numTestNets;

    private static class ExpectedNetResult {
        String _net;
        LolaResultStatus _bounded;
        LolaResultStatus _live;
        LolaResultStatus _reversible;

        private ExpectedNetResult(
            String net, LolaResultStatus bounded, LolaResultStatus live,
            LolaResultStatus reversible)
        {
            this._net = net;
            this._bounded = bounded;
            this._live = live;
            this._reversible = reversible;
        }
    }

    /** Determine Renew Checkout directory.
     * Prepare properties:
     * - boundedness
     *
     * @throws java.lang.Exception if directory setup or property initialization fails
     */
    @BeforeClass
    public static void setUpOnce() throws Exception {
        // trying to find the Renew checkout directory
        // - pwd for running in eclipse is Renew/ (default)
        // - pwd for running ant test is Renew/Lola/
        File here = new File("./");
        _hereName = here.getAbsolutePath();
        System.out.println("PWD is " + _hereName);
        while (!_hereName.endsWith("Renew")) {
            File parent = new File(_hereName).getParentFile();
            if (parent == null) {
                throw new RuntimeException("Could not find Renew directory");
            }
            _hereName = parent.getAbsolutePath();
            System.out.println("PWD is " + _hereName);
        }

        _numTestNets = 19;

        _expectedResults.add(
            new ExpectedNetResult(
                "bounded-live-reversible.rnw", LolaResultStatus.YES, LolaResultStatus.YES,
                LolaResultStatus.YES));
        _expectedResults.add(
            new ExpectedNetResult(
                "bounded-live-irreversible.rnw", LolaResultStatus.YES, LolaResultStatus.YES,
                LolaResultStatus.NO));
        _expectedResults.add(
            new ExpectedNetResult(
                "bounded-nonlive-reversible.rnw", LolaResultStatus.YES, LolaResultStatus.NO,
                LolaResultStatus.YES));
        _expectedResults.add(
            new ExpectedNetResult(
                "bounded-nonlive-irreversible.rnw", LolaResultStatus.YES, LolaResultStatus.NO,
                LolaResultStatus.NO));
        _expectedResults.add(
            new ExpectedNetResult(
                "unbounded-live-reversible.rnw", LolaResultStatus.NO, LolaResultStatus.ERROR,
                LolaResultStatus.ERROR));
        _expectedResults.add(
            new ExpectedNetResult(
                "unbounded-live-irreversible.rnw", LolaResultStatus.NO, LolaResultStatus.ERROR,
                LolaResultStatus.ERROR));
        _expectedResults.add(
            new ExpectedNetResult(
                "unbounded-nonlive-reversible.rnw", LolaResultStatus.NO, LolaResultStatus.NO,
                LolaResultStatus.ERROR));
        _expectedResults.add(
            new ExpectedNetResult(
                "unbounded-nonlive-irreversible.rnw", LolaResultStatus.NO, LolaResultStatus.ERROR,
                LolaResultStatus.ERROR));
        _expectedResults.add(
            new ExpectedNetResult(
                "simple-deadlock.rnw", LolaResultStatus.YES, LolaResultStatus.NO,
                LolaResultStatus.NO));
        _expectedResults.add(
            new ExpectedNetResult(
                "simple-unbounded.rnw", LolaResultStatus.NO, LolaResultStatus.ERROR,
                LolaResultStatus.ERROR));

        String os = System.getProperty("os.name").toLowerCase();

        if (os.contains("linux")) {
            _analyzer = new PropertyAnalyzer(_hereName + "/Lola2/lib/linux64");
        } else if (os.contains("mac")) {
            _analyzer = new PropertyAnalyzer(_hereName + "/Lola2/lib/macintel");
        } else if (os.contains("windows")) {
            _analyzer = new PropertyAnalyzer(_hereName + "/Lola2/lib/win64");
        }
    }

    /**
     * Erase temporary files
     * @throws java.lang.Exception if file deletion fails
     */
    @AfterClass
    public static void tearDownOnce() throws Exception {
        Iterator<String> iterator = _netFiles.keySet().iterator();
        while (iterator.hasNext()) {
            String net = iterator.next();
            _netFiles.get(net).delete();
        }
    }

    /** Read rnw files from Renew/Lola2/samples, prepare in hashmap
     * <code>_netfiles</code> and export to temporary net file.
     * @throws IOException if file reading or writing operations fail
     */
    @Test
    public void test1Export() throws IOException {
        // Read rnw files from Lola/samples, prepare in hashmap netfiles and export to temporary net file
        File dir = new File(_hereName + "/Lola2/src/main/resources/samples");
        System.out.println(dir.getCanonicalPath());
        if (dir.isDirectory()) {
            _files = dir.listFiles();
            for (int i = 0; i < _files.length; i++) {
                File file = _files[i];
                if (file.getName().endsWith("rnw")) {
                    System.out.println("" + i + " " + _files[i]);
                    Drawing loadDrawing = DrawingFileHelper.loadDrawing(file, this);
                    File temporaryLolaFile =
                        new LolaFileCreator().writeTemporaryLolaFile((CPNDrawing) loadDrawing);
                    //                    _netDrawings.put(file.getName(), (CPNDrawing) loadDrawing);
                    _netFiles.put(file.getName(), temporaryLolaFile);
                }
            }
        }
        System.out.println("netfiles = " + _netFiles);
        System.out.println("netfiles = " + _netFiles.keySet().size());

        assertEquals(_netFiles.keySet().size(), _numTestNets);
    }

    /**
     * Check of boundedness properties for 10 rnw files
     */
    @Test
    public void test2CheckBoundedness() {
        for (ExpectedNetResult expectedNetResult : _expectedResults) {
            File netFile = _netFiles.get(expectedNetResult._net);
            LolaResult boundednessResult = _analyzer.checkNetBoundedness(netFile);
            assertEquals(
                "Boundedness of " + expectedNetResult._net, expectedNetResult._bounded,
                boundednessResult.getStatus());
        }
    }

    /**
     * Check of liveness properties for 10 rnw files
     */
    @Test
    public void test3CheckLiveness() {
        for (ExpectedNetResult expectedNetResult : _expectedResults) {
            File netFile = _netFiles.get(expectedNetResult._net);
            LolaResult livenessResult = _analyzer.checkNetLiveness(netFile, true);
            assertEquals(
                "Liveness of " + expectedNetResult._net, expectedNetResult._live,
                livenessResult.getStatus());
        }
    }

    /**
     * Check of reversibility properties for 10 rnw files
     */
    @Test
    public void test4checkReversibility() {
        for (ExpectedNetResult expectedNetResult : _expectedResults) {
            File netFile = _netFiles.get(expectedNetResult._net);
            LolaResult reversibilityResult = _analyzer.checkNetReversibility(netFile);
            assertEquals(
                "Reversibility of " + expectedNetResult._net, expectedNetResult._reversible,
                reversibilityResult.getStatus());
        }
    }

    @Override
    public void showStatus(String message) {
        System.out.println(message);
    }
}