/* Dali Clock - a melting digital clock for Android.
 * Copyright (c) 1991-2015 Jamie Zawinski <jwz@jwz.org>
 *
 * Permission to use, copy, modify, distribute, and sell this software and its
 * documentation for any purpose is hereby granted without fee, provided that
 * the above copyright notice appear in all copies and that both that
 * copyright notice and this permission notice appear in supporting
 * documentation.  No representations are made about the suitability of this
 * software for any purpose.  It is provided "as is" without express or
 * implied warranty.
 */

package org.jwz.daliclock;

import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.app.Activity;
import android.content.SharedPreferences;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.graphics.Point;
import android.os.Bundle;
import android.os.Handler;
import android.preference.PreferenceManager;
import android.support.v4.view.GestureDetectorCompat;
import android.util.Log;
import android.view.Display;
import android.view.GestureDetector;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.ScaleGestureDetector;
import android.view.SurfaceView;
import android.widget.LinearLayout;
import android.widget.TextView;

public class DaliClockActivity extends Activity
    implements GestureDetector.OnGestureListener,
               GestureDetector.OnDoubleTapListener {

  DaliClock clock;
  Display display;

  private GestureDetectorCompat mDetector;
  private ScaleGestureDetector mScaleDetector;

  private static final String LOG = "DaliClock";

  @Override
  public void onCreate (Bundle savedInstanceState) {

    super.onCreate (savedInstanceState);

    // DaliClock/app/src/main/res/layout/dream_layout.xml
    setContentView(R.layout.dream_layout);

    mDetector = new GestureDetectorCompat (this, this);
    mDetector.setOnDoubleTapListener(this);
    mScaleDetector = new ScaleGestureDetector (this, new ScaleListener());

    display = getWindowManager().getDefaultDisplay();
    LinearLayout bdiv = (LinearLayout) findViewById(R.id.clockbg);
    SurfaceView canvas = (SurfaceView) findViewById(R.id.canvas);
    SharedPreferences settings = 
      PreferenceManager.getDefaultSharedPreferences(this);
    SharedPreferences.Editor editor = settings.edit();

    editor.putBoolean("show_date_p", false);

    Point size = new Point();
    display.getRealSize(size); // using realSize as we are in full screen

    editor.putInt ("width",  (int) size.x);
    editor.putInt ("height", (int) size.y);

    editor.apply();

    if (clock != null) {
      clock.hide();
      clock.changeSettings(settings);
    } else {
      clock = new DaliClock(this);
      clock.setup(canvas, bdiv, settings);
    }
  }


  @Override
  protected void onStart() {
    super.onStart();
    clock.show();
  }


  // Boilerplate for handling events

  @Override 
  public boolean onTouchEvent (MotionEvent event) { 
    this.mDetector.onTouchEvent(event);
    this.mScaleDetector.onTouchEvent(event);
    return super.onTouchEvent(event);
  }

  @Override
  public boolean onDown (MotionEvent event) { 
    return true;
  }

  @Override
  public void onShowPress (MotionEvent event) {
  }

  @Override
  public void onLongPress (MotionEvent event) {
  }

  @Override
  public boolean onSingleTapUp (MotionEvent event) {
    return true;
  }

  @Override
  public boolean onDoubleTapEvent (MotionEvent event) {
    return true;
  }

  @Override
  public boolean onScroll (MotionEvent event1, MotionEvent event2,
                           float distanceX, float distanceY) {
    return false;	// We use onFling instead
  }


  // Display credits and version number for a few seconds.

  private void aboutBox() {
    SharedPreferences settings =
      PreferenceManager.getDefaultSharedPreferences(this);
    SharedPreferences.Editor editor = settings.edit();

    TextView tv = (TextView) findViewById(R.id.about_text);
    if (tv.getVisibility() == TextView.VISIBLE)
      return;

    editor.putBoolean("show_date_p", true);
    editor.apply();
    clock.changeSettings(settings);

    String name = this.getPackageName();
    PackageManager pm = this.getPackageManager();
    String vers = "INTERNAL ERROR";
    try {
      PackageInfo pi = pm.getPackageInfo(name, 0);
      vers = pi.versionName;
    } catch (PackageManager.NameNotFoundException e) {
    }

    int i = vers.lastIndexOf('-');
    String year = (i > 0 ? vers.substring(i+1) : "");
    int j = vers.indexOf(',');
    if (j > 0) vers = vers.substring(0, j);
    vers = ("Dali Clock " + vers + "\n" +
            "\u00a9 1991-" + year + " Jamie Zawinski\n" +
            "http://www.jwz.org/xdaliclock/");

    tv.setText(vers);

    final double display_secs = 3.5;
    final double fade_secs    = 0.25;

    // Start a fade in.
    //
    tv.setAlpha(0);
    tv.setVisibility(TextView.VISIBLE);
    tv.animate().alpha(1).setDuration((int) (fade_secs * 1000))
      .setListener(null);

    // Wait a bit, then start a fade-out.
    //
    Handler handler = new Handler();
    Runnable runnable = new Runnable() {
        @Override
          public void run() {
          // Wow, it's 2015 and Java still doesn't have closures.
          final TextView tv = (TextView) findViewById(R.id.about_text);
          tv.animate().alpha(0).setDuration((int) (fade_secs * 1000))
            .setListener(new AnimatorListenerAdapter() {
                @Override
                public void onAnimationEnd (Animator animation) {
                  tv.setVisibility(TextView.INVISIBLE);
                }
            });
        }
      };
    handler.postDelayed (runnable, (int) (display_secs * 1000));
  }


  // Single tap -- briefly display about box.

  @Override
  public boolean onSingleTapConfirmed (MotionEvent event) {
    aboutBox();
    return true;
  }


  // Double tap -- toggle 12-hour mode.
  //
  @Override
  public boolean onDoubleTap (MotionEvent event) {
    SharedPreferences settings =
      PreferenceManager.getDefaultSharedPreferences(this);
    SharedPreferences.Editor editor = settings.edit();

    boolean twelve_hour_p = settings.getBoolean("twelve_hour_p", false);
    String time_mode = settings.getString("time_mode", "HHMMSS");

    editor.putBoolean("show_date_p", false);

    // Change it only if hours currently visible;
    // In seconds-only mode, this is a mis-tap.
    if (! time_mode.equals("SS")) {
      editor.putBoolean("twelve_hour_p", !twelve_hour_p);
      Log.d (LOG, "twelve = " + (twelve_hour_p ? "true" : "false"));
    }

    editor.apply();
    clock.changeSettings(settings);

    return true;
  }


  private boolean resize_digits (boolean down_p) {
    SharedPreferences settings =
      PreferenceManager.getDefaultSharedPreferences(this);
    SharedPreferences.Editor editor = settings.edit();

    String time_mode = settings.getString("time_mode", "HHMMSS");

    if (down_p) {
      if (time_mode.equals("HHMMSS")) {
        editor.putString("time_mode", "HHMM");
        Log.d (LOG, "time = HHMM");
      } else if (time_mode.equals("HHMM")) {
        editor.putString("time_mode", "SS");
        Log.d (LOG, "time = SS");
      } else {
        Log.d (LOG, "time unchanged");
        return false;
      }

    } else {
      if (time_mode.equals("SS")) {
        editor.putString("time_mode", "HHMM");
        Log.d (LOG, "time = HHMM");
      } else if (time_mode.equals("HHMM")) {
        editor.putString("time_mode", "HHMMSS");
        Log.d (LOG, "time = HHMMSS");
      } else {
        Log.d (LOG, "time = unchanged");
        return false;
      }
    }

    editor.apply();
    clock.changeSettings(settings);
    return true;
  }


  // Drag left, drag down -- decrease the number of digits shown.
  // Drag right, drag up -- increase the number of digits shown.
  //
  @Override
  public boolean onFling (MotionEvent event1, MotionEvent event2, 
                          float velocityX, float velocityY) {

    float distX = event1.getX() - event2.getX();
    float distY = event2.getY() - event1.getY();
    boolean horiz_p = Math.abs(distX) > Math.abs(distY);
    float dist = (horiz_p ? distX : distY);
    return resize_digits (dist < 0);
  }


  // Pinch outward -- decrease the number of digits shown.
  // Pinch inward -- increase the number of digits shown.
  // #### untested, since the emulator can't do it
  //
  private class ScaleListener
    extends ScaleGestureDetector.SimpleOnScaleGestureListener {
    @Override
    public boolean onScale (ScaleGestureDetector detector) {
      float s = detector.getScaleFactor();
      return resize_digits (s > 1);
    }
  }


  @Override
  public boolean onKeyDown (int keyCode, KeyEvent event) {
    // #### not getting called

    int digit = -1;
    if (keyCode >= KeyEvent.KEYCODE_0 &&
        keyCode <= KeyEvent.KEYCODE_9)
      digit = keyCode - KeyEvent.KEYCODE_0;
    else if (keyCode == KeyEvent.KEYCODE_SPACE)
      digit = 10;
    else
      return super.onKeyDown(keyCode, event);

    SharedPreferences settings =
      PreferenceManager.getDefaultSharedPreferences(this);
    SharedPreferences.Editor editor = settings.edit();
    editor.putInt("debug_digit", digit);
    editor.apply();
    clock.changeSettings(settings);
    return true;
  }

}
