
package de.ivu.elect.business.wahl.entity;

import java.util.Calendar;
import java.util.Comparator;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.List;
import java.util.stream.Collectors;

import javax.annotation.Nullable;
import javax.persistence.NoResultException;
import javax.persistence.NonUniqueResultException;
import javax.persistence.Transient;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import de.ivu.elect.business.gebietsbaum.boundary.WurzelgebietNotUniqueEvent;
import de.ivu.elect.business.gebietsbaum.control.EntityMitWurzelgebiet;
import de.ivu.elect.business.gebietsbaum.control.EntityMitWurzelgebietDAO;
import de.ivu.elect.business.gebietsbaum.entity.Gebiet;
import de.ivu.elect.business.mandant.entity.EntityMitMandant;
import de.ivu.elect.business.wahl.control.WahlByPositionComparator;
import de.ivu.elect.jee.cdi.BeanManagerUtil;
import de.ivu.elect.jee.faces.FacesMessageUtil;

public abstract class AbstractWahltermin implements WahlterminBase, EntityMitWurzelgebiet, WahlOderWahltermin {
  private static final Logger LOG = LoggerFactory.getLogger(AbstractWahltermin.class);

  private static final long serialVersionUID = 1L;

  private static final Comparator<Wahl> WAHL_BY_POSITION_COMPARATOR = new WahlByPositionComparator();

  public AbstractWahltermin() {
    super();
  }

  @Override
  public int getWahljahr() {
    Calendar calendar = new GregorianCalendar();
    calendar.setTime(getWahldatum());

    return calendar.get(Calendar.YEAR);
  }

  @Override
  public String getWahlterminNummer() {
    return getNummer();
  }

  @Override
  @Nullable
  public Gebiet getWurzelgebiet(EntityMitWurzelgebietDAO entityMitWurzelgebietDAO) {
    try {
      return entityMitWurzelgebietDAO.getWahlterminFct().apply((Wahltermin) this);
    } catch (NoResultException ignored) {
      return null;
    } catch (NonUniqueResultException e) {
      try {
        BeanManagerUtil.getBeanByClass(WurzelgebietNotUniqueEvent.class).fire(getPk());
      } catch (Exception ex) {
        LOG.warn("Fehler bei Wurzelgebietreperaturaufruf: " + ex.getMessage(), ex);
        FacesMessageUtil.addErrorMessage("mehr.als.ein.wurzelgebiet.vorhanden");
      }
      return null;
    }
  }

  public Date calculateStichtagVormWahltag(int anzahlTageVormWahltag) {
    return WahlterminStichtagCalculator.calculateTagVormWahltagByAnzahlTage((Wahltermin) this, anzahlTageVormWahltag);
  }

  public boolean isStichwahlMoeglich() {
    return Boolean.TRUE.equals(getStichwahlMoeglich());
  }

  public boolean isStichwahltermin() {
    return getStichwahlWahlterminUrspruenglich() != null;
  }

  // Nur für WOS(!)
  public boolean isWahlhelferdatenbank() {
    return "Wahlhelferdatenbank".equals(getName());
  }

  @Override
  public String getEinsehenRolleMessageKey() {
    return WahlterminConstants.MESSAGE_KEY_EINSEHEN_ID_EINZAHL;
  }

  public List<Wahl> getWahlenSortiertNachPosition() {
    return getWahlsByWahltermin().stream().sorted(WAHL_BY_POSITION_COMPARATOR).collect(Collectors.toList());
  }

  @Override
  public boolean isInstanceOfWahl() {
    return false;
  }

  @Override
  public boolean isInstanceOfWahltermin() {
    return true;
  }

  @Override
  public EntityMitMandant getParent() {
    return getMandant();
  }

  /**
   * Identifikation des nicht festgelegten Wahldatums ist der 01.01. des Wahljahrs (WASDE-1904)
   */
  @Override
  public boolean isWahldatumNichtFestgelegt() {
    Calendar calendar = new GregorianCalendar();
    calendar.setTime(getWahldatum());
    return calendar.get(Calendar.DAY_OF_YEAR) == 1;
  }

  @Transient
  private transient WahlterminCreateDokumenteUebernehmen wahlterminCreateDokumenteUebernehmen;

  public WahlterminCreateDokumenteUebernehmen getWahlterminCreateDokumenteUebernehmen() {
    if (wahlterminCreateDokumenteUebernehmen == null) {
      return WahlterminCreateDokumenteUebernehmen.NICHT_UBERNEHMEN;
    }
    return wahlterminCreateDokumenteUebernehmen;
  }

  public void setWahlterminCreateDokumenteUebernehmen(WahlterminCreateDokumenteUebernehmen wahlterminCreateDokumenteUebernehmen) {
    this.wahlterminCreateDokumenteUebernehmen = wahlterminCreateDokumenteUebernehmen;
  }
}
