package co.za.vectra.cordova.scannerplugin;

import android.app.Activity;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.os.RemoteException;
import android.util.Log;
import android.view.KeyEvent;

import co.za.vectra.scanner.api.service.aidl.IThumbzupScannerService;
import co.za.vectra.scanner.api.service.aidl.IThumbzupScannerServiceCallback;

/**
 * Utility class that's used to start and stop the scan service
 */
public class ThirdPartyScanController {

  private interface ThirdPartyScanControllerListener {
      public void onInitialised();
      public void onDisconnect();
  }
  private ThirdPartyScanControllerListener interalListener;
  private ThirdPartyScanListener scanListener;
  private static ThirdPartyScanController instance;
  private Activity activity;

  private IThumbzupScannerService scannerService;
  private ServiceConnection scannerServiceConnectionn = new ServiceConnection() {
      @Override
      public void onServiceConnected(ComponentName name, IBinder service) {
          Log.d(Resources.APP_TAG, "onServiceConnected...");
          scannerService = IThumbzupScannerService.Stub.asInterface(service);
          try {
              scannerService.initScanner();
          } catch (RemoteException rex) {
              Log.e(Resources.APP_TAG, rex.getMessage(), rex);
          }

          if (scanListener != null) {
              scanListener.onInitialised();
          }
          if (interalListener != null) {
              interalListener.onInitialised();
          }
      }

      @Override
      public void onServiceDisconnected(ComponentName name) {
          scannerService = null;
          if (scanListener != null) {
              scanListener.onDisconnect();
          }
          if (interalListener != null) {
              interalListener.onDisconnect();
          }
      }
  };

  private ThirdPartyScanController() {
  }

  public static ThirdPartyScanController getInstance() {
      if (instance == null) {
          instance = new ThirdPartyScanController();
      }

      return instance;
  }

  public void setScanListener(ThirdPartyScanListener listener) {
      this.scanListener = listener;
  }

  public void init(Activity activity) {
      this.activity = activity;
      Intent intent = new Intent(Resources.SCAN_SERVICE_COMMAND);
      intent.setClassName(Resources.SCAN_SERVICE_PACKAGE, Resources.SCAN_SERVICE_CLASS);
      activity.bindService(intent, scannerServiceConnectionn, Context.BIND_AUTO_CREATE);
  }

  public void startScanning(Activity activity, final boolean mustBeep) {
      this.activity = activity;
      Resources.wasSoftwareButtonScan = true;
      internalStartScanning(activity, mustBeep);
  }

  private void internalStartScanning(Activity activity, final boolean mustBeep) {
      this.activity = activity;
      if (isScannerInitialised()) {
          try {
              scannerService.startScanning(mustBeep, scannerServiceCallback);
          } catch (RemoteException rex) {
              Log.e(Resources.APP_TAG, rex.getMessage(), rex);
          }
      } else {
          interalListener = new ThirdPartyScanControllerListener() {
              @Override
              public void onInitialised() {
                  try {
                      scannerService.startScanning(mustBeep, scannerServiceCallback);
                  } catch (RemoteException rex) {
                      Log.e(Resources.APP_TAG, rex.getMessage(), rex);
                  }
              }

              @Override
              public void onDisconnect() {
              }
          };
      }
      init(activity);
  }

  public void stopScanning(final Activity activity) {
      this.activity = activity;
      if (isScannerInitialised()) {
          try {
              scannerService.stopScanning();
          } catch (RemoteException rex) {
              Log.e(Resources.APP_TAG, rex.getMessage(), rex);
          }
      }
  }

  public void handlePossibleScanEvent(Activity activity, KeyEvent event, boolean mustPlayScanBeep) {
      this.activity = activity;
      Resources.wasSoftwareButtonScan = false;

      if (KeyEvent.ACTION_DOWN == event.getAction()
              && event.getKeyCode() == Resources.SCAN_BUTTON_KEY_CODE
              && Resources.canScanAgain == true) {
          Resources.canScanAgain = false;

          if (!Resources.busyScanning) {
              Resources.busyScanning = true;
              scanListener.onScanStarted();
          }
          ThirdPartyScanController.getInstance().internalStartScanning(activity, mustPlayScanBeep);
      } else if (KeyEvent.ACTION_UP == event.getAction() && event.getKeyCode() == Resources.SCAN_BUTTON_KEY_CODE) {
          Resources.busyScanning = false;
          Resources.canScanAgain = true;
          scanListener.onScanStopped();

          ThirdPartyScanController.getInstance().stopScanning(activity);
      }
  }

  public void handlePossibleScanEvent(Activity activity, int action, int keyCode, boolean mustPlayScanBeep) {
      this.activity = activity;
      Resources.wasSoftwareButtonScan = false;

      if (KeyEvent.ACTION_DOWN == action
              && keyCode == Resources.SCAN_BUTTON_KEY_CODE
              && Resources.canScanAgain == true) {
          Resources.canScanAgain = false;

          if (!Resources.busyScanning) {
              Resources.busyScanning = true;
              scanListener.onScanStarted();
          }
          ThirdPartyScanController.getInstance().internalStartScanning(activity, mustPlayScanBeep);
      } else if (KeyEvent.ACTION_UP == action && keyCode == Resources.SCAN_BUTTON_KEY_CODE) {
          Resources.busyScanning = false;
          Resources.canScanAgain = true;
          scanListener.onScanStopped();

          ThirdPartyScanController.getInstance().stopScanning(activity);
      }
  }

  private boolean isScannerInitialised() {
      return scannerService != null;
  }

  private IThumbzupScannerServiceCallback scannerServiceCallback = new IThumbzupScannerServiceCallback.Stub() {
      @Override
      public void onScanCompleted(final String code) {
          Log.d(Resources.APP_TAG, "onScanCompleted: " + code);

          if (Resources.wasSoftwareButtonScan == true) {
              try {
                  scannerService.stopScanning();
              } catch (RemoteException rex) {
                  Log.e(Resources.APP_TAG, rex.getMessage(), rex);
              }
          }

          Thread runnable = new Thread() {
              @Override
              public void run() {
                  Looper.prepare();
                  Handler handler = new Handler();
                  try {
                      Thread.sleep(100);
                  } catch (InterruptedException e) {
                      e.printStackTrace();
                  }

                  try {
                      scannerService.stopScanning();
                  } catch (RemoteException rex) {
                      Log.e(Resources.APP_TAG, rex.getMessage(), rex);
                  }

                  Log.d(Resources.APP_TAG, "Bar code scanned: " + code);

                  activity.runOnUiThread(new Runnable() {
                      @Override
                      public void run() {
                          if (scanListener != null) {
                              int len = code != null ? code.trim().length() : 0;
                              String retCode = code != null ? code.trim() : "";
                              scanListener.onScanSuccess(len, retCode);
                          }
                      }
                  });
                  Looper.loop();
              }
          };
          runnable.start();
      }

      public void basicTypes(int anInt, long aLong, boolean aBoolean,
                             float aFloat, double aDouble, String aString) {
          // Does nothing
      }
  };

}
