package acquire.sdk;

import android.annotation.SuppressLint;
import android.app.Application;
import android.os.RemoteException;

import com.morefun.yapi.card.at24cxx.IAT24CxxCard;
import com.morefun.yapi.card.cpu.CPUTypeAHandler;
import com.morefun.yapi.card.cpu.ICpuCard;
import com.morefun.yapi.card.cpu.ICpuRFCard;
import com.morefun.yapi.card.emulate.EmulateCardHandler;
import com.morefun.yapi.card.felica.IFelica;
import com.morefun.yapi.card.m1card.IM1Card;
import com.morefun.yapi.card.mfulc.IMFULCCard;
import com.morefun.yapi.card.mfulev1.IMFULEv1Card;
import com.morefun.yapi.card.ntag215.INTAG215Card;
import com.morefun.yapi.card.psam.IPSAM;
import com.morefun.yapi.card.sle4442.ISLE4442Card;
import com.morefun.yapi.device.beeper.Beeper;
import com.morefun.yapi.device.dukpt.IDukpt;
import com.morefun.yapi.device.hsm.Hsm;
import com.morefun.yapi.device.led.LEDDriver;
import com.morefun.yapi.device.logrecorder.LogRecorder;
import com.morefun.yapi.device.ped.IPed;
import com.morefun.yapi.device.pinpad.PinPad;
import com.morefun.yapi.device.pinpad.SecureArea;
import com.morefun.yapi.device.printer.MultipleAppPrinter;
import com.morefun.yapi.device.printer.Printer;
import com.morefun.yapi.device.reader.icc.IccCardReader;
import com.morefun.yapi.device.reader.mag.MagCardReader;
import com.morefun.yapi.device.scanner.InnerScanner;
import com.morefun.yapi.device.serialport.SerialPort;
import com.morefun.yapi.device.serialport.SerialPortDriver;
import com.morefun.yapi.device.tpm.TpmManager;
import com.morefun.yapi.emv.EmvHandler;
import com.morefun.yapi.emv.EmvRupayService;
import com.morefun.yapi.engine.DeviceServiceEngine;

//import com.morefun.ysdk.sample.MyApplication;

//import com.morefun.ysdk.sample.utils.ToastUtils;
public class DeviceHelper {

    /** Callback fired once the device service is bound and ready. */
    public interface OnDeviceReadyListener {
        void onDeviceReady();
    }

    private static final java.util.List<OnDeviceReadyListener> sDeviceReadyListeners =
            new java.util.concurrent.CopyOnWriteArrayList<>();

    /**
     * Register a listener to be called when the device service is ready.
     * If the service is already initialised the listener is invoked immediately
     * on the calling thread.
     */
    public static void addOnDeviceReadyListener(OnDeviceReadyListener listener) {
        if (deviceServiceProvider != null) {
            listener.onDeviceReady();
        } else {
            sDeviceReadyListeners.add(listener);
        }
    }

    private static DeviceServiceProvider deviceServiceProvider;

    private final static String TAG = DeviceHelper.class.getName();

    private static PinPad pinpad;
    private static IccCardReader iccCardReader;

    private static SecureArea mSecureArea;
    private static Hsm mHsm;
    private static MagCardReader magCardReader;
    private static LEDDriver ledDriver;
    private static MultipleAppPrinter multipleAppPrinter;
    private static Printer printer;
    private static SerialPortDriver serialPortDriver;
    private static Beeper beeper;
    private static EmvHandler emvHandler;
    private static InnerScanner innerScanner;
    private static LogRecorder logRecorder;
    private static EmvRupayService emvRupayService;
    private static Printer printer1;
    private static IPed ped;
    private static CPUTypeAHandler cpuTypeAHandler;
    private static EmulateCardHandler emulateCardHandler;

    public static void init(DeviceServiceProvider app) {
        deviceServiceProvider = (DeviceServiceProvider) app;
        // Notify all waiting listeners now that the device service is ready.
        for (OnDeviceReadyListener l : sDeviceReadyListeners) {
            l.onDeviceReady();
        }
        sDeviceReadyListeners.clear();
    }


    private static SerialPort usbSerialPort;
    private static IDukpt dukpt;
    private static TpmManager tpmManager;
    private static IAT24CxxCard at24CxxCard;
    private static IM1Card m1CardHandler;
    private static ICpuCard cpuCard;
    private static ICpuRFCard cpuRFCard;
    private static IFelica felica;
    private static IPSAM psam;
    private static IMFULEv1Card mfulEv1Card;
    private static IMFULCCard mfulCCard;
    private static ISLE4442Card sle4442Card;
    private static INTAG215Card ntag215Card;

    @SuppressLint("NewApi")
    public static DeviceServiceEngine getDeviceService() throws RemoteException {
        if (deviceServiceProvider == null) {
            throw new RemoteException("DeviceServiceProvider is not initialized.");
        }
        if (deviceServiceProvider.getDeviceService() == null) {
            checkState();
        }
        return deviceServiceProvider.getDeviceService();
    }

    public static void checkState() throws RemoteException {
        if (deviceServiceProvider == null) {
            throw new RemoteException("Please restart the application.");
        }
        if (deviceServiceProvider.getDeviceService() == null) {
            deviceServiceProvider.bindDeviceService();
            reset();
            throw new RemoteException("Device service connection failed, please try again later.");
        }
    }

    @SuppressLint("NewApi")
    public static void initDevices(Application application) throws RemoteException {
        if (application == null) {
            return;
        }
        if (deviceServiceProvider == null && application instanceof DeviceServiceProvider) {
            deviceServiceProvider = (DeviceServiceProvider) application;
        }
        if (getDeviceService() != null) {
            try {
                pinpad = getPinpad();
                magCardReader = getMagCardReader();
                ledDriver = getLedDriver();
                multipleAppPrinter = getMultipleAppPrinter();
                printer = getPrinter();
                beeper = getBeeper();
                emvHandler = getEmvHandler();
                innerScanner = getInnerScanner();
                logRecorder = getLogRecorder();
                emvRupayService = getEmvRupayService();
                cpuTypeAHandler = getCpuTypeAHandler();
                emulateCardHandler = getEmulateCardHandler();
                dukpt = getDukpt();
                tpmManager = getTpmManager();
                at24CxxCard = getAT24CxxCard();
                cpuCard = getCpuCardHandler();
                cpuRFCard = getCpuRFCard();
                felica = getFelica();
                psam = getPSAM();
                mfulEv1Card = getMFULEv1Card();
                mfulCCard = getMFULCCard();
                sle4442Card = getSLE4442Card();
                ntag215Card = getNTAGCard();
                m1CardHandler = getM1CardHandler();
            } catch (RemoteException e) {
                e.printStackTrace();
                throw e;
            }
        } else {
            deviceServiceProvider.bindDeviceService();
            reset();
        }
    }

    @SuppressLint("NewApi")
    public static PinPad getPinpad() throws RemoteException {
        if (pinpad == null) {
            checkState();
            try {
                return deviceServiceProvider.getDeviceService().getPinPad();
            } catch (RemoteException e) {
                throw new RemoteException("PinPad service acquisition failed, please try again later.");
            }
        } else {
            return pinpad;
        }
    }

    @SuppressLint("NewApi")
    public static IPed getPed() throws RemoteException {
        if (ped == null) {
            checkState();
            try {
                return deviceServiceProvider.getDeviceService().getPed();
            } catch (RemoteException e) {
                throw new RemoteException("Ped service acquisition failed, please try again later.");
            }
        } else {
            return ped;
        }
    }


    @SuppressLint("NewApi")
    public static IccCardReader getIccCardReader(int cardType) throws RemoteException {
        if (iccCardReader == null) {
            checkState();
            try {
                return deviceServiceProvider.getDeviceService().getIccCardReader(cardType);
            } catch (RemoteException e) {
                throw new RemoteException("PinPad service acquisition failed, please try again later.");
            }
        } else {
            return iccCardReader;
        }
    }


    @SuppressLint("NewApi")
    public static SecureArea getSecureArea() throws RemoteException {
        if (mSecureArea == null) {
            checkState();
            try {
                return deviceServiceProvider.getDeviceService().getSecureAreaHandler();
            } catch (RemoteException e) {
                throw new RemoteException("SecureArea service acquisition failed, please try again later.");
            }
        } else {
            return mSecureArea;
        }
    }

    @SuppressLint("NewApi")
    public static Hsm getHsm() throws RemoteException {
        if (mHsm == null) {
            checkState();
            try {
                return deviceServiceProvider.getDeviceService().getHsmDevice();
            } catch (RemoteException e) {
                throw new RemoteException("SecureArea service acquisition failed, please try again later.");
            }
        } else {
            return mHsm;
        }
    }


    @SuppressLint("NewApi")
    public static MagCardReader getMagCardReader() throws RemoteException {
        if (magCardReader == null) {
            checkState();
            try {
                return deviceServiceProvider.getDeviceService().getMagCardReader();
            } catch (RemoteException e) {
                throw new RemoteException("PinPad service acquisition failed, please try again later.");
            }
        } else {
            return magCardReader;
        }
    }

    @SuppressLint("NewApi")
    public static LEDDriver getLedDriver() throws RemoteException {
        if (ledDriver == null) {
            checkState();
            try {
                return deviceServiceProvider.getDeviceService().getLEDDriver();
            } catch (RemoteException e) {
                throw new RemoteException("PinPad service acquisition failed, please try again later.");
            }
        } else {
            return ledDriver;
        }
    }

    @SuppressLint("NewApi")
    public static MultipleAppPrinter getMultipleAppPrinter() throws RemoteException {
        if (multipleAppPrinter == null) {
            checkState();
            try {
                return deviceServiceProvider.getDeviceService().getMultipleAppPrinter();
            } catch (RemoteException e) {
                throw new RemoteException("PinPad service acquisition failed, please try again later.");
            }
        } else {
            return multipleAppPrinter;
        }
    }

    @SuppressLint("NewApi")
    public static Printer getPrinter() throws RemoteException {
        if (printer == null) {
            checkState();
            try {
                return deviceServiceProvider.getDeviceService().getPrinter();
            } catch (RemoteException e) {
                return null;
            }
        } else {
            return printer;
        }
    }

    @SuppressLint("NewApi")
    public static SerialPortDriver getSerialPortDriver(int port) throws RemoteException {
        if (serialPortDriver == null) {
            checkState();
            try {
                return deviceServiceProvider.getDeviceService().getSerialPortDriver(port);
            } catch (RemoteException e) {
                throw new RemoteException("PinPad service acquisition failed, please try again later.");
            }
        } else {
            return serialPortDriver;
        }
    }

    @SuppressLint("NewApi")
    public static SerialPort getUsbSerialPort(String path) throws RemoteException {
        if (usbSerialPort == null) {
            checkState();
            try {
                return deviceServiceProvider.getDeviceService().getSerialPort(path);
            } catch (RemoteException e) {
                throw new RemoteException("PinPad service acquisition failed, please try again later.");
            }
        } else {
            return usbSerialPort;
        }
    }

    @SuppressLint("NewApi")
    public static Beeper getBeeper() throws RemoteException {
        if (beeper == null) {
            checkState();
            try {
                return deviceServiceProvider.getDeviceService().getBeeper();
            } catch (RemoteException e) {
                throw new RemoteException("PinPad service acquisition failed, please try again later.");
            }
        } else {
            return beeper;
        }
    }

    @SuppressLint("NewApi")
    public static EmvHandler getEmvHandler() throws RemoteException {
        if (emvHandler == null) {
            checkState();
            try {
                return deviceServiceProvider.getDeviceService().getEmvHandler();
            } catch (RemoteException e) {
                throw new RemoteException("PinPad service acquisition failed, please try again later.");
            }
        } else {
            return emvHandler;
        }
    }

    @SuppressLint("NewApi")
    public static EmvRupayService getEmvRupayService() throws RemoteException {
        if (emvRupayService == null) {
            checkState();
            try {
                return deviceServiceProvider.getDeviceService().getEmvRupayService();
            } catch (RemoteException e) {
                throw new RemoteException("PinPad service acquisition failed, please try again later.");
            }
        } else {
            return emvRupayService;
        }
    }

    @SuppressLint("NewApi")
    public static InnerScanner getInnerScanner() throws RemoteException {
        if (innerScanner == null) {
            checkState();
            try {
                return deviceServiceProvider.getDeviceService().getInnerScanner();
            } catch (RemoteException e) {
                throw new RemoteException("PinPad service acquisition failed, please try again later.");
            }
        } else {
            return innerScanner;
        }
    }

    @SuppressLint("NewApi")
    public static LogRecorder getLogRecorder() throws RemoteException {
        if (logRecorder == null) {
            checkState();
            try {
                return deviceServiceProvider.getDeviceService().getLogRecorder();
            } catch (RemoteException e) {
                throw new RemoteException("PinPad service acquisition failed, please try again later.");
            }
        } else {
            return logRecorder;
        }
    }

    @SuppressLint("NewApi")
    public static CPUTypeAHandler getCpuTypeAHandler() throws RemoteException {
        if (cpuTypeAHandler == null) {
            checkState();
            try {
                return deviceServiceProvider.getDeviceService().getCPUTypeAHandler();
            } catch (RemoteException e) {
                throw new RemoteException("PinPad service acquisition failed, please try again later.");
            }
        } else {
            return cpuTypeAHandler;
        }
    }

    @SuppressLint("NewApi")
    public static EmulateCardHandler getEmulateCardHandler() throws RemoteException {
        if (emulateCardHandler == null) {
            checkState();
            try {
                return deviceServiceProvider.getDeviceService().getEmulateCardHandler();
            } catch (RemoteException e) {
                throw new RemoteException("PinPad service acquisition failed, please try again later.");
            }
        } else {
            return emulateCardHandler;
        }
    }

    @SuppressLint("NewApi")
    public static IDukpt getDukpt() throws RemoteException {
        if (dukpt == null) {
            checkState();
            try {
                return deviceServiceProvider.getDeviceService().getDukpt();
            } catch (RemoteException e) {
                throw new RemoteException("PinPad service acquisition failed, please try again later.");
            }
        } else {
            return dukpt;
        }
    }

    @SuppressLint("NewApi")
    public static TpmManager getTpmManager() throws RemoteException {
        if (tpmManager == null) {
            checkState();
            try {
                return deviceServiceProvider.getDeviceService().getTpmManager();
            } catch (RemoteException e) {
                throw new RemoteException("Tpm service acquisition failed, please try again later.");
            }
        } else {
            return tpmManager;
        }
    }

    @SuppressLint("NewApi")
    public static IAT24CxxCard getAT24CxxCard() throws RemoteException {
        if (at24CxxCard == null) {
            checkState();
            try {
                return deviceServiceProvider.getDeviceService().getAT24CxxCard();
            } catch (RemoteException e) {
                throw new RemoteException("Tpm service acquisition failed, please try again later.");
            }
        } else {
            return at24CxxCard;
        }
    }

    @SuppressLint("NewApi")
    public static ICpuCard getCpuCardHandler() throws RemoteException {
        if (cpuCard == null) {
            checkState();
            try {
                return deviceServiceProvider.getDeviceService().getCpuCard();
            } catch (RemoteException e) {
                throw new RemoteException("PinPad service acquisition failed, please try again later.");
            }
        } else {
            return cpuCard;
        }
    }

    @SuppressLint("NewApi")
    public static IM1Card getM1CardHandler() throws RemoteException {
        if (m1CardHandler == null) {
            checkState();
            try {
                return deviceServiceProvider.getDeviceService().getM1Card();
            } catch (RemoteException e) {
                throw new RemoteException("PinPad service acquisition failed, please try again later.");
            }
        } else {
            return m1CardHandler;
        }
    }


    @SuppressLint("NewApi")
    public static ICpuRFCard getCpuRFCard() throws RemoteException {
        if (cpuRFCard == null) {
            checkState();
            try {
                return deviceServiceProvider.getDeviceService().getCpuRFCard();
            } catch (RemoteException e) {
                throw new RemoteException("PinPad service acquisition failed, please try again later.");
            }
        } else {
            return cpuRFCard;
        }
    }

    @SuppressLint("NewApi")
    public static IFelica getFelica() throws RemoteException {
        if (felica == null) {
            checkState();
            try {
                return deviceServiceProvider.getDeviceService().getFelica();
            } catch (RemoteException e) {
                throw new RemoteException("PinPad service acquisition failed, please try again later.");
            }
        } else {
            return felica;
        }
    }


    public static IPSAM getPSAM() throws RemoteException {
        if (psam == null) {
            checkState();
            try {
                return deviceServiceProvider.getDeviceService().getPSAM();
            } catch (RemoteException e) {
                throw new RemoteException("PinPad service acquisition failed, please try again later.");
            }
        } else {
            return psam;
        }
    }

    public static IMFULEv1Card getMFULEv1Card() throws RemoteException {
        if (mfulEv1Card == null) {
            checkState();
            try {
                return deviceServiceProvider.getDeviceService().getMFULEV1Card();
            } catch (RemoteException e) {
                throw new RemoteException("PinPad service acquisition failed, please try again later.");
            }
        } else {
            return mfulEv1Card;
        }
    }

    public static IMFULCCard getMFULCCard() throws RemoteException {
        if (mfulCCard == null) {
            checkState();
            try {
                return deviceServiceProvider.getDeviceService().getMFULCCard();
            } catch (RemoteException e) {
                throw new RemoteException("PinPad service acquisition failed, please try again later.");
            }
        } else {
            return mfulCCard;
        }
    }

    public static ISLE4442Card getSLE4442Card() throws RemoteException {
        if (sle4442Card == null) {
            checkState();
            try {
                return deviceServiceProvider.getDeviceService().getSLE4442Card();
            } catch (RemoteException e) {
                throw new RemoteException("PinPad service acquisition failed, please try again later.");
            }
        } else {
            return sle4442Card;
        }
    }

    public static INTAG215Card getNTAGCard() throws RemoteException {
        if (ntag215Card == null) {
            checkState();
            try {
                return deviceServiceProvider.getDeviceService().getNTAG215Card();
            } catch (RemoteException e) {
                throw new RemoteException("PinPad service acquisition failed, please try again later.");
            }
        } else {
            return ntag215Card;
        }
    }

    public static void reset() {
        pinpad = null;
        iccCardReader = null;
        magCardReader = null;
        ledDriver = null;
        multipleAppPrinter = null;
        serialPortDriver = null;
        beeper = null;
        emvHandler = null;
        innerScanner = null;
        logRecorder = null;
        ped = null;
        emulateCardHandler = null;
        usbSerialPort = null;
        dukpt = null;
        tpmManager = null;
        at24CxxCard = null;
        m1CardHandler = null;
        cpuCard = null;
        cpuRFCard = null;
        felica = null;
        psam = null;
        mfulEv1Card = null;
        mfulCCard = null;
        sle4442Card = null;
        ntag215Card = null;
        printer = null;
        deviceServiceProvider = null;
    }

}
