/*
 * MIT License
 *
 * Copyright (c) 2018-2019 Daniel Cortes
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

package danielcortes.xyz.views.components;

import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.text.NumberFormat;
import javax.swing.JTextField;
import org.mariuszgromada.math.mxparser.Expression;

/**
 * Crea un JTextField que formatea automaticamente su texto como un integer el cual se puede obtener
 * con el metodo getValue. Ademas de tener comportamientos especiales: - Al ganar foco se selecciona
 * todo el texto. - Al perder foco formatea el texto como numero. - Evalua la operacion matematica
 * que se ingrese en el campo
 */
public class NumberFormatedTextField extends JTextField {

  private int value;
  private NumberFormat nf;

  /**
   * Crea una instacia del objeto
   */
  public NumberFormatedTextField() {
    super();

    this.nf = NumberFormat.getIntegerInstance();

    this.addFocusListener(new FieldFocusListener());
  }

  /**
   * Llama a readValue por un bug seguramente relacionado con el focus listener: - No actualizaba el
   * valor al momento de hacer requestfocus a otro componente, probablemente porque no alcanza a
   * realizarse la accion antes que ocurra la siguiente
   * <p>
   * Fuerza a que se lea el valor en el textfield antes de retornarlo
   */
  public int getValue() {
    this.readValue();
    return this.value;
  }

  /**
   * Guarda el integer entregado y lo muestra en el campo.
   */
  public void setValue(int value) {
    this.value = value;
    this.setText(nf.format(value));
  }

  /**
   * Lee el valor en el texto, ejecuta la operacion matematica que en caso que exista una y la
   * almacena en el valor Si la operacion matematica es invalida, almacenara un 0
   */
  private void readValue() {
    String currentText = this.getText();
    String stripedDots = currentText.replace(".", "");
    Expression expression = new Expression(stripedDots);

    if (expression.checkSyntax()) {
      this.value = (int) Math.floor(expression.calculate());
    } else {
      this.value = 0;
    }
  }

  /**
   * Formatea el value y lo muestra en el field
   */
  private void formatText() {
    this.setText(nf.format(this.value));
  }

  private class FieldFocusListener implements FocusListener {

    /**
     * Selecciona todo al momento de ganar foco
     */
    @Override
    public void focusGained(FocusEvent e) {
      NumberFormatedTextField.this.select(0, getText().length());
    }

    /**
     * Actualiza el texto y el valor interno al perder el foco
     */
    @Override
    public void focusLost(FocusEvent e) {
      NumberFormatedTextField.this.readValue();
      NumberFormatedTextField.this.formatText();
    }
  }
}
