
package de.ivu.elect.business.gruppe.control;

import java.util.List;

import javax.inject.Inject;
import javax.persistence.NoResultException;

import de.ivu.elect.business.gruppe.boundary.GruppeDAO;
import de.ivu.elect.business.gruppe.entity.AbstractGruppe;
import de.ivu.elect.business.gruppe.entity.Gruppe;
import de.ivu.elect.business.gruppe.entity.PolitischeGruppe;
import de.ivu.elect.business.konfiguration.entity.KonfigurationLoader;
import de.ivu.elect.business.mandant.boundary.MandantDAO;
import de.ivu.elect.business.wahl.boundary.WahlDAO;
import de.ivu.elect.business.wahl.entity.Wahl;


import static java.util.Collections.singletonList;

public class PolitischeGruppeCreate extends AbstractPolitischeGruppeCreate {

  @Inject
  protected transient WahlDAO wahlDAO;

  @Inject
  protected transient GruppeDAO gruppeDAO;

  @Inject
  protected transient PolitischeGruppeSchluesselNormalisierer politischeGruppeSchluesselNormalisierer;

  @Inject
  private transient KonfigurationLoader konfigurationLoader;

  @Inject
  private transient MandantDAO mandantDAO;

  public PolitischeGruppeCreate() {
    super();
  }

  @Override
  public void save(PolitischeGruppe politischeGruppe) {
    save(politischeGruppe.getWahl(), politischeGruppe);
  }

  private void save(Wahl wahlNotAttached, PolitischeGruppe politischeGruppe) {
    Wahl wahl = attach(wahlNotAttached);

    politischeGruppeSchluesselNormalisierer.normalisiere(politischeGruppe, wahl, konfigurationLoader, mandantDAO);

    validate(politischeGruppe);

    politischeGruppe.setWahl(wahl);

    if (politischeGruppe.getRelativePosition() == null && politischeGruppe.getSchluessel() != null) {
      // versuche den Schlüssel als relative Position zu verwenden
      try {
        politischeGruppe.setRelativePosition(Long.parseLong(politischeGruppe.getSchluessel()));
      } catch (NumberFormatException nfe) {
        // egal
      }
    }

    AbstractGruppe.relativePositionSetzenWennNoetig(singletonList(politischeGruppe), getGruppenDerWahl(wahl));

    // default-Werte setzen, falls nicht vorhanden
    if (politischeGruppe.getInPraesentation() == null) {
      politischeGruppe.setInPraesentation(true);
    }
    if (politischeGruppe.getMinderheit() == null) {
      politischeGruppe.setMinderheit(false);
    }
    if (politischeGruppe.getPrivilegiert() == null) {
      politischeGruppe.setPrivilegiert(false);
    }

    if (politischeGruppe.getKurzname() == null) {
      politischeGruppe.setKurzname(politischeGruppe.getSchluessel());
    }
    if (politischeGruppe.getName() == null) {
      politischeGruppe.setName(politischeGruppe.getKurzname());
    }

    super.save(politischeGruppe);
  }

  private List<Gruppe> getGruppenDerWahl(Wahl wahl) {
    if (wahl == null) {
      return gruppeDAO.findByOhneWahl();
    }
    return gruppeDAO.findByWahl(wahl);
  }

  protected void validate(PolitischeGruppe politischeGruppe) {
    assertKeineSystemGruppe(politischeGruppe);
    assertUnique(politischeGruppe);
  }

  private void assertKeineSystemGruppe(PolitischeGruppe politischeGruppe) {
    if (politischeGruppe.isSystemGruppe()) {
      throw new IllegalStateException("Eine politische Gruppe [gruppe = <" + politischeGruppe + ">] darf keine System-Gruppe sein");
    }
  }

  private void assertUnique(PolitischeGruppe politischeGruppe) {
    if (politischeGruppe.getWahl() == null) {
      try {
        PolitischeGruppe inDb = dao.findByOhneWahlAndSchluessel(politischeGruppe.getSchluessel());
        if (inDb == null) {
          return;
        }
        throwNotValidException(politischeGruppe);
      } catch (NoResultException e) {
        return;
      }
    }
    if (dao.isEntityWithUKPresent(politischeGruppe.getPolitischeGruppeUK())) {
      throwNotValidException(politischeGruppe);
    }
  }

  private void throwNotValidException(PolitischeGruppe politischeGruppe) {
    throw new IllegalStateException("Eine Politische Gruppe mit <" + politischeGruppe
        .getPolitischeGruppeUK() + "> kann nicht angelegt werden, da eine solche politische Gruppe bereits existiert.");
  }

  private Wahl attach(Wahl wahl) {
    return wahlDAO.attach(wahl);
  }
}
