package org.openremote.controller.protocol.ehouse;
/**
 * @author robert jarzabek 
 * http://www.isys.pl/
 * http://inteligentny-dom.ehouse.pro/
 * http://www.ehouse.pro/
 * http://sterowanie.biz/
 * 
*/

import java.io.InputStream;
import java.io.OutputStream;
import java.io.BufferedReader;
import java.net.InetAddress;
import java.net.*;
public class EhouseTCP
    {
//WifiManager wifi;
/**
 * initial prioryty of thread for TCP client connection
 */
static int TCPQueryPriority=Thread.MIN_PRIORITY;
/**
 * initial prioryty of thread for udp client connection
 */
static int UDPQueryPriority=Thread.MIN_PRIORITY;
/**
 * speech syntesiser thread priority
 */
static int StatusServerPriority=Thread.//NORM_PRIORITY;
                                MIN_PRIORITY;
static byte[] message=new byte[1500];
static int CurrentORSensorConnection=0;
//blocking unblocking some options
/**
 * udp flag
 */
static boolean UDPInit=true;
/**
 * tcp flag
 */
static boolean StatusServerEnable=false;
ServerSocket providerSocket;
static final int MAX_OR_SERVER_SOCKETS=1000;
//static Socket[] CliSocket=new Socket[MAX_OR_SERVER_SOCKETS];
/**
 * udp socket
 */
static DatagramSocket ds=null;
/**
 * UDP reception initiated
 */
public static boolean UDPStarted=false; 
/**
 * Enable UDP Reception
 */
public static boolean UDPEnabled=false;
/**
 * Udp port nr for reception
 */
public static int UDPPort=6789;          
public static boolean Dynamic = false;
/**
 * loads settings of devices from files (statusehouse, statuscommmanager)
 */
public static boolean EhouseTCPDevicesInitiated=false; 
public static boolean ViaCommManager=true;
//static public boolean Offline=true;
public static String sep=System.getProperty("file.separator");
static public InetAddress broadcastinet=null;
/**
 * tcp connection for query controller status is active
 */
    static boolean QueryConnected=false;
    static boolean chchch=false;
    /**
     * wifi submit success flag
     */
    static boolean WiFiSendOk=true;      
    /**
     * Client Connection
     */
    public static Socket ehouseconnection=null;  
    /**
     * output stream connection
     */
    public static OutputStream ehouseout=null;            
    /**
     * input stream connection
     */
    public static InputStream ehousein=null;              
    public static BufferedReader ehouseinput=null;
//    static Thread RunQuery=null;
    /**
     * additional size of query for ehouse over communication module
     * 0 for direct ehouse connection
     */
    public static int QueryOffset = 2;
    /**
     * changed ADC measurement flag
     */                                 
    public static boolean AdcChanged=false;
    /**
     * checking for init all graphic matrix temp, temps, other
     */
    static private boolean initiatedgraphicobjects=false;    
    static public int iiter=0;
    /**
     * enabled TCP query status
     */
    public static boolean TCPPanelEnabled = false; 
    /**
     * Wifi / internet  configuration - internet uses as well ddns service support
     */
    //public static Boolean EnabledWan = false;
    public static String statustemp = "";
    /**
     * first flag for application init
     */
    static public boolean OnlyTheFirst = false;
        static Byte[] EventList = new Byte[256];
        static int EventSize = 0;
        static Byte ClientOpts = 0;
        static int WiFiSendTimeOut = 0;        
        final static int WiFiSENDTIMEOUT=3;
        static byte[] QueryBuff = new byte[1024];
        final static int MAX_TOTDEVS_COUNT=30;
        static int DevNameIndex=0;
        static int Status = 0;
        public static int QueryStatus = 0;
        static boolean Changed = false;
        public static int ProgressIndicator = 0;
        public static int QueryProgressIndicator = 0;
        /**
         * Devices auto views
         */
        public static String[] DevViewNames=new String[MAX_TOTDEVS_COUNT];
//        private static int[] HashTable = new int[15];		//finally converted
        /**
         * terminate send for kill application, threads or cancel
         */
        public static boolean TerminateSend = false;
        /**
         * terminate infinite query reception over tcp ip
         */
        public static boolean QueryTerminateSend = false; 
        /**
         * tcp ip client current status
         */
        public final static int CLIENT_BSD_CONNECT = 3;
        public final static int CLIENT_BSD_RECEIVE_CHALANGE = 4;
        public final static int CLIENT_BSD_RECEIVE_PROMPT = 5;
        public final static int CLIENT_BSD_RECEIVE_PROMPT_AFTER_SIZE = 6;
        public final static int CLIENT_BSD_RECEIVE_COMPLETE_AFTER_DATA = 7;
        public static boolean EhouseDevicesInitiated = false; //
        //#define	    CLIENT_BSD_SEND 
        public final static int CLIENT_BSD_OPERATION = 8;
        public final static int CLIENT_BSD_CLOSE = 9;
        public final static int CLIENT_BSD_DONE = 10;
        public final static int CLIENT_BSD_REPORT = 11;
        public final static int CLIENT_BSD_REPORT_END = 12;
        public static int BSDClientState = 0;
        //static Socket EhTCP=null;
        //////////////////////////////////////////////////////////////////////////////////////////////////
        static int[] response = new int[100];
        final static int EVENT_SIZE = 10;
        /**
         * max nr of ehouse 1 devs (RMs, EM, HM)
         */
        final static int MAX_SIZE_OF_EHOUSE_DEVS=36;
        /**
         * max size of ehouse ethernet devs (commmanager, levelmanager, ethernetroommanager)
         */
        final static int MAX_SIZE_OF_EHOUSE_DEVS_TCP = 36;
//        final 
        /**
         * caching arrays for store ehouse 1 devs status, names, calculated results, visualization objects, etc
         */
        static StatusEhouse[] EhDev=new StatusEhouse[MAX_SIZE_OF_EHOUSE_DEVS];
        /**
         * caching arrays for store ethernet ehouse  devs status, names, calculated results, visualization objects
         */
        static StatusEthernet[] EhDevTCP = new StatusEthernet[MAX_SIZE_OF_EHOUSE_DEVS_TCP]; 
        
        /**
         * count of RM,EM,HM
         */
        static int RM_COUNT=0;
        /**
         * count of CM,ERM,LM
         */
        static int TCP_COUNT=0;
//////////////////////////////////////////////////////////////////////////////////////////////////
/** Add to local log
    Dodaje string do logu     */        
        public static void l(String s)
        { 
            
            String log="";
            log=s+"\r\n";
            ehousecommunication.log+=log;
        }
////////////////////////////////////////////////////////////////////////////////////////////////        
/////////////////////////////////////////////////////////////////////////////////////
/**
 * first time setup flag
 * 
 * @return 
 */       
        public boolean OnlyFirst()
        {
            if (OnlyTheFirst)
            {
                OnlyTheFirst = false;
                return true;
            }
            else return false;
        }
//////////////////////////////////////////////////////////////////////////////////////////////////////        
/**
 * Check if Adc measurement was changed from previous query
 * 
 * @return 
 */        
        
   public boolean IsAdcChanged()
    {
        if ((AdcChanged) && (OnlyTheFirst))
        {
            OnlyTheFirst = false;
            AdcChanged = false;
            return true;
        }
        return false;
    }
/////////////////////////////////////////////////////////////////////////////////////////////        
/**
 * Get Size of Eventque keep it less then 70
 * 
 * @return 
 */
        static public int GetEventsCount()
        {
            
            return EventSize;
        }
////////////////////////////////////////////////////////////////////////
/**
 * return string representation of adc value  
 * devindex - index of rm table
 * opts - type of measurement (percent, absolute, light level, temp, invert percent, and other for future use)        
 * nr - index of sensor for device
 * 
 * @param devindex
 * @param opts
 * @param nr
 * @return 
 */
        static public String Replacement(int devindex, int opts, int nr)
        {
            if (devindex >= MAX_SIZE_OF_EHOUSE_DEVS) return "";
            if (opts > 3) return "";
            if (nr >= 16) return "";
            switch (opts)
                {
                case 0:
                    return String.valueOf(EhDev[devindex].SensorABSValues[nr]); //absolute values 0..1023
                case 1:
                    return String.valueOf(EhDev[devindex].SensorTemps[nr]);     //calculate as temperature in degrees
                case 2:
                    return String.valueOf(EhDev[devindex].SensorLights[nr]);    //calculate as light level (inverted scale linear)
                case 3:
                    return String.valueOf(EhDev[devindex].SensorPercents[nr]);  //calculate as percent value comparing to power device supplly
                case 4:
                    //return String.valueOf(EhDev[devindex].SensorVolt[nr]);
                //case 5:
                    return String.valueOf(EhDev[devindex].SensorPercents[nr]);   //volty zmienic w razie potrzeby
                }
            return "";
        }
//////////////////////////////////////////////////////////////////////////////////////////////////
/**
 * wifi send timeout decrement of sending event via WiFi or internet
 * 
 * @return 
 */       
static public int DecWiFiTimeOut()
{
    if (WiFiSendTimeOut>0) WiFiSendTimeOut--;
    return WiFiSendTimeOut;
}
//////////////////////////////////////////////////////////////////////////////////////////////////
/**
 * Update Status Class for each hardware devices EhDev[i] for each device
 * 
 * @return 
 */
static public int QueryReceived()   //query status received event of ehouse 1 devs
        {
        int i;
        boolean qchanged=false;
        for (i = 0; i < RM_COUNT; i++)  //ehouse 1 devices
            {
                if (EhDev[i].isAddress(QueryBuff[0], QueryBuff[1]))// compare by addr h and addr l
                {
                    if (i == 0) OnlyTheFirst = true;                //first device in EhDev matrix
                    if (EhDev[i].WriteCheckIfChangedAndCpy(QueryBuff,false) ) //update data to EhDev[i] matrix
                        {   //data was changed from previous reception
                            qchanged=true;
                            Changed = true;
                        }
                break;
                }
            }
        boolean cmmana=false;
        if (QueryBuff[0]>0) cmmana=true;  //roommanagers via commmanager
        if ((QueryBuff[0]==0) && (QueryBuff[1]==0)) cmmana=true;
        if ((QueryBuff[1]==-1)) cmmana=true;
        if (ViaCommManager)   //Connection via commanager
        for (i = 0; i < TCP_COUNT; i++)    //ethernet devices
            {
            
            if ((cmmana))    
                {
              if (EhDevTCP[i].IsCommManager)        //if commmanager
                    {
                    if (EhDevTCP[i].WriteCheckIfChangedAndCpy(QueryBuff,false,ViaCommManager) ) //decode commanager status
                        {   //data was changed from previous reception
                            qchanged=true;
                            Changed = true;
                        }
                break;
                }
            }
            else
              {
                if (EhDevTCP[i].isAddress(QueryBuff[0],QueryBuff[1]))  
                    if (EhDevTCP[i].WriteCheckIfChangedAndCpy(QueryBuff,false,true) ) //decode commanager status
                        {   //data was changed from previous reception
                            qchanged=true;
                            Changed = true;
                            break;
                        }    
              }        
            }
        
        return -1;
        }
//////////////////////////////////////////////////////////////////////////////////////////////////
/**
 * check if something was changed flag
 * 
 * @return 
 */
public boolean IsChanged()
    {
        return Changed;
    }
//////////////////////////////////////////////////////////////////////////////////////////////////
/**
 * Clear Changed Flag
 */
public void ClrChanged()
        {
            Changed = false;
        }
///////////////////////////////////////////////////////////////////////////////
/**
 * get index of ehouse 1 device searched by name
 * 
 * @param str
 * @return 
 */
public static int GetEhouseIndex(String str)
{
if (str==null) return -1;    
for (int i=0;i<RM_COUNT;i++)
    {
    if (EhDev[i].DeviceName.compareTo(str)==0) return i;
    }
return -1;
}
///////////////////////////////////////////////////////////////////////////////
/**
 * get index of ethernet ehouse device name 
 * 
 * @param str
 * @return 
 */
public static int GetEhouseTCPIndex(String str)
{
if (str==null) return -1;    
for (int i=0;i<TCP_COUNT;i++)
    {
    if (EhDevTCP[i].DeviceName.compareTo(str)==0) return i;
    }
return -1;
}
////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////
/**
 * get names, signals, eventnames for inicialization of appliaction
 */
public static void AllDevsStatus()
         {
if (EhouseDevicesInitiated) return; //if already initiated at the start of aplication then ignore
    String path=ehousecommunication.path;
             int i=0;
             String temp;
        if (ehousecommunication.FileExists(path+"mobile/devices.txt")) //device names
             //try
             {
             String devs[]=ehousecommunication.getfile(path+"mobile/devices.txt"); //load


int m=0;
             for (i = 0; i < 200; i++)
             {
                 if (devs[i]!= null)
                 {
                     temp = devs[i];
                     boolean ignore=false;
                     //dummy events for programs, events, security zones, security programs, analog programs, user events, output events, rollers events
                     if  
                     ((temp.indexOf(" - P") > 0) ||
                             (temp.indexOf(" - E") > 0) ||
                             (temp.indexOf(" - U") > 0) ||
                             (temp.indexOf(" - A") > 0) ||
                             (temp.indexOf(" - O") > 0) ||
                             (temp.indexOf(" - R") > 0) ||
                            (temp.indexOf(" - S") > 0)  ||
                            (temp.indexOf(" - Z") > 0)) {ignore=true;continue;}
                         
                      if (temp.equalsIgnoreCase("Batch")) {ignore=true;continue;}
                        if (temp.equalsIgnoreCase("Secu")) {ignore=true;continue;}                                    
                         
                     
                      if (temp!=null)
                        if ((temp.length() > 0) && (!ignore)) //if not empty and not to ignore
                     {
                         temp = path + "devs"+sep + temp + ".dev"; //devs config file
                         EhDev[m]=new StatusEhouse(); // initialize status of ehouse 1 dev matrix
                         EhDev[m].LoadDta(temp);//, enc); //load configuration data
                         if (DevNameIndex<MAX_TOTDEVS_COUNT)
                            DevViewNames[DevNameIndex]=EhDev[m].DeviceName; //load device name for automatic visualization names
                        DevNameIndex++;                       
                         if (DevNameIndex<MAX_TOTDEVS_COUNT) //set next device name to null for any case
                            DevViewNames[DevNameIndex]=null;
                        
//                         EhDev[m].clearvisualisationitems();
                         EhDev[m].SetStatusIndex(i); //
                         if (EhDev[m].IsEM==true)
                            {
                                EhDev[m].ReadAlarmSensorsNames(path+"AlarmSensors.txt"); //load alarm sensor names for external manager
                            }
                         if (EhDev[m].IsHM) 
                             EhDev[m].ReadHMSensorsNames(); //load temperature sensor names for HM
                         RM_COUNT++;
                         m++;
                         if (m==MAX_SIZE_OF_EHOUSE_DEVS) break; //if too much ehouse 1 devs then drop the rest
                     }
                     //else break;
                 }
                 else
                     break;
                 //else break;
             }
             EhouseDevicesInitiated = true; //set configuration initialized flag
             }
             

        }

/// /////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
 * read and initialize array ethernet device names, sensors, configurations
 */
public static void AllDevsTCPStatus()//String path, String TCPLocalServer, String TCPLocalPort,String TCPRemoteServer,String TCPRemotePort)
{   int i=0;
    String temp;
    String path=ehousecommunication.path;
    if (EhouseTCPDevicesInitiated) return; //if already initiated at aplication start then ignore
    if (ehousecommunication.FileExists(path + "mobile"+sep+"tcpdevices.cfg")) //load list of ethernet devices
        {
            String tcpdevs[]=ehousecommunication.getfile(path + "mobile"+sep+"tcpdevices.cfg");//, enc);
            int m=0;
            for (i = 0; i < 100; i++)
            {
                if (tcpdevs[i] != null)
                {
                    temp = tcpdevs[i];
                    if (temp.length() > 0) //if ethernet dev name is not null and not empty
                    {
                        temp = path + "mobile"+sep+"tcpdevs"+sep + temp + ".dev"; //configuration path
                        EhDevTCP[m] = new StatusEthernet();//, enc);                      //initialize ethernet device  matrix
                         EhDevTCP[m].LoadDta(temp);//, enc); //load configuration data for current ethernet device
                         if (DevNameIndex<MAX_TOTDEVS_COUNT)
                            DevViewNames[DevNameIndex]=EhDevTCP[m].DeviceName; //set devname for automatic visualization
                        DevNameIndex++;
                        if (DevNameIndex<MAX_TOTDEVS_COUNT) //set next to null for any case
                            DevViewNames[DevNameIndex]=null;
                        EhDevTCP[m].SetStatusIndex(i);
                        if (EhDevTCP[m].IsCommManager) //load alarm sensor names for commmanager
                        {
                            EhDevTCP[m].ReadAlarmSensorsNames(path + "mobile"+sep + EhDevTCP[i].DevAdr +sep+ "names"+sep+"SensorNames.txt");
                        }
                        TCP_COUNT++;
                        EhDevTCP[m].MakeXml();
                        m++;
                        if (m==MAX_SIZE_OF_EHOUSE_DEVS_TCP) break;
                    }
                    else break;
                }
                else
                    break;

            }
            EhouseTCPDevicesInitiated = true; //set flag that ethernet devices were initialized

        }
  
}
final static int EventLengtMax = 250;
//////////////////////////////////////////////////////////////////////////////////////////////////
public static int GetProgress()
        {
            return ProgressIndicator;
        }
//////////////////////////////////////////////////////////////////////////////////////////////////
        public static void ClrEvents()
        {
            EventSize = 0;
        }
        //////////////////////////////////////////////////////////////////////////////////////////////////
        public static void SetMode(Byte mode)
        {
            ClientOpts = mode;
        }
        //////////////////////////////////////////////////////////////////////////////////////////////////
/**
 * append binary event to send queue
 * 
 * @param events
 * @return 
 */
        public static int AppendEvent(Byte[] events)
        {
            int i;
            if (EventSize + EVENT_SIZE < EventLengtMax)
            {
                for (i = 0; i < EVENT_SIZE; i++)
                {

                    EventList[EventSize] = events[i];
                    EventSize++;
                }
                return EventSize;
            }
            else
            {
                return 0;

            }
        }
        //////////////////////////////////////////////////////////////////////////////////////////////////
        ///////////////////////////////////////////////////////////////////
        static void PerformQuery()
        {

            //  (QueryBuff);
        }
        /// ////////////////////////////////////////////////////////////////
        //check if terminate tcp communication was initiated
        public static boolean isTerminated()
        {
            if (TerminateSend)
                return true;
            else
                return false;
        }
///////////////////////////////////////////////////////////////////
/**
 * initiate termination of tcp communication
 */
        public static void Terminate()
        {
            TerminateSend = true;

        
       }
//////////////////////////////////////////////////////////////////////////////////        
/**
 * terminate query reception from controllers over tcpip   
 */     
        public static void TerminateQuery()
        {
            TCPPanelEnabled = false;
            QueryTerminateSend = true;
            
        }
    static int QueryRunnerStatus=0;
/**
 * check integer value
 * 
 * @param stt
 * @param defaut
 * @return 
 */
    static private int check_in(String stt, int defaut)
    {
        double dd = Double.valueOf(stt);
        int ino = (int)dd;
        //ino=st.IConvertible.ToInt32();
        return (ino);
    }

////////////////////////////////////////////////////////////////////////////////        
        
     
    }
//}