package org.odk.collect.android.views.colorpickerdialog;

import android.app.Activity;
import android.app.Dialog;
import android.graphics.Color;
import android.os.Bundle;
import android.view.View;
import android.view.Window;
import android.widget.Button;
import android.widget.SeekBar;

import org.odk.collect.android.R;

/**
 * This is the only class of the project. It consists in a custom dialog that shows the GUI
 * used for choosing a color using three sliders or an input field.
 *
 * @author Simone Pessotto
 */
public class ColorPicker extends Dialog implements SeekBar.OnSeekBarChangeListener {

  private final Activity activity;

  private View colorView;
  private SeekBar alphaSeekBar, redSeekBar, greenSeekBar, blueSeekBar;
  private int alpha, red, green, blue;
  private ColorPickerCallback callback;

  private boolean withAlpha;

  /**
   * Creator of the class. It will initialize the class with black color as default
   *
   * @param activity
   *     The reference to the activity where the color picker is called.
   */
  public ColorPicker(Activity activity) {
    super(activity);

    this.activity = activity;

    if (activity instanceof ColorPickerCallback) {
      callback = (ColorPickerCallback) activity;
    }

    this.alpha = 255;
    this.red = 0;
    this.green = 0;
    this.blue = 0;

    this.withAlpha = false;
  }

  /**
   * Creator of the class. It will initialize the class with the rgb color passed as default
   *
   * @param activity
   *     The reference to the activity where the color picker is called
   * @param red
   *     Red color for RGB values (0 - 255)
   * @param green
   *     Green color for RGB values (0 - 255)
   * @param blue
   *     Blue color for RGB values (0 - 255) <p> If the value of the colors it's not in the right range (0 - 255) it
   *     will be place at 0.
   */
  public ColorPicker(Activity activity, int red, int green, int blue) {
    this(activity);

    this.red = ColorFormatHelper.assertColorValueInRange(red);
    this.green = ColorFormatHelper.assertColorValueInRange(green);
    this.blue = ColorFormatHelper.assertColorValueInRange(blue);

  }

  /**
   * Creator of the class. It will initialize the class with the argb color passed as default
   *
   * @param activity
   *     The reference to the activity where the color picker is called
   * @param alpha
   *     Alpha value (0 - 255)
   * @param red
   *     Red color for RGB values (0 - 255)
   * @param green
   *     Green color for RGB values (0 - 255)
   * @param blue
   *     Blue color for RGB values (0 - 255) <p> If the value of the colors it's not in the right range (0 - 255) it
   *     will be place at 0.
   *
   * @since v1.1.0
   */
  public ColorPicker(Activity activity, int alpha, int red, int green, int blue) {
    this(activity);

    this.alpha = ColorFormatHelper.assertColorValueInRange(alpha);
    this.red = ColorFormatHelper.assertColorValueInRange(red);
    this.green = ColorFormatHelper.assertColorValueInRange(green);
    this.blue = ColorFormatHelper.assertColorValueInRange(blue);

    this.withAlpha = true;

  }

  /**
   * @param listener
   *     the listener fired when a color is selected.
   */
  public void setCallback(ColorPickerCallback listener) {
    callback = listener;
  }

  /**
   * Simple onCreate function. Here there is the init of the GUI.
   *
   * @param savedInstanceState
   *     the saved state.
   */
  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    requestWindowFeature(Window.FEATURE_NO_TITLE);
    setContentView(R.layout.color_picker);

    colorView = findViewById(R.id.colorView);
    colorView.setBackgroundColor(getColor());

    alphaSeekBar = (SeekBar) findViewById(R.id.alphaSeekBar);
    redSeekBar = (SeekBar) findViewById(R.id.redSeekBar);
    greenSeekBar = (SeekBar) findViewById(R.id.greenSeekBar);
    blueSeekBar = (SeekBar) findViewById(R.id.blueSeekBar);

    alphaSeekBar.setOnSeekBarChangeListener(this);
    redSeekBar.setOnSeekBarChangeListener(this);
    greenSeekBar.setOnSeekBarChangeListener(this);
    blueSeekBar.setOnSeekBarChangeListener(this);

    alphaSeekBar.setProgress(alpha);
    redSeekBar.setProgress(red);
    greenSeekBar.setProgress(green);
    blueSeekBar.setProgress(blue);

    if (!withAlpha) {
      alphaSeekBar.setVisibility(View.GONE);
    }

    final Button okColor = (Button) findViewById(R.id.okColorButton);
    okColor.setOnClickListener(new View.OnClickListener() {
      @Override
      public void onClick(View view) {
        sendColor();
        dismiss();
      }
    });
  }

  private void sendColor() {
    if (callback != null) {
      callback.onColorChosen(getColor());
    }
  }

  /**
   * Method that synchronizes the color between the bars, the view, and the HEX code text.
   *
   * @param input
   *     HEX Code of the color.
   */
  private void updateColorView(String input) {
    try {
      final int color = Color.parseColor('#' + input);
      alpha = Color.alpha(color);
      red = Color.red(color);
      green = Color.green(color);
      blue = Color.blue(color);

      colorView.setBackgroundColor(getColor());

      alphaSeekBar.setProgress(alpha);
      redSeekBar.setProgress(red);
      greenSeekBar.setProgress(green);
      blueSeekBar.setProgress(blue);
    } catch (IllegalArgumentException ignored) {
    }
  }

  /**
   * Method called when the user change the value of the bars. This sync the colors.
   *
   * @param seekBar
   *     SeekBar that has changed
   * @param progress
   *     The new progress value
   * @param fromUser
   *     Whether the user is the reason for the method call
   */
  @Override
  public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {

    if (seekBar.getId() == R.id.alphaSeekBar) {

      alpha = progress;

    } else if (seekBar.getId() == R.id.redSeekBar) {

      red = progress;

    } else if (seekBar.getId() == R.id.greenSeekBar) {

      green = progress;

    } else if (seekBar.getId() == R.id.blueSeekBar) {

      blue = progress;

    }

    colorView.setBackgroundColor(getColor());

  }

  @Override
  public void onStopTrackingTouch(SeekBar seekBar) {
  }

  @Override
  public void onStartTrackingTouch(SeekBar seekBar) {
  }

  /**
   * Getter for the ALPHA value of the ARGB selected color
   *
   * @return ALPHA Value Integer (0 - 255)
   * @since v1.1.0
   */
  public int getAlpha() {
    return alpha;
  }

  /**
   * Getter for the RED value of the RGB selected color
   *
   * @return RED Value Integer (0 - 255)
   */
  public int getRed() {
    return red;
  }

  /**
   * Getter for the GREEN value of the RGB selected color
   *
   * @return GREEN Value Integer (0 - 255)
   */
  public int getGreen() {
    return green;
  }


  /**
   * Getter for the BLUE value of the RGB selected color
   *
   * @return BLUE Value Integer (0 - 255)
   */
  public int getBlue() {
    return blue;
  }

  /**
   * Getter for the color as Android Color class value.
   * <p>
   * From Android Reference: The Color class defines methods for creating and converting color
   * ints.
   * Colors are represented as packed ints, made up of 4 bytes: alpha, red, green, blue.
   * The values are unpremultiplied, meaning any transparency is stored solely in the alpha
   * component, and not in the color components.
   *
   * @return Selected color as Android Color class value.
   */
  public int getColor() {
    return withAlpha ? Color.argb(alpha, red, green, blue) : Color.rgb(red, green, blue);
  }
}