package com.visagetechnologies.lightConditions;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.app.Activity;
import android.content.res.AssetManager;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.Window;
import android.widget.FrameLayout;
import com.visagetechnologies.bsc.FrameProvider;
import com.visagetechnologies.makeupsdk.Effect;
import com.visagetechnologies.makeupsdk.IApplicationLifecycleHandler;
import com.visagetechnologies.makeupsdk.IMakeupObserver;
import com.visagetechnologies.makeupsdk.MakeupEngine;
import com.visagetechnologies.makeupsdk.SDKProvider;
import com.visagetechnologies.makeupsdk.LightConditionsAnalyzer;
import com.visagetechnologies.makeupsdk.LicenseTypeEnum;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.util.EnumMap;
import java.util.Map;

class ExternalMakeupObserver implements IMakeupObserver {
  private static String TAG = "ExternalMakeupObserver";

  @Override
  public void OnEffectCreated(MakeupEngine sender, Effect effect) {
    sender.DisplayMakeup(effect);
    Log.d(TAG, "OnEffectCreated effectID: " + Long.toString(effect.GetID()));
  }

  @Override
  public void OnEffectRemoved(MakeupEngine sender, Effect effect) {
    Log.d(TAG, "OnEffectRemoved effectID: " + Long.toString(effect.GetID()));
  }

  @Override
  public void OnEffectHidden(MakeupEngine sender, Effect effect) {
    Log.d(TAG, "OnEffectHidden effectID: " + Long.toString(effect.GetID()));
  }

  @Override
  public void OnEffectDisplayed(MakeupEngine sender, Effect effect) {
    Log.d(TAG, "OnEffectDisplayed effectID: " + Long.toString(effect.GetID()));
  }

  @Override
  public void OnClear(MakeupEngine effect) {
    Log.d(TAG, "OnClear");
  }

  @Override
  public void OnStart(MakeupEngine effect) {
    Log.d(TAG, "OnStart");
  }

  public void OnEffectUpdated(MakeupEngine sender, Effect effect) {
    Log.d(TAG, "OnEffectUpdated effectID: " + Long.toString(effect.GetID()));
  }
}

public class MainActivity extends Activity {

  static {
    System.loadLibrary("BeautySightCore");
    System.loadLibrary("FrameProvider");
  }

  public static String TAG = "MainActivity";

  SDKProvider sdkProvider;
  MakeupEngine makeupEngine;
  IApplicationLifecycleHandler lifecycleHandler;
  ExternalMakeupObserver externalObserver = new ExternalMakeupObserver();
  LightConditionsAnalyzer lightConditionsAnalyzer;
  CameraActivity camera;

  private final int finishedAfterFrames = 5;
  private int nFrames;

  private String loadLicenceCached(String path, String mapName)  {
    AssetManager manager = this.getAssets();

    File f = new File(getCacheDir() + "/" + mapName);
    if (!f.exists())
      try {
        InputStream is = manager.open(path);
        int size = is.available();
        byte[] buffer = new byte[size];
        is.read(buffer);
        is.close();

        FileOutputStream fos = new FileOutputStream(f);

        // Print the content of buffer as a String
        String content = new String(buffer, "UTF-8"); // Specify charset like UTF-8
        System.out.println(content);

        fos.write(buffer);
        fos.close();
      } catch (Exception e) {
        throw new RuntimeException(e);
      }

      return f.getPath();
  }

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    requestWindowFeature(Window.FEATURE_NO_TITLE);
    super.onCreate(savedInstanceState);

    nFrames = 0;
    Map<LicenseTypeEnum, String> licenses = new EnumMap<LicenseTypeEnum, String>(LicenseTypeEnum.class);
    licenses.put(LicenseTypeEnum.MAKEUP, loadLicenceCached("license.vlc","ml.map"));
    licenses.put(LicenseTypeEnum.SKINTONE, loadLicenceCached("license_shadefinder.vlc","stl.map"));

    sdkProvider = SDKProvider.GetProvider(licenses, this);

    FrameProvider frameProvider = null;
    try {
      frameProvider = sdkProvider.GetFrameProvider();
    } catch (Exception e) {
      e.printStackTrace();
    }

    try {
      makeupEngine = sdkProvider.CreateMakeupEngine();
    } catch (Exception e) {
      e.printStackTrace();
    }

    try {
      sdkProvider.SetLightConditionsBacklightThreshold(0.5f);
      sdkProvider.SetLightConditionsUniformityThreshold(0.5f);
      analyzer = sdkProvider.CreateLightConditionsAnalyzer();
    } catch (Exception e) {
      e.printStackTrace();
    }

    camera = new CameraActivity(this, frameProvider);
    camera.GrabFromCamera();

    makeupEngine.AddObserver(externalObserver);

    View unityPlayer = makeupEngine.GetView();
    lifecycleHandler = makeupEngine.GetLifecycleHandler();

    setContentView(R.layout.activity_main);
    ((FrameLayout)findViewById(R.id.frame_layout)).addView(unityPlayer, FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT);

    unityPlayer.requestFocus();

    lifecycleHandler.onResume();
  }

  LightConditionsAnalyzer analyzer;
  public void analyzeLightConditions(View v){
    analyzer.StartAnalysis(new com.visagetechnologies.makeupsdk.LightConditionsCallback() {
        @Override
        public void done(com.visagetechnologies.bsc.LightConditionsResult result) {
        if(++nFrames < finishedAfterFrames) {
          return;
        }

        nFrames = 0;

        analyzer.StopAnalysis();
        
        runOnUiThread(new Runnable() {
          private boolean isFaceUniformlyLit = result.getIsFaceUniformlyLit();
          private float IsFaceUniformlyLitProbability = result.getIsFaceUniformlyLitProbability();
          private boolean hasNoBacklit = result.getHasNoBacklight();
          private float HasNoBacklightProbability = result.getHasNoBacklightProbability();

          @Override
          public void run() {
            AlertDialog dialog = (new AlertDialog.Builder(MainActivity.this))
                    .setTitle(R.string.light_conditions_dialog_title)
                    .setMessage(String.format(getString(R.string.light_conditions_dialog_message),
                            isFaceUniformlyLit, IsFaceUniformlyLitProbability, hasNoBacklit, HasNoBacklightProbability))
                    .setPositiveButton(R.string.light_conditions_dialog_button, new DialogInterface.OnClickListener() {
                      public void onClick(DialogInterface dialog, int id) { }
                    }).create();

            dialog.show();
          }
        });
        }
    });
  }

  // Quit Unity
  @Override
  protected void onDestroy() {
    camera.onDestroy();
    lifecycleHandler.onDestroy();
    super.onDestroy();
  }

  // Pause Unity
  @Override
  protected void onPause() {
    camera.onPause();
    super.onPause();
    lifecycleHandler.onPause();
  }

  // Resume Unity
  @Override
  protected void onResume() {
    camera.onResume();
    super.onResume();
    lifecycleHandler.onResume();
  }

  // Notify Unity of the focus change.
  @Override
  public void onWindowFocusChanged(boolean hasFocus) {
    super.onWindowFocusChanged(hasFocus);
    lifecycleHandler.onWindowFocusChanged(hasFocus);
  }
}
