package cordova;

import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.RectF;
import android.util.Base64;

import com.scansolutions.mrzscannerlib.MRZEffortLevel;
import com.scansolutions.mrzscannerlib.MRZLicenceResultListener;
import com.scansolutions.mrzscannerlib.MRZResultModel;
import com.scansolutions.mrzscannerlib.MRZScanner;
import com.scansolutions.mrzscannerlib.MRZScannerListener;

import org.apache.cordova.CallbackContext;
import org.apache.cordova.CordovaPlugin;
import org.apache.cordova.PluginResult;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import java.io.ByteArrayOutputStream;

/**
 * This class echoes a string called from JavaScript.
 */
public class MrzScanner extends CordovaPlugin implements MRZScannerListener, MRZScannerDismissedListener {
    private CallbackContext resultCallbackContext = null;
    float zoomFactor = 0f;
    public boolean execute(String action, JSONArray args, CallbackContext callbackContext) throws JSONException {
        if (action.equals("startScanner")) {
            resultCallbackContext = callbackContext;
            ScannerActivity.startScanner(cordova.getActivity(),zoomFactor, MrzScanner.this, MrzScanner.this);
            return true;
        } else if (action.equals("startPartialViewScanner")) {
            resultCallbackContext = callbackContext;
            ScannerActivity.startScanner(cordova.getContext(),zoomFactor,
                    this,
                    this,
                    new RectF(args.getInt(0), args.getInt(1), args.getInt(2), args.getInt(3)));
            return true;
        } else if ("setScannerType".equals(action)) {
            ScannerActivity.scannerType = args.getInt(0);

            return true;
        } else if ("setMaxThreads".equals(action)) {
            MRZScanner.setMaxThreads(args.getInt(0));

            return true;
        } else if ("registerWithLicenseKey".equals(action)) {
            MRZScanner.registerWithLicenseKey(cordova.getActivity(), args.getString(0), new MRZLicenceResultListener() {
                @Override
                public void onRegisterWithLicenceResult(int resultKey, String errorMessage) {
                    PluginResult pr;
                    if (errorMessage != null) {
                        pr = new PluginResult(PluginResult.Status.ERROR, errorMessage);
                    } else {
                        pr = new PluginResult(PluginResult.Status.OK, "Success");
                    }
                    callbackContext.sendPluginResult(pr);
                }
            });

            return true;
        } else if ("resumeScanner".equals(action)) {
            if (ScannerActivity.scannerActivityListener != null) {
                ScannerActivity.scannerActivityListener.resumeScanning();
            }
            return true;
        } else if ("closeScanner".equals(action)) {
            if (ScannerActivity.scannerActivityListener != null) {
                ScannerActivity.scannerActivityListener.closeScanner();
            }
            return true;
        } else if ("scanFromGallery".equals(action)) {
            resultCallbackContext = callbackContext;
            MRZScanner.scanFromGallery(cordova.getActivity(), this);

            return true;
        } else if ("setPassportActive".equals(action)) {
            MRZScanner.setPassportActive(args.getBoolean(0));

            return true;
        } else if ("setVibrateOnSuccessfulScan".equals(action)) {
            MRZScanner.setEnableVibrationOnSuccess(args.getBoolean(0));

            return true;
        } else if ("setIDActive".equals(action)) {
            MRZScanner.setIDActive(args.getBoolean(0));

            return true;
        } else if ("setContinuousScanningEnabled".equals(action)) {
            ScannerActivity.setContinuousScanningEnabled(args.getBoolean(0));

            return true;
        } else if ("setIgnoreDuplicatesEnabled".equals(action)) {
            ScannerActivity.setIgnoreDuplicatesEnabled(args.getBoolean(0));

            return true;
        } else if ("setVisaActive".equals(action)) {
            MRZScanner.setVisaActive(args.getBoolean(0));

            return true;
        } else if ("scanBitmap".equals(action)) {
            resultCallbackContext = callbackContext;
            Bitmap bitmap = decodeBase64(args.getString(0));
            MRZScanner.scanBitmap(bitmap, cordova.getActivity(), this);

            return true;
        } else if ("setExtractPortraitEnabled".equals(action)) {
            ScannerActivity.setExtractPortraitEnabled(args.getBoolean(0));

            return true;
        } else if ("setExtractFullPassportImageEnabled".equals(action)) {
            ScannerActivity.setExtractFullPassportImageEnabled(args.getBoolean(0));

            return true;
        } else if ("setExtractSignatureEnabled".equals(action)) {
            ScannerActivity.setExtractSignatureEnabled(args.getBoolean(0));

            return true;
        } else if ("setExtractIdBackImageEnabled".equals(action)) {
            ScannerActivity.setExtractIdBackImageEnabled(args.getBoolean(0));

            return true;
        } else if ("getSdkVersion".equals(action)) {
            String sdkVersionString = MRZScanner.sdkVersion();
            PluginResult pr = new PluginResult(PluginResult.Status.OK, sdkVersionString);
            callbackContext.sendPluginResult(pr);

            return true;
        } else if ("setDateFormat".equals(action)) {
          MRZScanner.setDateFormat(args.getString(0));

          return true;
        } else if ("setEffortLevel".equals(action)) {
          int level = args.getInt(0);
          MRZEffortLevel effortLevel;

          switch (level) {
            case 0:
              effortLevel = MRZEffortLevel.EFFORT_LEVEL_CASUAL;
              break;
            default:
            case 1:
              effortLevel = MRZEffortLevel.EFFORT_LEVEL_TRY_HARDER;
              break;
            case 2:
              effortLevel = MRZEffortLevel.EFFORT_LEVEL_SWEATY;
              break;
          }

          MRZScanner.setEffortLevel(effortLevel);

            return true;
        } else if ("toggleFlash".equals(action)) {
          boolean toggleEnabled = args.getBoolean(0);
          ScannerActivity.flashToggleActivated = toggleEnabled;
          Activity scannerActivity = cordova.getActivity();
          if (scannerActivity instanceof ScannerActivity) {
            ((ScannerActivity) scannerActivity).toggleFlash(toggleEnabled);
          }
          return true;
        } else if ("setShowFlashButton".equals(action)) {
          boolean showFlashButton = args.getBoolean(0);
          ScannerActivity.setShowFlashButton(showFlashButton);

          return true;
        } else if ("startScannerWithCustomOverlay".equals(action)) {
            resultCallbackContext = callbackContext;
            String base64String = args.getString(0);
            ScannerActivity.startScannerWithCustomOverlay(cordova.getActivity(),zoomFactor, MrzScanner.this, base64String, MrzScanner.this);
            return true;
        } else if ("setZoomFactor".equals(action)) {
            zoomFactor = (float) args.getDouble(0);
            MRZScanner.setZoomFactor(zoomFactor);
        }

        return false;
    }

    private String convertMapToB64(Bitmap bitmap) {
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        bitmap.compress(Bitmap.CompressFormat.PNG, 100, byteArrayOutputStream);
        byte[] byteArray = byteArrayOutputStream.toByteArray();

        return Base64.encodeToString(byteArray, Base64.DEFAULT);
    }

    private Bitmap decodeBase64(String string) {
        byte[] decodedString = Base64.decode(string, Base64.DEFAULT);
        return BitmapFactory.decodeByteArray(decodedString, 0, decodedString.length);
    }

    @Override
    public void successfulScanWithResult(MRZResultModel mrzResultModel) {
        JSONObject successfulMrzScan = new JSONObject();
        try {
            successfulMrzScan.put("document_type_raw", mrzResultModel.documentTypeRaw);
            successfulMrzScan.put("document_type_readable", mrzResultModel.documentTypeReadable);
            successfulMrzScan.put("issuing_country", mrzResultModel.issuingCountry);
            successfulMrzScan.put("surname", mrzResultModel.surnamesReadable());
            successfulMrzScan.put("document_number", mrzResultModel.documentNumber);
            successfulMrzScan.put("nationality", mrzResultModel.nationality);
            successfulMrzScan.put("dob_raw", mrzResultModel.dobRaw);
            successfulMrzScan.put("dob_readable", mrzResultModel.dobReadable);
            successfulMrzScan.put("sex", mrzResultModel.sex);
            successfulMrzScan.put("est_issuing_date_raw", mrzResultModel.estIssuingDateRaw);
            successfulMrzScan.put("est_issuing_date_readable", mrzResultModel.estIssuingDateReadable);
            successfulMrzScan.put("expiration_date_raw", mrzResultModel.expirationDateRaw);
            successfulMrzScan.put("expiration_date_readable", mrzResultModel.expirationDateReadable);
            successfulMrzScan.put("given_names_readable", mrzResultModel.givenNamesReadable());
            successfulMrzScan.put("optionals", mrzResultModel.optionalsReadable());

            if (mrzResultModel.signature != null) {
                String bitmapEncoded = convertMapToB64(mrzResultModel.signature);
                successfulMrzScan.put("signature", bitmapEncoded);
            }

            if (mrzResultModel.portrait != null) {
                String bitmapEncoded = convertMapToB64(mrzResultModel.portrait);
                successfulMrzScan.put("portrait", bitmapEncoded);
            }

            if (mrzResultModel.fullImage != null) {
                String bitmapEncoded = convertMapToB64(mrzResultModel.fullImage);
                successfulMrzScan.put("passportImage", bitmapEncoded);
            }

            if (mrzResultModel.idBack != null) {
                String bitmapEncoded = convertMapToB64(mrzResultModel.idBack);
                successfulMrzScan.put("idBack", bitmapEncoded);
            }

            PluginResult pr = new PluginResult(PluginResult.Status.OK, successfulMrzScan);

            if (ScannerActivity.continuousScanningEnabled)
                pr.setKeepCallback(true);
            resultCallbackContext.sendPluginResult(pr);
        } catch (JSONException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void successfulScanWithDocumentImage(Bitmap bitmap) {
        String bitmapEncoded = convertMapToB64(bitmap);
        PluginResult pr = new PluginResult(PluginResult.Status.OK, bitmapEncoded);
        resultCallbackContext.sendPluginResult(pr);
    }

    @Override
    public void successfulIdFrontImageScan(Bitmap fullImage, Bitmap portrait) {
        String fullImageEncoded = convertMapToB64(fullImage);
        String portraitEncoded = convertMapToB64(portrait);

        JSONObject result = new JSONObject();
        try {
            result.put("fullImage", fullImageEncoded);
        } catch (JSONException e) {
            //NO-OP
        }
        try {
            result.put("portrait", portraitEncoded);
        } catch (JSONException e) {
            //NO-OP
        }

        PluginResult pr = new PluginResult(PluginResult.Status.OK, result);
        resultCallbackContext.sendPluginResult(pr);
    }

    @Override
    public void scanImageFailed() {
        String scanFailed = "Scan Failed";
        PluginResult pr = new PluginResult(PluginResult.Status.ERROR, scanFailed);
        resultCallbackContext.sendPluginResult(pr);
    }

    @Override
    public void permissionsWereDenied() {
        String cameraPermissionDenied = "Camera Permission Denied";
        PluginResult pr = new PluginResult(PluginResult.Status.ERROR, cameraPermissionDenied);
        resultCallbackContext.sendPluginResult(pr);
    }

    @Override
    public void scannerWasDismissed() {
        PluginResult pr = new PluginResult(PluginResult.Status.NO_RESULT, "scannerWasDismissed");
        pr.setKeepCallback(false);
        resultCallbackContext.sendPluginResult(pr);
    }
}
