/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

/*
 * ExperimentLauncher.java
 *
 * Created on 30.08.2010, 10:14:33
 */

package de.delbrueg.experiment;

import champ2011client.Controller;
import de.delbrueg.steering.behaviour.CircleSteeringSettings;
import de.delbrueg.steering.behaviour.decision.LineOrCircleDeciders;
import de.delbrueg.steering.wheelAngle.WheelAngleCalculators;
//import de.janquadflieg.mrracer.controller.TimsExperimentController;
import de.janquadflieg.mrracer.network.ConnectionListener;
import de.janquadflieg.mrracer.network.ConnectionStatistics;
import de.janquadflieg.mrracer.network.UDPConnection;

/**
 *
 * @author Tim
 */
public class ExperimentLauncher extends javax.swing.JFrame implements ConnectionListener{

    Controller controller;
    UDPConnection connection;

    /** last:
    final double tw_min = 2.5;
    final double tw_max = 5.00001;
    final double tw_step = 0.25;
    final double ts_min = 0.08;
    final double ts_max = 0.20001;
    final double ts_step = 0.02;**/

    // change Settings
    final double tw_min = 2.5;
    final double tw_max = 5.00001;
    final double tw_step = 0.25;
    final double ts_min = 0.08;
    final double ts_max = 0.20001;
    final double ts_step = 0.02;
    Experiments exp = Experiments.race;

    // indicates if connection was established
    boolean conn_est = false;

    /** Creates new form ExperimentLauncher */
    public ExperimentLauncher() {
        initComponents();
    }

    /** This method is called from within the constructor to
     * initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is
     * always regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {

        jButton1 = new javax.swing.JButton();
        jScrollPane1 = new javax.swing.JScrollPane();
        jTextArea1 = new javax.swing.JTextArea();
        jTextField1 = new javax.swing.JTextField();
        jLabel1 = new javax.swing.JLabel();

        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);

        jButton1.setText("start");
        jButton1.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jButton1ActionPerformed(evt);
            }
        });

        jTextArea1.setColumns(20);
        jTextArea1.setRows(5);
        jScrollPane1.setViewportView(jTextArea1);

        jLabel1.setText("Track:");

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
        getContentPane().setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 426, Short.MAX_VALUE)
            .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
                .addContainerGap()
                .addComponent(jLabel1)
                .addGap(45, 45, 45)
                .addComponent(jTextField1, javax.swing.GroupLayout.PREFERRED_SIZE, 167, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addGap(18, 18, 18)
                .addComponent(jButton1, javax.swing.GroupLayout.PREFERRED_SIZE, 156, javax.swing.GroupLayout.PREFERRED_SIZE))
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addContainerGap()
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(jTextField1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addComponent(jLabel1)
                    .addComponent(jButton1, javax.swing.GroupLayout.PREFERRED_SIZE, 37, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 382, Short.MAX_VALUE))
        );

        pack();
    }// </editor-fold>//GEN-END:initComponents

    private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButton1ActionPerformed
        jButton1.setEnabled(false);
        init();


        Runnable starter = new Runnable() {

            @Override
            public void run() {

                execSync("MainMenuToQuickRace.exe");

                boolean ok = start();

                if( !ok ){
                    log("initial start was not successful!");
                    jButton1.setEnabled(true);
                }
                else{
                    log("initial start successful!");
                }
            }
        };
        java.awt.EventQueue.invokeLater(starter);
    }//GEN-LAST:event_jButton1ActionPerformed

    /**
    * @param args the command line arguments
    */
    public static void main(String args[]) {
        java.awt.EventQueue.invokeLater(new Runnable() {
            public void run() {
                ExperimentLauncher l = new ExperimentLauncher();
                l.setVisible(true);
                l.log("started... now please start Torcs and stay in main menu!");
            }
        });
    }

    private void init(){
        CircleSteeringSettings.car_track_width = tw_min;
        CircleSteeringSettings.time_step = ts_min;
        CircleSteeringSettings.use_lines = true;
        CircleSteeringSettings.ignore_plan = false;
        CircleSteeringSettings.line_or_circle_decider = LineOrCircleDeciders.QuadraticFailureDecider;
        CircleSteeringSettings.timestep_dynamic = false;
        CircleSteeringSettings.target_position_weight = 1;
        CircleSteeringSettings.wheel_angle_calculator = WheelAngleCalculators.SimpleQuotient;
        CircleSteeringSettings.car_prop_steering_factor = 0;
        

        log("init track_width to " + CircleSteeringSettings.car_track_width );
        log("init time_step to " + CircleSteeringSettings.time_step );
    }

    private boolean start(){

        log("-------------------------");
        log("------START--------------");
        log("-------------------------");

        // make torcs start new race!
        // we have to be in main menu!
        // send Enters
        execSync("QuickRaceStart.exe");

        // wait until map is loaded
        sleep(10000);


        // setup controller
        log("setup controller with experiment " + exp.name());
        log("track is " + jTextField1.getText());
        controller = null;//new TimsExperimentController(exp);
        controller.setStage(champ2011client.Controller.Stage.RACE);
        controller.setTrackName(jTextField1.getText());
        controller.reset();

        sleep(1000);

        // setup connection
        String ip = "127.0.0.1";
        int port = 3001;

        try{
            log("connecting...");
            connection = new UDPConnection(ip, port, controller);
            connection.addConnectionListener(this);
        }
        catch(Exception e){
            e.printStackTrace();
        }

        // wait for package
        conn_est = false;
        sleep(2000);

        // play 4x
        execSync("fastForward.exe");

        // check if package came
        return conn_est;
    }

    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JButton jButton1;
    private javax.swing.JLabel jLabel1;
    private javax.swing.JScrollPane jScrollPane1;
    private javax.swing.JTextArea jTextArea1;
    private javax.swing.JTextField jTextField1;
    // End of variables declaration//GEN-END:variables

    public void newStatistics(ConnectionStatistics data){
        if( !conn_est ){
            log("connected.");
            conn_est = true;
        }
    }

    public void stopped(boolean requested){
        log("-------------------------");
        log("        STOP");
        log("-------------------------");
        
        // experiment has finished!
        controller.shutdown();

        // change settings
        if( CircleSteeringSettings.car_track_width + tw_step > tw_max )
        {
            CircleSteeringSettings.car_track_width = tw_min;
            CircleSteeringSettings.time_step += ts_step;
            log("reset track_width to "+ tw_min+", inc time_step to "+CircleSteeringSettings.time_step + " (maximum is " + ts_max + ")");
        }
        else
        {
            CircleSteeringSettings.car_track_width += tw_step;
            log("increase track_width to " + CircleSteeringSettings.car_track_width + " (maximum is " + tw_max + ")");
            log("time_step is still "+CircleSteeringSettings.time_step + " (maximum is " + ts_max + ")");
        }

        // go back to main menu
        execSync("afterRaceToQuickRace.exe");

        // test if we have finished
        if(CircleSteeringSettings.time_step > ts_max ){
            // FINISHED !
            log("FINISHED!");
            return;
        }

        // if not finished, start new one!
        while( !start() ){
            System.out.println("start failed... retry");
            log("-------------------------");
            log("   start failed... retry...");
            log("-------------------------");
            sleep(300);
        }
    }

    private void sleep(int milli){
        log("sleeping "+milli+"ms");
        
        try{
            Thread.sleep(milli);
        }
        catch(InterruptedException e){
            log(e.toString());
        }
    }

    /**
     * executes the given exe in a fixed folder. The caller thread is suspended until the exe has finished.
     * @param exe
     */
    private void execSync(String exe){
        try{
            log("--starting "+exe+"...");
            String folder = "G:/Dokumente/Uni/6. Semester/Bachelorarbeit/Code/Code/projects/MrRacer/TorcsScripts/";
            Process process = Runtime.getRuntime ().exec (folder + exe);
            log("--waiting for "+exe+" to end...");
            process.waitFor();
            log("--"+exe+" finished.");
        }
        catch( Exception e ){
            log(e.toString());
        }
    }

    private void log(String entry){
        this.jTextArea1.append("\n");
        this.jTextArea1.append(entry);
        jTextArea1.setCaretPosition(jTextArea1.getText().length()-1);
        jTextArea1.repaint();
    }
}
