import java.awt.geom.Point2D;
import java.io.File;
import java.util.Arrays;

import jimena.binaryrn.RegulatoryNetwork;
import jimena.libs.StringLib;
import jimena.perturbation.OnOffPerturbation;
import jimena.simulation.BasicCalculationController;
import jimena.simulation.ProgressWindow;
import jimena.simulationmethods.NormalizedHillCubeMethod;
import jimena.ssssearcher.RandomSearcher;

/**
 * A collection of typical example which show how to use the simulation package as a library.
 * 
 * @author Stefan Karl, Department of Bioinformatics, University of Würzburg, stefan[dot]karl[at]uni-wuerzburg[dot]de
 * 
 */
public class Example {

    /**
     * @param args
     */
    public static void main(String[] args) {
        // Create a new GRN
        RegulatoryNetwork network = new RegulatoryNetwork();

        // Load a yED GraphML file into the network

        network.loadYEdFile(new File("Athaliana.graphml"));

        // List network nodes
        System.out.println(Arrays.toString(network.getNodeNames()));
        System.out.print("\n");

        // Set the SQUAD decay parameter for the third node
        network.getNetworkNodes()[2].setSQUADDecay(2D);

        // Set the SQUAD decay parameter for the AG node
        network.getNodeByName("AG").setSQUADDecay(2D);

        // Set the SQUAD weights of all inputs from WUS to AG to 2D
        for (Integer index : network.getInputIndicesByName("AG", "WUS")) {
            network.getNodeByName("AG").getSQUADWeights()[index] = 2D;
        }

        // Set value of the first node
        network.getNodeByName("FUL").setValue(1D);
        System.out.println("Old value of FUL: " + network.getNodeByName("FUL").getValue() + "\n");

        /*
         * Simulate the network using the Odefy model with normalized HillCubes, an differential equation solving step of 0.001 for 10
         * second (network time). Simulate as fast as possible (maxSpeed = Double.POSITIVE_INFINITY) and create a log entry every ~1.0
         * seconds. Since the network has no registered observers we can set the GUI refreshing interval to infinity. No calculation
         * controller is given (null).
         */
        network.simulate(new NormalizedHillCubeMethod(), 0.0001D, 10D, Double.POSITIVE_INFINITY, 1.0D, new BasicCalculationController());

        // The time index of network and its values are different now
        System.out.println("\nNew time index: " + network.getTimeIndex() + "\n");
        System.out.println("New value of FUL: " + network.getNodeByName("FUL").getValue() + "\n");

        // Print the log entries of the FUL node:
        for (Point2D.Double logEntry : network.getNodeByName("FUL").getLog()) {
            System.out.println(logEntry.getX() + ": " + logEntry.getY());
        }
        System.out.print("\n");

        // Reset the network (Resets all values to the initial values, resets the logs and sets the time index to 0.)
        // Does not reset the simulation parameters or perturbations
        network.reset();

        // Fix the first node to the value 1 between the time indices 0 and 5 by adding a perturbation to the node
        network.getNodeByName("WUS").getPerturbations().add(new OnOffPerturbation(0, 100, 1));

        // Simulate the network again. This time with a calculation controller: A progress window.
        network.simulate(new NormalizedHillCubeMethod(), 0.0001D, 10D, Double.POSITIVE_INFINITY, 1.0, new ProgressWindow());

        // Print the log entries of the first node:
        for (Point2D.Double logEntry : network.getNodeByName("WUS").getLog()) {
            System.out.println(logEntry.getX() + ": " + logEntry.getY());
        }
        System.out.print("\n");

        // Remove all perturbations before we calculate stable steady states
        // Otherwise they will be included in the calculation as assumptions
        network.removeAllPerturbations();

        /*
         * Note that all methods of RegulatoryNetwork block the current thread (even if they are threaded internally). You should not call
         * them in the default Swing GUI thread or the GUI will freeze.
         */

        /*
         * Calculate the stable steady state reached from the current values. A state is considered to be stable after all of its values
         * stay in an environment of 2*0.001 for 5 seconds. The search is conducted for no more than 1000 seconds (simulation time).
         */
        System.out.println(Arrays.toString(network.stableSteadyState(network.getValues(), 0.001D, 5D, new NormalizedHillCubeMethod(),
                0.01D, 100D, new ProgressWindow())));
        System.out.print("\n");

        /*
         * Calculate a subset of the stable steady states. A state is considered to be stable after all of its values stay in an environment
         * of 2*0.001 for 5 seconds. The search is conducted for no more than 1000 seconds per random start vector in simulation time and
         * 5000 ms real calculation time. 2 threads and a random searcher are used for the search.
         */
        StringLib.printDoubleVectorList(network.stableSteadyStates(0.001D, 5D, new NormalizedHillCubeMethod(), 0.01D, 100D, 0.001D, 5000,
                new ProgressWindow(), 4, new RandomSearcher()));
        System.out.print("\n");

        // Determine the stable steady states for a discrete model using BDDs
        StringLib.printByteVectorList(network.discreteStableSteadyStates());

        // Stop all GUI activities.
        System.exit(0);
    }
}
