/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package org.openremote.controller.protocol.ehouse;
import java.net.DatagramSocket;
import java.net.*;

/**
 *
 * @author robert
 */
public class EHouse4OpenRemote {
static boolean firsttime=true;
static ServerSocket providerSocket=null; 
    /**
     * @param args the command line arguments
     */
static void l(String line)
    {
    ehousecommunication.l(line);
    
    }
    public static void main(String[] args) {
        
        
        
 l("!!!!!!!! Starting eHouse application !!!!!!");
        
        
        
        
        
        
        
        EhouseTCP.StatusServerEnable=true;
//        EhouseTCP.Offline=true;
        EhouseTCP.UDPInit=true;
        EhouseTCP.UDPQueryPriority=Thread.MIN_PRIORITY;
        EhouseTCP.UDPEnabled=true;
        //EhouseTCP.UDPStarted=true;
        
        
        
    ehousecommunication.init();
        try{
            EhouseTCP.AllDevsTCPStatus();               //load Ethernet Ehouse Devs cache config
        }
        catch (Exception e){
            l("Err 7:"+e.getMessage());
        }
        try{
            EhouseTCP.AllDevsStatus();      //load Ehouse1 Devs cache Config
        }
        catch (Exception e){
            l("Err 8:"+e.getMessage());
        }
      
      
    //eHouse UDP
        if (EhouseTCP.UDPInit){                 //Start UDP listener for reception status from Ethernet eHouse Controllers
//    EhouseTCP.UDPInit=false;
            try{
                //QueryUDP.start();
                if (!QueryUDP.isAlive())
                if (QueryUDP.getState()!=Thread.State.RUNNABLE){
                    QueryUDP.setPriority(Thread.MIN_PRIORITY);
                    QueryUDP.start();
                }
            }
            catch(Exception ie){
        ehousecommunication.l("ErQ: "+ie.getMessage()+" UDP Query -> "+QueryUDP.getState().toString());
            }
        
        }

        
    
        firsttime=false;
        
        



/// Server for Open Remote inicialisation

        if (EhouseTCP.StatusServerEnable)
            {    
            try
                {
                   
                if (!StatusOR.isAlive())
                    if (StatusOR.getState()!=Thread.State.RUNNABLE)
                        {
                        StatusOR.setPriority(Thread.MIN_PRIORITY);
                        StatusOR.start();
                        }
                }
            catch(Exception ie)
                {
                
                //ehousecommunication.Log
                l("ErQ: "+ie.getMessage()+" Status Sever TCP IP -> "+StatusOR.getState().toString());
                }

            }



    
    
        
        
        
        
        
        //ehousecommunication.AddAsciiEvent("00 d0 01 01 02 00 00 00 00 00 00 00 00 00");
        //ehousecommunication.SendWiFi("",0);
        // TODO code application logic here
     
    }

    
    
/**
 * Creates a socket ready to receive data from drivers. Updates visualization.
 * 
 * @param port 
 */
    public static void udp(int port){
        DatagramSocket ds=null;     
        byte[] message=new byte[2000];          ///buffer for datapacket
        byte[] broadcastadr = new byte[4];      //broadcast decoded ip address
        byte[] localadr=new byte[4];            //local ip address of device decoded
        boolean fail=false; ///encounter error someware inside this function
        if (ehousecommunication.Terminate) return;   // if during terminating application
        if (!EhouseTCP.UDPEnabled) return;          //udp flag for enable udp connection
        if (EhouseTCP.UDPStarted) return;           //if udp is started then do not create another connection
        
            broadcastadr[0]=(byte)192;
            broadcastadr[1]=(byte)168;
            broadcastadr[2]=(byte)0;
            broadcastadr[3]=(byte)255;
        
        try{
      
            ds=new DatagramSocket(port);///listening udp data on port from any ip inside a mask 
        }
        catch (Exception e){
              fail=true;
              //ehousecommunication.l("Error Inet: get address"+e.getMessage()); for test
         }
        try{
            ds.setBroadcast(true);     //enable send broadcast message
            ds.setReuseAddress(true);  //enable multiple socket use the same IP address
            ds.setSoTimeout(0);    //reception timeout 201203 byĹ‚o 400
        }
        catch (Exception io){
            fail=true;    
        }

  

        EhouseTCP.UDPStarted=true;    
        while (!ehousecommunication.Terminate){   //infinite loop for udp reception
    
            DatagramPacket dp=new DatagramPacket(message,message.length);        //create udp datagram packet using data buffer
            try{
        
                ds.receive(dp);      //udp packet reception from ehouse system
                int siz=dp.getLength();
                if (siz>0){
                    byte[] temp    =new byte[2000];
        
                    temp=dp.getData(); //assign udp broadcast recepition to querybuffer
                    for (int i=1;i<siz;i++) EhouseTCP.QueryBuff[i-1] = temp[i];
                    dp.setLength(0);
                    EhouseTCP.QueryReceived();    //decode query data and fill devices arrays
                }
            }
            catch (Exception os){
        //     ehousecommunication.l("asdfasdfsafsa"+os.getMessage())  ;   //for test only           
            }   
            if (!EhouseTCP.UDPEnabled) break;
    
        }
        try{
            ds.close();   //close datagram socket at the end
        }
        catch (Exception e){

        }
        EhouseTCP.UDPStarted=false;    
    }
    
/////////////////////////////////////////////////////////////////////////////////    
/**
 *  UDP Broadcast status reception thread
 */    
public  static Thread  QueryUDP=new Thread(){
        @Override
        public void run(){
            setPriority(EhouseTCP.UDPQueryPriority);
            if (EhouseTCP.UDPStarted) return;           //ensure wasnt started
            if (EhouseTCP.QueryConnected) return;       
            while (!ehousecommunication.Terminate)
                {
                try
                    {           
                    if (!EhouseTCP.UDPStarted)
                        {
                        if (EhouseTCP.UDPEnabled) udp(Integer.parseInt(ehousecommunication.UDPStatusReceptionPort));
                        }
                    if (!ehousecommunication.Terminate) 
                        sleep(200);
                    
                    }
                catch (Exception e)  //ignoring all exceptions
                    {
                    //   return;
                        //break;
                    }
        
                }
            
        }
    };    
    
/**
 *  Multi Thread Server non blocking for current support of OpenRemote queries via TCP/IP sockets
 */    
    
 public static  Thread  StatusOR=new Thread()
 {
        @Override
    public void run()
        {
            Socket newSock;
            int ServerInstance=0;
            setPriority(EhouseTCP.StatusServerPriority);            //set priority from global varibles
            try
                    {
                    providerSocket = new ServerSocket(ehousecommunication.OpenRemotePortNr);        //Creating TCP server socket for Open Remote
                    }
            catch (Exception e)
                {
                    l("Exception in creating ServerSocket #"+String.valueOf(EhouseTCP.CurrentORSensorConnection)+" -> "+e.getMessage());
                    
                }
            
            while (!ehousecommunication.Terminate)                  //if Terminate Flag then break
                {
                if (!ehousecommunication.OpenRemoteTCPStatusEnabled) return;    
                
                try
                    {           
                    
			l("Waiting for connection #"+EhouseTCP.CurrentORSensorConnection);
                            newSock = providerSocket.accept();              //Accept New Client Socket Connection to Server
                        StatusServer cli=new StatusServer(newSock,ServerInstance);EhouseTCP.CurrentORSensorConnection++;    //Pass client socket to new thread for non blocking multithreading Server and initialize server
                        cli.start();    //Start New thread for next connection
                        
                    }
                catch (Exception e)
                    {
                    l("Exception in server socket: "+e.getMessage());
                    break;
                    }
        
                }
            try
                {
                sleep(1000);
                }
            catch (Exception e) {}
            try {providerSocket.close();}
            catch (Exception e) {ehousecommunication.l("Error closing Server socket: "+e.getMessage());}
            
        }
    
 
};    
    
}
