/*
 * 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.controllers;

import danielcortes.xyz.data.DAOManager;
import danielcortes.xyz.models.caja.Caja;
import danielcortes.xyz.models.documentos.Documentos;
import danielcortes.xyz.models.efectivo.Efectivo;
import danielcortes.xyz.views.ArqueoView;
import danielcortes.xyz.views.CalcularFondoView;
import danielcortes.xyz.views.components.NumberFormatedTextField;
import java.awt.Color;
import javax.swing.KeyStroke;

/**
 * Controlador destinado a la vista ArqueoView Maneja su contenido y las acciones que esta realiza.
 */
public class ArqueoController extends BaseController {

  private ArqueoView view;
  private Caja caja;
  private Efectivo efectivo;
  private Documentos documentos;

  /**
   * Crea el controlador y ejecuta el metodo que genera los eventos para su vista.
   */
  public ArqueoController(ArqueoView view) {
    this.view = view;
    this.setUpViewEvents();
  }

  /**
   * Actualiza los campos de documentos, efectivo y resumen con los datos de la caja.
   *
   * @param caja Caja para la cual se seleccionaran los datos a mostrar
   */
  public void updateCaja(Caja caja) {
    this.caja = caja;
    this.fillDocumentos();
    this.fillEfectivo();
    this.fillResumen();
  }

  /**
   * Acceso publico para rellenar el resumen
   */
  public void updateResumen() {
    this.fillResumen();
  }

  /**
   * Rellena los campos del efectivo con la instancia de efectivo que pertenece a la caja
   */
  private void fillEfectivo() {
    this.efectivo = DAOManager.getEfectivoDAO().getByCaja(this.caja).orElse(Efectivo.EMPTY);
    this.view.getVeinteMilField().setValue(efectivo.getVeinteMil());
    this.view.getDiezMilField().setValue(efectivo.getDiezMil());
    this.view.getCincoMilField().setValue(efectivo.getCincoMil());
    this.view.getDosMilField().setValue(efectivo.getDosMil());
    this.view.getMilField().setValue(efectivo.getMil());
    this.view.getQuinientosField().setValue(efectivo.getQuinientos());
    this.view.getCienField().setValue(efectivo.getCien());
    this.view.getCincuentaField().setValue(efectivo.getCincuenta());
    this.view.getDiezField().setValue(efectivo.getDiez());
  }

  /**
   * Rellea los campos de documentos con la instancia de documentos que pertenece a la caja
   */
  private void fillDocumentos() {
    this.documentos = DAOManager.getDocumentosDAO().getByCaja(caja).orElse(Documentos.EMPTY);
    this.view.getTarjetasField().setValue(documentos.getTarjetas());
    this.view.getChequesField().setValue(documentos.getCheques());
    this.view.getRetiroField().setValue(documentos.getRetiros());
  }

  /**
   * Llama a todos los metodos que llenan y calculan los campos de resumen
   */
  private void fillResumen() {
    this.updateResumenEfectivo();
    this.updateResumenDocumentos();
    this.updateResumenEgresos();
    this.updateResumenArqueo();
  }

  /**
   * Calcula el total de efectivo y lo muestra en el efectivoField
   */
  private void updateResumenEfectivo() {
    NumberFormatedTextField efectivoField = this.view.getEfectivoField();
    int total = DAOManager.getEfectivoDAO().getTotalEfectivo(this.caja);
    efectivoField.setValue(total);
  }

  /**
   * Calcula el total de documentos y lo muestra en el documentosField
   */
  private void updateResumenDocumentos() {
    NumberFormatedTextField documentosField = this.view.getDocumentosField();
    int total = DAOManager.getDocumentosDAO().getTotalDocumentos(this.caja);
    documentosField.setValue(total);
  }

  /**
   * Obtiene el total de egresos y lo muestra en el campo de egresosField
   */
  private void updateResumenEgresos() {
    int total = DAOManager.getEgresoDAO().getTotalEgreso(this.caja);
    this.view.getEgresosField().setValue(total);
  }

  /**
   * Calcula los datos de arqueo, rendido y ajuste y los muestra en sus campos correspondientes
   */
  private void updateResumenArqueo() {
    int totalEfectivo = DAOManager.getEfectivoDAO().getTotalEfectivo(this.caja);
    int totalDocumentos = DAOManager.getDocumentosDAO().getTotalDocumentos(this.caja);
    int totalEgresos = DAOManager.getEgresoDAO().getTotalEgreso(this.caja);
    int totalIngresos = DAOManager.getIngresoDAO().getTotalIngreso(this.caja);

    int rendido = totalDocumentos + totalEfectivo + totalEgresos;
    int diferencia = rendido - totalIngresos;

    this.view.getRendidoField().setValue(rendido);
    this.view.getDebeRendirField().setValue(totalIngresos);
    this.view.getDiferenciaField().setValue(diferencia);

    if (diferencia < 0) {
      this.view.getDiferenciaField().setForeground(new Color(255, 0, 0));
    } else {
      this.view.getDiferenciaField().setForeground(new Color(0, 0, 0));
    }

  }

  /**
   * Setea los eventos de los fields de la vista
   */
  private void setUpViewEvents() {
    moveTo(this.view.getVeinteMilField(), this.view.getDiezMilField());
    moveTo(this.view.getDiezMilField(), this.view.getCincoMilField());
    moveTo(this.view.getCincoMilField(), this.view.getDosMilField());
    moveTo(this.view.getDosMilField(), this.view.getMilField());
    moveTo(this.view.getMilField(), this.view.getQuinientosField());
    moveTo(this.view.getQuinientosField(), this.view.getCienField());
    moveTo(this.view.getCienField(), this.view.getCincuentaField());
    moveTo(this.view.getCincuentaField(), this.view.getDiezField());
    doAction(this.view.getDiezField(), "save", KeyStroke.getKeyStroke("ENTER"),
        e -> this.guardarEfectivoActionListener());
    moveTo(this.view.getChequesField(), this.view.getTarjetasField());
    moveTo(this.view.getTarjetasField(), this.view.getRetiroField());
    doAction(this.view.getRetiroField(), "save", KeyStroke.getKeyStroke("ENTER"),
        e -> this.guardarDocumentosActionListener());

    this.view.getGuardarEfectivoButton()
        .addActionListener(e -> this.guardarEfectivoActionListener());
    this.view.getGuardarDocumentosButton()
        .addActionListener(e -> this.guardarDocumentosActionListener());
    this.view.getCalcularFondoButton().addActionListener(e -> this.calcularFondoActionListener());
  }

  /**
   * Llama a los metodos necesarios para guardar los campos de efectivo Primero llama a normalizar
   * el input, luego a esconder los mensajes de error, para finalmente llamar a guardar el efectivo
   */
  private void guardarEfectivoActionListener() {
    this.view.getGuardarEfectivoButton().requestFocus();
    this.guardarEfectivo();
  }

  /**
   * Llama a los metodos necesarios para guardar los documentos Primero llama a normalizar el input,
   * luego a esconder los mensajes de error y finalmente a guardar los documentos
   */
  private void guardarDocumentosActionListener() {
    this.view.getGuardarDocumentosButton().requestFocus();
    this.guardarDocumentos();
  }

  /**
   * Lanza la ventana en la que se puede calcular el fondo de la caja.
   */
  private void calcularFondoActionListener() {
    CalcularFondoView view = new CalcularFondoView();
    CalcularFondoController controller = new CalcularFondoController(view, this.caja);
    launchFrame(view.getContentPanel(), "Calcular Fondo");
  }

  /**
   * Guarda los datos del detalle de efectivo solo despues de que los campos sean validados, luego
   * de guardar llama a updateResumenEfectivo y updateResumenArqueo para actualizar los datos en
   * efectivoField y arqueoField
   */
  private void guardarEfectivo() {
    int diez = this.view.getDiezField().getValue();
    int cincuenta = this.view.getCincuentaField().getValue();
    int cien = this.view.getCienField().getValue();
    int quinientos = this.view.getQuinientosField().getValue();
    int mil = this.view.getMilField().getValue();
    int dosMil = this.view.getDosMilField().getValue();
    int cincoMil = this.view.getCincoMilField().getValue();
    int diezMil = this.view.getDiezMilField().getValue();
    int veinteMil = this.view.getVeinteMilField().getValue();

    this.efectivo.setDiez(diez);
    this.efectivo.setCincuenta(cincuenta);
    this.efectivo.setCien(cien);
    this.efectivo.setQuinientos(quinientos);
    this.efectivo.setMil(mil);
    this.efectivo.setDosMil(dosMil);
    this.efectivo.setCincoMil(cincoMil);
    this.efectivo.setDiezMil(diezMil);
    this.efectivo.setVeinteMil(veinteMil);
    DAOManager.getEfectivoDAO().update(efectivo);

    this.updateResumenEfectivo();
    this.updateResumenArqueo();
  }

  /**
   * Guarda los datos del detalle de documentos solo despues de que los campos sean validados, luego
   * de guardar llama a updateResumenDocumentos y updateResumenArqueo para actualizar los datos de
   * documentosField y arqueoField
   */
  private void guardarDocumentos() {
    int tarjetas = this.view.getTarjetasField().getValue();
    int cheques = this.view.getChequesField().getValue();
    int retiros = this.view.getRetiroField().getValue();

    this.documentos.setTarjetas(tarjetas);
    this.documentos.setCheques(cheques);
    this.documentos.setRetiros(retiros);
    DAOManager.getDocumentosDAO().update(documentos);

    this.updateResumenDocumentos();
    this.updateResumenArqueo();
  }

}
