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

import CommonFunctions.debugPrinter;
import database.CoreDatabase;
import java.io.*;
import javax.microedition.io.SocketConnection;
import javax.microedition.io.Connector;
import java.util.Enumeration;
import java.util.Hashtable;
import database.Context;
import mdot.Main;
import structures.Constants;
import structures.HashContext;
import structures.NeighborStateDBValue;
import structures.RegionalManagerObject;
import utility.StringUtil;
import utility.J2SEToJ2MEUtil;

/**
 *class RM_CommunicationThread
 * Contacts regional manager every x seconds to get the vehicles in our area.
 * Constructs hashtable of neighbors from regional manager response.
 */
public class RMCommunicationThread extends Thread {

    private String stringSend;
    private SocketConnection tcpSocket;
    private int sleepTime = -1;

    public RMCommunicationThread(int tickTime) {
        HashContext me = Main.getMe();
        stringSend = Main.meString + Constants.DELIMITER_FOR_VIN + Main.portno_receive + Constants.DELIMITER_FOR_VIN + Main.password + Constants.DELIMITER_FOR_VIN + me.GetObjectAsString(Constants.HASH_LATITUDE) + Constants.DELIMITER_FOR_VIN + me.GetObjectAsString(Constants.HASH_LONGITUDE) + "\n";
        sleepTime = tickTime;
    }

    public String returnValues() {
        String stringToSend = Main.meString + Constants.DELIMITER_FOR_VIN + Main.portno_receive + Constants.DELIMITER_FOR_VIN + Main.password + Constants.DELIMITER_FOR_VIN + Main.getMe().GetObjectAsString(Constants.HASH_LATITUDE) + Constants.DELIMITER_FOR_VIN + Main.getMe().GetObjectAsString(Constants.HASH_LONGITUDE) + "\n";
        return stringToSend;
    }

    @Override
    public void run() {
        while (true) {
            try {
                if (sleepTime >= 40000) {
                    sleep(20000);
                    yield();
                    ContactRegionalManagers();
                    sleep(sleepTime - 20000);
                    yield();
                } else {
                    sleep(sleepTime);
                    yield();
                    ContactRegionalManagers();
                }
            } catch (Exception ex) {
                ex.printStackTrace();
            }
        }
    }

    /*
     * Send message with latitude and longitude position to each regional 
     * manager in the database using TCP socket.
     * Wait for and deserialize the reply.
     */
    public void ContactRegionalManagers() {

        Enumeration enRMs = CoreDatabase.rmVector.elements();
        while (enRMs.hasMoreElements()) {
            RegionalManagerObject tmp = (RegionalManagerObject)enRMs.nextElement();
            try {

                tcpSocket = (SocketConnection)Connector.open("socket://" +
                        tmp.getIPAddress() + ":" + Integer.parseInt(tmp.getPortNo()));

                stringSend = returnValues();
                
                OutputStream out = tcpSocket.openOutputStream();
                out.write(stringSend.getBytes());
                out.close();

                debugPrinter.printLine("from node to RM = " + stringSend);
             
                InputStream inStream = tcpSocket.openInputStream();
                DeserializeTCPInputStream(inStream);
                inStream.close();

                tcpSocket.close();
            } catch (Exception ex) {
                debugPrinter.printLine("RM connection error ");
            }
        }
    }

    /* Deserializes string received from regional manager.
     * Constructs hashtable of neighbors that are in our area.
     * Deletes vehicles that were previously in our area.
     */
    public void DeserializeTCPInputStream(InputStream input) {
        String inputString = null;
        
        //read the input string from the TCP socket
        try {

            InputStreamReader inReader = new InputStreamReader(input);
            inputString = J2SEToJ2MEUtil.readStrFrmInputStream(inReader);
            inReader.close();

            inputString = StringUtil.replace(inputString, "\n", "");
            debugPrinter.printLine("inputStr at mobile = " + inputString);
            if (inputString.equals("null")) {
                inputString = null;
            }

        } catch (Exception ex) {
            ex.printStackTrace();
            return;
        }

        try {
            debugPrinter.printLine("------------------------------------");
            debugPrinter.printLine("getting input from RM");
            debugPrinter.printLine("------------------------------------");
            Hashtable tmpHash = new Hashtable();

            if (inputString != null) {
                String[] entries = StringUtil.split(inputString, Constants.DELIMITER_ENTRY);
                
                //Create a hashtable of vehicles in our area
                for (int i = 0; i < entries.length; i++) {
                    String entry = entries[i];
                    debugPrinter.printLine("------------------------------------");
                    String name = StringUtil.split(entry, Constants.DELIMITER_FOR_VIN)[0];
                    debugPrinter.printLine("name = " + name);
                    debugPrinter.printLine("------------------------------------");
                    String ipAddress = StringUtil.split(entry, Constants.DELIMITER_FOR_VIN)[1];
                    int portno = Integer.parseInt(StringUtil.split(entry, Constants.DELIMITER_FOR_VIN)[2]);
                    String password = StringUtil.split(entry, Constants.DELIMITER_FOR_VIN)[3];
                    NeighborStateDBValue neighborEntry = new NeighborStateDBValue(ipAddress, portno, password);
                    tmpHash.put(name, neighborEntry);
                }

                //Remove vehicles that are no longer in our area
                Enumeration enKeys = Main.neighbors.neighborDatabase.keys();
                while (enKeys.hasMoreElements()) {
                    String key = (String)enKeys.nextElement();
                    if (!tmpHash.containsKey(key)) {
                        debugPrinter.printLine("removing from context -->" + key);
                        Main.getContext().remove(key);
                    }
                }

            }
            //No response from the Regional Manager
            //No vehicles in our area.
            else {
                Context.context = new Hashtable();
                debugPrinter.printLine("clearing context = " + Main.getContext().size());
            }

            //Update our neighborDatabase
            Main.neighbors.neighborDatabase = tmpHash;

        } catch (Exception ex) {
            ex.printStackTrace();
        }

    }
}
