package org.suffieldacademy.introcs;


import org.suffieldacademy.introcs.jhealy.LineSocket;

import java.io.IOException;
import lejos.hardware.ev3.EV3;
import lejos.hardware.ev3.LocalEV3;
import lejos.hardware.Key;
import lejos.hardware.KeyListener;
import lejos.hardware.lcd.Font;
import lejos.hardware.lcd.TextLCD;
import lejos.hardware.motor.EV3LargeRegulatedMotor;
import lejos.robotics.RegulatedMotor;
import lejos.utility.Delay;


/**
 * <p>
 * A skeleton class for a robot that can communicate with another
 * computer or robot using a network connection (most likely via Wi-Fi).
 * </p>
 *
 * <p>
 * This class contains all the code necessary to wait for inbound network
 * connections, accept them, and then hand off processing to a method that
 * you must complete.  It must be customized to actually send and receive
 * values from another program and act on the messages it sends and receives.
 * </p>
 *
 * <p>
 * Typically, this class must be tested with another program that uses the
 * LineSocket class for communication.
 * </p>
 *
 * @author Your Name
 *
 */
public class RobotServer {

        /** What port number to listen on (should be between 1024 and 65535).
         * The number is not too meaningful, but the other program that
         * connects to this one must use the same port number in order to
         * connect. */
        public static final int PORT = 12345;

        /** The EV3 brick being controlled */
        private EV3 brick;

        /** Left motor */
        private RegulatedMotor lMotor;

        /** Right motor */
        private RegulatedMotor rMotor;

        // add other variables here (motors, sensors, etc)


        /**
         * <p>
         * Main method; bootstraps and runs the robot.
         * </p>
         *
         * @param args Command-line arguments (not used)
         */
        public static void main(String[] args) {
                // construct the bot (you may need to add other parameters
                // to tell the robot about motors and sensors)
                RobotServer rs = new RobotServer(LocalEV3.get(), "A", "D");

                // listen for connections (this will call the connect() method
                // once a connection is established)
                rs.listen();
        }


        /**
         * <p>
         * Constructor.  Creates a new instance of the class and sets
         * it up so it's ready to go.  You should add code to this method
         * to perform any other necessary initialization (motors, sensors,
         * etc.).
         * </p>
         *
         * @param b The EV3 brick to associate with this robot
         * @param lPort The port that the left motor is connected to
         * @param rPort The port that the right motor is connected to
         */
        public RobotServer(EV3 b, String lPort, String rPort) {
                // store the brick instance
                brick = b;

                // establish a fail-safe: pressing Escape shuts down the network
                // server, which also causes the program to quit
                brick.getKey("Escape").addKeyListener(new KeyListener() {
                        @Override
                        public void keyPressed(Key k) {
                        }

                        @Override
                        public void keyReleased(Key k) {
                                if (null != server) {
                                        server.close();
                                }
                                else {
                                        System.exit(1);
                                }
                        }
                });
                println("Press Escape to exit");

                lMotor = new EV3LargeRegulatedMotor(brick.getPort(lPort));
                rMotor = new EV3LargeRegulatedMotor(brick.getPort(rPort));

                // Your code here: initialize any other motors, sensors, etc

        }


        /**
         * <p>
         * This method is called whenever a new request is received from the
         * network.  You must write code to inspect the message, take any
         * desired action, and return a response.
         * </p>
         *
         * @param r A message received from the network
         *
         * @return Any response generated after processing the request
         */
        public String request(String r) {
                // By default, this method simply logs a message that it didn't
                // process anything, and also returns that to the network client.
                // You'll need to replace this code with your own code that does
                // something useful.


                // NOTE WELL: if you want to see if a string is the same
                // as another string, you need to use a method called
                // "equals", NOT ==    For example:
                //
                // String a = "Something";
                // String b = "Something";
                // if (a.equals(b)) {
                //   println("a and b are the same");
                // }


                String response = "Ignored " + r;
                println(response);
                return response;
        }



        /*
         *
         *
         * You do not need to edit below this comment, though you are
         * welcome to read and make changes to figure out how this works!
         *
         *
         *
         */


        /** Text LCD to print to (see the println() method below) */
        private static TextLCD lcd = LocalEV3.get().getTextLCD(Font.getSmallFont());

        /** LineSocket used to listen for messages */
        private LineSocket.Server server;


        /**
         * <p>
         * Prints a message to the bottom of the LCD screen, and scrolls
         * any existing messages out of the way.
         * </p>
         *
         * @param msg The message to display
         */
        public static void println(String msg) {
                lcd.scroll();
                lcd.drawString(msg, 0, lcd.getTextHeight()-1);
        }


        /**
         * <p>
         * Listens for TCP/IP connections on the PORT specified above.
         * When a connection is made, control is handed off to the
         * connect() method above (which you must customize).
         * </p>
         *
         * <p>
         * When a connection closes, this method goes back to listening
         * for another connection.  If you only want to handle a single
         * connection before quitting, see the comments in the while loop
         * of the method.
         * </p>
         *
         * <p>
         * Otherwise, you do not need to make changes to this method.
         * </p>
         *
         */
        public void listen() {
                try {
                        server = LineSocket.getServer((String r) -> request(r),
                                        PORT, null);
                        server.join(); // wait indefinitely for connections
                }
                catch (IOException ioe) {
                        // report the error and quit
                        println(ioe.toString());
                        Delay.msDelay(30000);
                }
        }


}
