package kr.co.icontrols.ilp300_700.ethernet;

import android.content.Context;
import android.os.StrictMode;
import android.util.Log;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.Enumeration;

import kr.co.icontrols.ilp300_700.MainActivity;
import kr.co.icontrols.ilp300_700.global.Configure.ConfigValKey;
import kr.co.icontrols.ilp300_700.global.Configure.ConfigValue;
import kr.co.icontrols.ilp300_700.global.Configure.SetValue;
import kr.co.icontrols.ilp300_700.global.Declare;
import kr.co.icontrols.ilp300_700.global.Declare.DeviceType;

public class EthernetCtrl {

    static String TAG = "EthernetCtrl";

    static boolean bLOG = true;   // true, false
    static boolean bLOG_DEBUG = false;   // true, false
    static boolean bLOG_INFO = true;   // true, false

    private static void LOG(String log) {
        if (bLOG) Log.v(TAG, log);
    }

    private static void LOG_DEBUG(String log) {
        if (bLOG_DEBUG) Log.d(TAG, log);
    }

    private static void LOG_INFO(String log) {
        if (bLOG_INFO) Log.i(TAG, log);
    }

    public static String makeIPAddress(DeviceType eDeviceType, String strDong, String strHo) {
        try {
            LOG("[makeIPAddress] eDeviceType [" + eDeviceType + "], strDong [" + strDong + "], strHo [" + strHo + "]");
            String strResult = null;
            String IP_01 = "10";
            String IP_02 = Integer.toString(Integer.parseInt(strDong) % 100);
            String IP_03 = "1";
            String IP_04 = "1";

            if (ConfigValue.eIPExpansion == SetValue.TRUE) {
                if (IP_02.equals("0")) IP_01 = "10";   // 장비동(0동)인 경우에는 IP의 A클래스를 "10"으로 고정한다.
                else IP_01 = Integer.toString(Integer.parseInt(strDong) / 100);
            }

            if (eDeviceType == DeviceType.RESIDENCE) {
                IP_03 = Integer.toString(Integer.parseInt(strHo) / 100);
                IP_04 = Integer.toString(Integer.parseInt(strHo) % 100);
            } else if (eDeviceType == DeviceType.RENTRESIDENCE) {
                IP_03 = Integer.toString(Integer.parseInt(strHo) / 100);
                IP_04 = Integer.toString((Integer.parseInt(strHo) % 100) + 200);
            } else if (eDeviceType == DeviceType.LOBBY) {
                IP_03 = "0";
                IP_04 = Integer.toString(Integer.parseInt(strHo) % 100);
            } else if (eDeviceType == DeviceType.GUARD) {
                IP_03 = "128";
                IP_04 = Integer.toString(Integer.parseInt(strHo) % 100);
            }

            if (!checkIPValidity(IP_01)) return null;
            if (!checkIPValidity(IP_02)) return null;
            if (!checkIPValidity(IP_03)) return null;
            if (!checkIPValidity(IP_04)) return null;
            strResult = IP_01 + "." + IP_02 + "." + IP_03 + "." + IP_04;

            return strResult;
        } catch (Exception e) {
            Log.e(TAG, "[Exception] makeIPAddress(DeviceType eDeviceType, String strDong, String strHo)");
            e.printStackTrace();
            return null;
        }
    }

    public static String makeIPAddress(String a, String b, String c, String d) {
        try {
            LOG("[makeIPAddress] a [" + a + "], b [" + b + "], c [" + c + "], d [" + d + "]");
            String strResult = null;
            if (!checkIPValidity(a)) return null;
            if (!checkIPValidity(b)) return null;
            if (!checkIPValidity(c)) return null;
            if (!checkIPValidity(d)) return null;
            strResult = a + "." + b + "." + c + "." + d;
            LOG("[makeIPAddress] strResult [" + strResult + "]");
            return strResult;
        } catch (Exception e) {
            Log.e(TAG, "[Exception] makeIPAddress(a, b, c, d)");
            e.printStackTrace();
            return null;
        }
    }

    public static String makeIPAddress(String[] aip) {
        try {
            LOG("[makeIPAddress] aip.length [" + aip.length + "]");
            String strResult = null;
            for (int i = 0; i < aip.length; i++) {
                LOG("[makeIPAddress] classes [" + i + "] = " + aip[i]);
                if (!checkIPValidity(aip[i])) return null;
            }
            strResult = aip[0] + "." + aip[1] + "." + aip[2] + "." + aip[3];
            LOG("[makeIPAddress] strResult [" + strResult + "]");
            return strResult;
        } catch (Exception e) {
            Log.e(TAG, "[Exception] makeIPAddress(aip)");
            e.printStackTrace();
            return null;
        }
    }

    private static boolean checkIPValidity(String ip) {
        try {
            LOG("[checkIPValidity] ip [" + ip + "]");
            int nIP = Integer.parseInt(ip);
            if ((0 <= nIP) && (nIP <= 255)) return true;
            else return false;
        } catch (Exception e) {
            Log.e(TAG, "[Exception] makeIPAddress(a, b, c, d)");
            e.printStackTrace();
            return false;
        }
    }

    public static String makeMACAddress(String strIPAddress) {
        try {
            LOG("[makeMACAddress] START!");
            LOG("[makeMACAddress] strIPAddress [" + strIPAddress + "]");

            String strResult = "";
            String[] parse = strIPAddress.split("\\.");
            if (parse.length != 4) return null;
//            for (int i = 0; i < parse.length; i++) {
//                Log.d(TAG, "[makeMACAddress] parse[" + i + "] = " + parse[i]);
//            }

            strResult = String.format("00:%02X:%02X:%02X:%02X:00", Integer.parseInt(parse[0]), Integer.parseInt(parse[1]), Integer.parseInt(parse[2]), Integer.parseInt(parse[3]));
            LOG("[getDeviceIPAddress] DONE! [MAC Address : " + strResult + "]");

            return strResult;
        } catch (Exception e) {
            Log.e(TAG, "[Exception] makeMACAddress() " + e);
            e.printStackTrace();
        }
        return null;
    }

    public static boolean setDeviceIPAddressByBasicInfo(Context context, String strSitecode, String strDong, String strID) {
        try {
            LOG("[setDeviceIPAddressByBasicInfo] strSitecode [" + strSitecode + "], strDong [" + strDong + "], strID [" + strID + "]");

            if (strDong.length() < 3 || 4 < strDong.length()) return false;
            if (strID.length() != 2) return false;

            int ndong = Integer.parseInt(strDong);
            int nid = Integer.parseInt(strID);
            int ndong_head = ndong / 100;
            int ndong_tail = ndong % 100;
            int nid_head = nid / 100;
            int nid_tail = nid % 100;

            if (Declare.DeviceInfo.Type == DeviceType.LOBBY) {
                nid_head = 0;
            } else if (Declare.DeviceInfo.Type == DeviceType.GUARD) {
                nid_head = 128;
            }

            ConfigValue.strSitecode = strSitecode;
            ConfigValue.strDevice_Dong = strDong;
            ConfigValue.strDevice_ID = strID;
            if (ConfigValue.eIPExpansion == SetValue.TRUE) {
                if (ndong_tail == 0) ndong_head = 10;   // 장비동(0동)인 경우에는 IP의 A클래스를 "10"으로 고정한다.
                ConfigValue.strDeviceIPAddress = ndong_head + "." + ndong_tail + "." + nid_head + "." + nid_tail;
                ConfigValue.strGatewayIPAddress = ndong_head + "." + ndong_tail + ".0.254";
            } else {
                ConfigValue.strDeviceIPAddress = "10." + ndong_tail + "." + nid_head + "." + nid_tail;
                ConfigValue.strGatewayIPAddress = "10." + ndong_tail + ".0.254";
            }
            ConfigValue.strSubnetmask = "255.255.0.0";

            if (!MainActivity.ConfigDBManager.setData(Declare.DBInfo.TABLE_NAME_CONFIG, ConfigValKey.Sitecode, ConfigValue.strSitecode))
                return false;
            if (!MainActivity.ConfigDBManager.setData(Declare.DBInfo.TABLE_NAME_CONFIG, ConfigValKey.Device_Dong, ConfigValue.strDevice_Dong))
                return false;
            if (!MainActivity.ConfigDBManager.setData(Declare.DBInfo.TABLE_NAME_CONFIG, ConfigValKey.Device_ID, ConfigValue.strDevice_ID))
                return false;

            if (!MainActivity.ConfigDBManager.setData(Declare.DBInfo.TABLE_NAME_CONFIG, ConfigValKey.DeviceIPAddress, ConfigValue.strDeviceIPAddress))
                return false;
            if (!MainActivity.ConfigDBManager.setData(Declare.DBInfo.TABLE_NAME_CONFIG, ConfigValKey.Subnetmask, ConfigValue.strSubnetmask))
                return false;
            if (!MainActivity.ConfigDBManager.setData(Declare.DBInfo.TABLE_NAME_CONFIG, ConfigValKey.GatewayIPAddress, ConfigValue.strGatewayIPAddress))
                return false;

            return setDeviceNetInterface(context, ConfigValue.strDeviceIPAddress, ConfigValue.strSubnetmask, ConfigValue.strGatewayIPAddress,
                    ConfigValue.strDNSIPAddress, makeMACAddress(ConfigValue.strDeviceIPAddress));
        } catch (Exception e) {
            Log.e(TAG, "[Exception] setDeviceIPAddressByBasicInfo(Context context, String strSitecode, String strDong, String strID)");
            e.printStackTrace();
            return false;
        }
    }

    public static boolean setDeviceIPAddressByBasicInfo(Context context, String strSitecode, String strDong, String strID, boolean bSubnetAClass) {
        try {
            LOG("[setDeviceIPAddressByBasicInfo] strSitecode [" + strSitecode + "], strDong [" + strDong + "], strID [" + strID + "], bSubnetAClass [" + bSubnetAClass + "]");

            if (strDong.length() < 3 || 4 < strDong.length()) return false;
            if (strID.length() != 2) return false;

            int ndong = Integer.parseInt(strDong);
            int nid = Integer.parseInt(strID);
            int ndong_head = ndong / 100;
            int ndong_tail = ndong % 100;
            int nid_head = nid / 100;
            int nid_tail = nid % 100;

            if (Declare.DeviceInfo.Type == DeviceType.LOBBY) {
                nid_head = 0;
            } else if (Declare.DeviceInfo.Type == DeviceType.GUARD) {
                nid_head = 128;
            }

            ConfigValue.strSitecode = strSitecode;
            ConfigValue.strDevice_Dong = strDong;
            ConfigValue.strDevice_ID = strID;
            if (ConfigValue.eIPExpansion == SetValue.TRUE) {
                if (ndong_tail == 0) ndong_head = 10;   // 장비동(0동)인 경우에는 IP의 A클래스를 "10"으로 고정한다.
                ConfigValue.strDeviceIPAddress = ndong_head + "." + ndong_tail + "." + nid_head + "." + nid_tail;
                ConfigValue.strGatewayIPAddress = ndong_head + "." + ndong_tail + ".0.254";
            } else {
                ConfigValue.strDeviceIPAddress = "10." + ndong_tail + "." + nid_head + "." + nid_tail;
                ConfigValue.strGatewayIPAddress = "10." + ndong_tail + ".0.254";
            }

            if (bSubnetAClass) ConfigValue.strSubnetmask = "255.0.0.0";
            else ConfigValue.strSubnetmask = "255.255.0.0";

            if (!MainActivity.ConfigDBManager.setData(Declare.DBInfo.TABLE_NAME_CONFIG, ConfigValKey.Sitecode, ConfigValue.strSitecode))
                return false;
            if (!MainActivity.ConfigDBManager.setData(Declare.DBInfo.TABLE_NAME_CONFIG, ConfigValKey.Device_Dong, ConfigValue.strDevice_Dong))
                return false;
            if (!MainActivity.ConfigDBManager.setData(Declare.DBInfo.TABLE_NAME_CONFIG, ConfigValKey.Device_ID, ConfigValue.strDevice_ID))
                return false;

            if (!MainActivity.ConfigDBManager.setData(Declare.DBInfo.TABLE_NAME_CONFIG, ConfigValKey.DeviceIPAddress, ConfigValue.strDeviceIPAddress))
                return false;
            if (!MainActivity.ConfigDBManager.setData(Declare.DBInfo.TABLE_NAME_CONFIG, ConfigValKey.Subnetmask, ConfigValue.strSubnetmask))
                return false;
            if (!MainActivity.ConfigDBManager.setData(Declare.DBInfo.TABLE_NAME_CONFIG, ConfigValKey.GatewayIPAddress, ConfigValue.strGatewayIPAddress))
                return false;

            return setDeviceNetInterface(context, ConfigValue.strDeviceIPAddress, ConfigValue.strSubnetmask, ConfigValue.strGatewayIPAddress,
                    ConfigValue.strDNSIPAddress, makeMACAddress(ConfigValue.strDeviceIPAddress));
        } catch (Exception e) {
            Log.e(TAG, "[Exception] setDeviceIPAddressByBasicInfo(Context context, String strSitecode, String strDong, String strID, boolean bSubnetAClass)");
            e.printStackTrace();
            return false;
        }
    }

    public static boolean setDeviceNetInterface(Context mContext, String strIPAddr, String strSubnetmask, String strGateway, String strDNSAddr, String strMACAddr) {
        try {
            LOG("[setDeviceNetInterface] strIPAddr [" + strIPAddr + "], strSubnetmask [" + strSubnetmask + "], strGateway [" + strGateway + "], strDNSAddr [" + strDNSAddr + "], strMACAddr [" + strMACAddr + "]");
            MainActivity.mIOInterface.setNetworkInterface(strIPAddr, strSubnetmask, strGateway, strDNSAddr, strMACAddr);

            if(ConfigValue.eSubServerType == SetValue.ServerMixed_Integrated)
                MainActivity.mIOInterface.setDns(Declare.Const.DNS_IP1, Declare.Const.DNS_IP2);
            else
                MainActivity.mIOInterface.setDns(Declare.Const.DNS_IP, Declare.Const.DNS_IP2);

            //MainActivity.mIOInterface.setDns(Declare.Const.DNS_IP, Declare.Const.DNS_IP2);
            LOG("[setDeviceNetInterface] DONE!!");
            return true;
        } catch (Exception e) {
            Log.e(TAG, "[Exception] setDeviceNetInterface() " + e);
            e.printStackTrace();
            return false;
        }
    }

    public static String getDeviceIPAddress() {
        try {
            LOG("[getDeviceIPAddress] START!");

            String strResult = "";
            Enumeration<NetworkInterface> eni = NetworkInterface.getNetworkInterfaces();
            String netinfo = NetworkInterface.getByName("eth0").toString();
            Log.i(TAG, "[getDeviceIPAddress] ===== netinfo : " + netinfo + " =====");
            netinfo.trim();

            String[] parse_01 = netinfo.split("\\[");
//            for (int i = 0; i < Parse_01.length; i++) {
//                DEBUG("===== Parse_01[" + i + "] : " + Parse_01[i]);
//            }

            String[] parse_02 = parse_01[4].split("\\/");
//            for (int i = 0; i < Parse_02.length; i++) {
//                DEBUG("===== Parse_02[" + i + "] : " + Parse_02[i]);
//            }

            String[] parse_03 = parse_02[1].split("\\]");
//            for (int i = 0; i < Parse_03.length; i++) {
//                DEBUG("===== Parse_03[" + i + "] : " + Parse_03[i]);
//            }

            strResult = parse_03[0];

            LOG("[getDeviceIPAddress] DONE! [IP Address : " + strResult + "]");
            return strResult;
        } catch (Exception e) {
            Log.e(TAG, "[Exception] getDeviceIPAddress() " + e);
            e.printStackTrace();
        }
        return null;
    }

    public static String getDeviceMACAddress() {
        try {
            LOG("[getDeviceMACAddress] START!");

            String strResult = "";
            byte[] hNativeMACAddr = null;
//            hNativeMACAddr = MainActivity.mIOInterface.ilp300_700_getMacAddr();

            strResult = String.format("%02X:%02X:%02X:%02X:%02X:%02X", Integer.parseInt(String.valueOf(hNativeMACAddr[0])), Integer.parseInt(String.valueOf(hNativeMACAddr[1])),
                    Integer.parseInt(String.valueOf(hNativeMACAddr[2])), Integer.parseInt(String.valueOf(hNativeMACAddr[3])),
                    Integer.parseInt(String.valueOf(hNativeMACAddr[4])), Integer.parseInt(String.valueOf(hNativeMACAddr[5])));
            LOG("[getDeviceMACAddress] DONE! [MAC Address : " + strResult + "]");

//            for (int i = 0; i < hNativeMACAddr.length; i++) {
//                Log.d(TAG, "[getDeviceMACAddress] hNativeMACAddr[" + i + "] = " + hNativeMACAddr[i]);
//            }

            return strResult;
        } catch (Exception e) {
            Log.e(TAG, "[Exception] getDeviceMACAddress()");
            e.printStackTrace();
            return null;
        }
    }

    public static boolean checkPing(String dstip) {
        try {
            LOG("[checkPing] dstip = " + dstip);
            InetAddress TargetIP = InetAddress.getByName(dstip);
            StrictMode.enableDefaults();
            if (TargetIP.isReachable(3000)) {
                LOG("[checkPing] OK!!");
                return true;
            } else {
                LOG("[checkPing] FAIL!!");
                return false;
            }
        } catch (UnknownHostException e) {
            Log.e(TAG, "[UnknownHostException] checkPing(dstip) : " + e);
            e.printStackTrace();
            return false;
        } catch (IOException e) {
            Log.e(TAG, "[IOException] checkPing(dstip) : " + e);
            e.printStackTrace();
            return false;
        } catch (IllegalArgumentException e) {
            Log.e(TAG, "[IllegalArgumentException] checkPing(dstip) : " + e);
            e.printStackTrace();
            return false;
        } catch (Exception e) {
            Log.e(TAG, "[Exception] checkPing(dstip) : " + e);
            e.printStackTrace();
            return false;
        }
    }

    static boolean checkConnection(String DstIP) {
        try {
            LOG("[checkConnection] DstIP = " + DstIP);
            InetAddress TargetAddr = InetAddress.getByName(DstIP);
            if (TargetAddr.isReachable(30000)) {
                LOG("[checkConnection] OK!!");
                return true;
            } else {
                LOG("[checkConnection] FAIL!!");
                return false;
            }
        } catch (Exception e) {
            Log.e(TAG, "[Exception] checkConnection(DstIP) : " + e);
            e.printStackTrace();
            return false;
        }
    }

    // 소켓에서 IP주소를 추출하는 함수
    public static String getRemoteIPAddress(Socket Sock) {
        try {
//            Log.i(TAG, "[getRemoteIPAddress] == START ==");
            if (Sock == null) return "10.0.1.1";

            String strRemoteIP = Sock.getRemoteSocketAddress().toString();
            String[] strSplited_01 = strRemoteIP.split(":");
            String[] strSplited_02 = strSplited_01[0].split("/");
            strRemoteIP = strSplited_02[1];
            return strRemoteIP;
        } catch (Exception e) {
            Log.e(TAG, "[Exception] getRemoteIPAddress(Sock)");
            e.printStackTrace();
            return "10.0.1.1";
        }
    }

    public class TCPClient implements Runnable {
        private static final String TargetIP = "10.0.1.10";
        private static final int TargetPort = 10000;
        private Socket iNetSocket = null;
        private String MSG;

        private String return_msg;

        public TCPClient(String _msg) {
            this.MSG = _msg;
        }

        @Override
        public void run() {
            try {
                LOG_INFO("[Run] Connecting...");

                iNetSocket = new Socket(TargetIP, TargetPort);
//                iNetSocket.connect(remoteAddr);

                try {
                    LOG_INFO("[Sending] Sending : '" + MSG + "'");
                    PrintWriter Out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(iNetSocket.getOutputStream(), "euc-kr")), true);
                    Out.println(MSG);
                    LOG_INFO("[Sending] Sent : '" + MSG + "'");
                    BufferedReader In = new BufferedReader(new InputStreamReader(iNetSocket.getInputStream()));
                    return_msg = In.readLine();
                    LOG_INFO("[Sending] Received : '" + return_msg + "'");

                } catch (Exception e) {
                    Log.e(TAG, "[Exception] Run() " + e);
                    e.printStackTrace();
                } finally {
                    iNetSocket.close();
                }
            } catch (Exception e) {
                Log.e(TAG, "[Exception] Run() " + e);
                e.printStackTrace();
            }
        }
    }


}