package com.asreader.asr033w.asr033w;

import android.util.Log;
import com.asreader.asr033w.asr033w.asr033wenum.ASR033WConnectMethod;
import com.asreader.asr033w.asr033w.asr033wenum.ASR033WResultCode;
import com.asreader.asr033w.asr033w.errormodel.ASR033WErrorModel;
import com.asreader.asr033w.asr033w.info.ASR033WReaderInfo;
import com.asreader.asr033w.asr033w.network.ASR033WNetworkMQTT;
import com.asreader.asr033w.asr033w.network.ASR033WNetworkMQTTCallBack;
import com.asreader.asr033w.asr033w.network.ASR033WNetworkTCP;
import com.asreader.asr033w.asr033w.network.ASR033WNetworkTCPCallBack;
import com.asreader.asr033w.asr033w.network.ASR033WNetworkUDP;
import com.asreader.asr033w.asr033w.network.ASR033WNetworkUDPCallBack;
import com.asreader.asr033w.asr033w.asr033wenum.ASR033WNetworkState;
import com.asreader.asr033w.asr033w.protocol.ASR033WProtocol;
import java.util.HashMap;

public class ASR033W {
    private static ASR033W instance = null;
    private ASR033WNetworkUDP asr033wNetworkUDP = null;
    private ASR033WReaderInfo asr033wReaderInfo = null;
    private ASR033WProtocol asr033wProtocol = null;
    private ASR033WNetworkTCP asr033wNetworkTCP = null;
    private ASR033WNetworkMQTT asr033WNetworkMQTT = null;
    private ASR033WCallBack callBack = null;
    private boolean isConnect = false;
    private ASR033WConnectMethod currentConnectMethod = ASR033WConnectMethod.ASR033WConnectMethod_TCP;
    public static ASR033W sharedInstance() {
        if (instance == null) {
            instance = new ASR033W();
        }
        return instance;
    }
    private ASR033W(){
        asr033wNetworkUDP = new ASR033WNetworkUDP();
        asr033wNetworkUDP.setCallBack(new ASR033WNetworkUDPCallBack() {
            @Override
            public void onSearchingUDPReceiveInformation(HashMap<String, String> dictionary, boolean isFinish) {
                if (callBack != null){
                    callBack.searchingIP(ASR033W.this,dictionary,isFinish);
                }
            }

            @Override
            public void onReceivedUDPSearchError(ASR033WErrorModel errorModel) {

            }
        });
        asr033wReaderInfo = ASR033WReaderInfo.getInstance();
        asr033wNetworkTCP = new ASR033WNetworkTCP();
        asr033wNetworkTCP.setASR033WNetworkTCPCallBack(new ASR033WNetworkTCPCallBack() {
            @Override
            public void onTCPDisconnect() {
                isConnect = false;
                if (callBack != null){
                    callBack.changeNetworkState(ASR033W.this, ASR033WNetworkState.ASR033WNetworkStateDisconnected,null);
                }
            }

            @Override
            public void onTCPConnected() {
                isConnect = true;
                if (callBack != null){
                    callBack.changeNetworkState(ASR033W.this, ASR033WNetworkState.ASR033WNetworkStateConnected,null);
                }
            }

            @Override
            public void onTCPReceive(byte[] data) {
                asr033wProtocol.receiveData(data);
            }

            @Override
            public void onTCPErrorReceive(Exception e) {
                isConnect = false;
                if (callBack != null) {
                    callBack.changeNetworkState(ASR033W.this, ASR033WNetworkState.ASR033WNetworkStateError, new Error(e.getMessage()));
                }
            }
        });
        asr033WNetworkMQTT = new ASR033WNetworkMQTT();
        asr033WNetworkMQTT.setASR033WNetworkMQTTCallBack(new ASR033WNetworkMQTTCallBack() {
            @Override
            public void onMQTTDisconnect() {
                isConnect = false;
                if (callBack != null){
                    callBack.changeNetworkState(ASR033W.this, ASR033WNetworkState.ASR033WNetworkStateDisconnected,null);
                }
            }

            @Override
            public void onMQTTConnected() {
                isConnect = true;
                if (callBack != null){
                    callBack.changeNetworkState(ASR033W.this, ASR033WNetworkState.ASR033WNetworkStateConnected,null);
                }
            }

            @Override
            public void onMQTTReceive(byte[] data) {
                asr033wProtocol.receiveData(data);
            }

            @Override
            public void onMQTTErrorReceive(Exception e) {
                isConnect = false;
                if (callBack != null) {
                    callBack.changeNetworkState(ASR033W.this, ASR033WNetworkState.ASR033WNetworkStateError, new Error(e.getMessage()));
                }
            }
        });
        asr033wProtocol = new ASR033WProtocol(asr033wNetworkTCP, asr033WNetworkMQTT);
    }

    public void setCallBack(ASR033WCallBack callBack) {
        this.callBack = callBack;
        asr033wProtocol.setCallBack(callBack);
    }

    public boolean getCurrentConnect() {
        return isConnect;
    }

    public ASR033WConnectMethod getASR033WConnectMethod() {
        return currentConnectMethod;
    }

    public void setASR033WConnectMethod(ASR033WConnectMethod connectMethod) {
        currentConnectMethod = connectMethod;
        asr033wProtocol.setASR033WConnectMethod(connectMethod);
    }

    public void startSearchDevice(){
        if (ASR033WConnectMethod.ASR033WConnectMethod_TCP == currentConnectMethod) {
            asr033wNetworkTCP.disconnect();
        } else {
            asr033WNetworkMQTT.disconnect();
        }
        asr033wNetworkUDP.searchDevice();
    }

    public void stopSearchDevice(){
        asr033wNetworkUDP.stopSearch();
    }

    public void setSearchDeviceTimeout(int searchTimeout){
        if (searchTimeout < 10){
            searchTimeout = 10;
        }
        if (searchTimeout > 60){
            searchTimeout = 60;
        }
        asr033wReaderInfo.searchTimeout = searchTimeout;
    }

    public void connectServerWithIP(String IP ,int port){
        if (ASR033WConnectMethod.ASR033WConnectMethod_TCP == currentConnectMethod) {
            asr033wNetworkTCP.connect(IP,port);
        } else {
            asr033WNetworkMQTT.connect(IP,port);
        }
    }

    public void disconnectServer(){
        if (ASR033WConnectMethod.ASR033WConnectMethod_TCP == currentConnectMethod) {
            asr033wNetworkTCP.disconnect();
        } else {
            asr033WNetworkMQTT.disconnect();
        }
    }

    public void startReceiveRFIDData(){
        if (ASR033WConnectMethod.ASR033WConnectMethod_TCP == currentConnectMethod) {
            byte[] param = new byte[] {(byte) 0xC0,0x00,0x00,0x00,0x00,0x01};
            sendData(param);
        } else {
            asr033WNetworkMQTT.subscribe(asr033WNetworkMQTT.rfidTopic);
        }
    }

    public void stopReceiveRFIDData(){
        if (ASR033WConnectMethod.ASR033WConnectMethod_TCP == currentConnectMethod) {
            byte[] param = new byte[] {(byte) 0xC0,0x00,0x00,0x00,0x00,0x02};
            sendData(param);
        } else {
            asr033WNetworkMQTT.unsubscribe(asr033WNetworkMQTT.rfidTopic);
        }
    }

    public void startReceiveHIDData(){
        if (ASR033WConnectMethod.ASR033WConnectMethod_TCP == currentConnectMethod) {
            byte[] param = new byte[] {(byte) 0xC0,0x00,0x00,0x00,0x00,0x03 };
            sendData(param);
        } else {
            asr033WNetworkMQTT.subscribe(asr033WNetworkMQTT.hidTopic);
        }
    }

    public void stopReceiveHIDData(){
        if (ASR033WConnectMethod.ASR033WConnectMethod_TCP == currentConnectMethod) {
            byte[] param = new byte[] {(byte) 0xC0,0x00,0x00,0x00,0x00,0x04};
            sendData(param);
        } else {
            asr033WNetworkMQTT.unsubscribe(asr033WNetworkMQTT.hidTopic);
        }
    }

    public ASR033WResultCode regionName(){
        ASR033WResultCode resultCode = asr033wProtocol.getRegionName();
        return resultCode;
    }

    public ASR033WResultCode serialNumber(){
        ASR033WResultCode resultCode = asr033wProtocol.getSerialNumber();
        return resultCode;
    }

    public ASR033WResultCode hardwareVersion(){
        ASR033WResultCode resultCode = asr033wProtocol.getHardwareVersion();
        return resultCode;
    }

    public ASR033WResultCode rFModuleVersion(){
        ASR033WResultCode resultCode = asr033wProtocol.getRFModuleVersion();
        return resultCode;
    }

    public ASR033WResultCode firmwareVersion(){
        ASR033WResultCode resultCode = asr033wProtocol.getFirmwareVersion();
        return resultCode;
    }
    public ASR033WResultCode macAddress(){
        ASR033WResultCode resultCode = asr033wProtocol.getMacAddress();
        return resultCode;
    }
    public ASR033WResultCode startInventoryAntenna1(boolean antenna1,
                                         boolean antenna2,
                                         boolean antenna3,
                                         boolean antenna4,
                                         boolean antenna5,
                                         boolean antenna6,
                                         boolean antenna7,
                                         boolean antenna8,
                                         boolean tid) {
        Log.d("ASR033W","startInventoryAntenna1");
        byte[] param = new byte[] {(byte) 0x0b,0x01,0x00,0x00,0x00,0x00,0x00};
        if (tid) {
            param[0] = (byte)0xB0;
        } else {
            param[0] = (byte)0xC0;
        }
        param[1] = 0x01;
        int ant = ((antenna1?1:0) + (antenna2?1:0) * 2 + (antenna3?1:0) * 4 + (antenna4?1:0) * 8 + (antenna5?1:0) * 16 + (antenna6?1:0) * 32 + (antenna7?1:0) * 64 + (antenna8?1:0) * 128) & 0xFF;
        param[2] = (byte)ant;
        ASR033WResultCode resultCode = asr033wProtocol.startInventoryAntenna1(param);
        return resultCode;
    }

    public ASR033WResultCode stopInventory(){
        Log.d("ASR033W","stopInventory");
        ASR033WResultCode resultCode = asr033wProtocol.stopInventory();
        return resultCode;
    }

    public ASR033WResultCode sendData(byte[] data) {
        Log.d("ASR033W","sendData");
        ASR033WResultCode resultCode = asr033wProtocol.sendData(data);
        return resultCode;
    }

    public String getMessageWithResultCode(ASR033WResultCode resultCode){
        Log.d("ASR033W","getMessageWithResultCode");
        switch (resultCode) {
            case ASR033WResultNoError:
                return "No Error";
            case ASR033WResultOtherError:
                return "Other Error";
            case ASR033WResultUndefined:
                return "Undefined";
            case ASR033WResultMemoryOverrun:
                return "Memory Overrun";
            case ASR033WResultMemoryLocked:
                return "Memory Locked";
            case ASR033WResultInsufficientPower:
                return "Insufficient Power";
            case ASR033WResultNotConnected:
                return "Disconnected";
            case ASR033WResultInvalidParameter:
                return "Invalid parameter";
            case ASR033WResultTimeout:
                return "Timeout";
            case ASR033WResultCommandFormatError:
                return "Command format error";
            case ASR033WResultOutOfRetries:
                return "Out of retries";
            case ASR033WResultReadAntennaPortParameterError:
                return "Read antenna port parameter error";
            case ASR033WResultReadReadParameterError:
                return "Read read parameter error";
            case ASR033WResultReadTidReadingParameterError:
                return "Read tid reading parameter error";
            case ASR033WResultReadUserDataAreaParameterError:
                return "Read user data area parameter error";
            case ASR033WResultReadReservedAreaParameterError:
                return "Read reserved area parameter error";
            case ASR033WResultReadOtherParameterError:
                return "Read other parameter error";
            case ASR033WResultWriteAntennaPortParameterError:
                return "Write antenna port parameter error";
            case ASR033WResultWriteSelectionParameterError:
                return "Write selection parameter error";
            case ASR033WResultWriteWritingParameterError:
                return "Write writing parameter error";
            case ASR033WResultWriteCRCCheckError:
                return "Write CRC error on tag response";
            case ASR033WResultWriteInsufficientPower:
                return "Write insufficient power";
            case ASR033WResultWriteMemoryOverrun:
                return "Write memory overrun";
            case ASR033WResultWriteMemoryLocked:
                return "Write Memory locked";
            case ASR033WResultWriteIncorrectAccessPassword:
                return "Write incorrect access password";
            case ASR033WResultWriteOtherLabelError:
                return "Write other label error";
            case ASR033WResultWriteLabelLoss:
                return "Write label loss";
            case ASR033WResultWriteSendingInstructionError:
                return "Write sending instruction error";
            case ASR033WResultLockAntennaPortParameterError:
                return "Lock antenna port parameter error";
            case ASR033WResultLockSelectionParameterError:
                return "Lock selection parameter error";
            case ASR033WResultLockLockingParameterError:
                return "Lock locking parameter error";
            case ASR033WResultLockCRCCheckError:
                return "Lock CRC error on tag response";
            case ASR033WResultLockInsufficientPower:
                return "Lock insufficient power";
            case ASR033WResultLockMemoryOverrun:
                return "Lock memory overrun";
            case ASR033WResultLockMemoryLocked:
                return "Lock memory locked";
            case ASR033WResultLockIncorrectAccessPassword:
                return "Lock incorrect access password";
            case ASR033WResultLockOtherLabelError:
                return "Lock other label error";
            case ASR033WResultLockLabelLoss:
                return "Lock label loss";
            case ASR033WResultLockSendingInstructionError:
                return "Lock sending instruction error";
            case ASR033WResultKillAntennaPortParameterError:
                return "Kill antenna port parameter error";
            case ASR033WResultKillSelectionParameterError:
                return "Kill selection parameter error";
            case ASR033WResultKillCRCCheckError:
                return "Kill CRC error on tag response";
            case ASR033WResultKillInsufficientPower:
                return "Kill insufficient power";
            case ASR033WResultKillIncorrectAccessPassword:
                return "Kill incorrect access password";
            case ASR033WResultKillOtherLabelError:
                return "Kill other label error";
            case ASR033WResultKillLabelLoss:
                return "Kill label loss";
            case ASR033WResultKillSendingInstructionError:
                return "Kill sending instruction error";
            default:
                return "Unknown Error";
        }
    }
}
