
package de.ivu.elect.presentation.personenpruefung.form;

import static org.apache.commons.lang3.StringUtils.isNotBlank;

import java.text.DateFormat;
import java.util.Date;
import java.util.Locale;

import de.ivu.elect.business.person.entity.Personendaten;
import de.ivu.elect.business.person.entity.PersonendatenConstants;
import de.ivu.elect.business.person.entity.Wahlrechtsausschluss;
import de.ivu.elect.business.personenpruefung.control.wahlrecht.AbstractPersonendatenWahlrechtMatcher;
import de.ivu.elect.business.personenpruefung.control.wahlrecht.WahlrechtAnschriftsart;
import de.ivu.elect.business.personenpruefung.control.wahlrecht.WahlrechtGebietsart;
import de.ivu.elect.business.personenpruefung.control.wahlrecht.WahlrechtPersonenregisterAbgleichbarkeit;
import de.ivu.elect.business.personenpruefung.control.wahlrecht.WahlrechtPflichtangabe;
import de.ivu.elect.business.personenpruefung.control.wahlrecht.WahlrechtStaatsangehoerigkeit;
import de.ivu.elect.business.staat.entity.StaatConstants;
import de.ivu.elect.business.wahl.entity.WahlterminConstants;

public class PersonenWahlrechtPruefSchrittErgebnisProperties {

  private final AbstractPersonendatenWahlrechtMatcher matcher;

  private final Personendaten personendaten;

  public PersonenWahlrechtPruefSchrittErgebnisProperties(AbstractPersonendatenWahlrechtMatcher matcher, Personendaten personendaten) {
    super();

    this.matcher = matcher;
    this.personendaten = personendaten;
  }

  public PflichtangabeProperty getPflichtangabeProperty(WahlrechtPflichtangabe pflichtangabe) {
    return new PflichtangabeProperty(personendaten, matcher, pflichtangabe);
  }

  public MindestalterAmStichtagProperty getMindestalterAmStichtagProperty(Date stichtag, Integer mindestalter) {
    return new MindestalterAmStichtagProperty(personendaten, matcher, stichtag, mindestalter);
  }

  public HoechstalterAmStichtagProperty getHoechstalterAmStichtagProperty(Date stichtag, Integer hoechstalter) {
    return new HoechstalterAmStichtagProperty(personendaten, matcher, stichtag, hoechstalter);
  }

  public StaatsangehoerigkeitProperty getStaatsangehoerigkeitProperty(Locale staatsangehoerigkeit) {
    return new StaatsangehoerigkeitProperty(personendaten, matcher, staatsangehoerigkeit);
  }

  public StaatsangehoerigkeitZugelassenProperty getStaatsangehoerigkeitZugelassenProperty(WahlrechtStaatsangehoerigkeit wahlrechtStaatsangehoerigkeit) {
    return new StaatsangehoerigkeitZugelassenProperty(personendaten, matcher, wahlrechtStaatsangehoerigkeit);
  }

  public WahlrechtsausschlussProperty getWahlrechtsausschlussProperty(Wahlrechtsausschluss wahlrechtsausschluss) {
    return new WahlrechtsausschlussProperty(personendaten, matcher, wahlrechtsausschluss);
  }

  public PersonenregisterAbgleichbarkeitProperty getPersonenregisterAbgleichbarkeitProperty(WahlrechtPersonenregisterAbgleichbarkeit personenregisterAbgleichbarkeit) {
    return new PersonenregisterAbgleichbarkeitProperty(personendaten, matcher, personenregisterAbgleichbarkeit);
  }

  public static final class PflichtangabeProperty extends AbstractPruefSchrittErgebnisStringProperty<AbstractPersonendatenWahlrechtMatcher> {

    private final WahlrechtPflichtangabe pflichtangabe;

    public PflichtangabeProperty(Personendaten personendaten, AbstractPersonendatenWahlrechtMatcher matcher, WahlrechtPflichtangabe pflichtangabe) {
      super(personendaten, matcher);

      this.pflichtangabe = pflichtangabe;
    }

    public WahlrechtPflichtangabe getPflichtangabe() {
      return pflichtangabe;
    }

    @Override
    public String getDefaultLabel() {
      return getMessage("PflichtangabeKriterium.label");
    }

    @Override
    public String getValue() {
      return getPflichtangabe().getLabel(getMessages());
    }
  }

  public MindestaufenthaltAnAnchriftArtInGebietAmStichtagProperty getMindestaufenthaltAnAnschriftArtInGebietAmStichtagProperty(Date stichtag, WahlrechtAnschriftsart anschriftsart,
      WahlrechtGebietsart gebietsart, Integer mindestaufenthalt) {
    return new MindestaufenthaltAnAnchriftArtInGebietAmStichtagProperty(personendaten, matcher, stichtag, anschriftsart, gebietsart, mindestaufenthalt);
  }

  public static final class MindestalterAmStichtagProperty extends AbstractAlterAmStichtagProperty {

    private static final String PROPERTY_MSG_KEY_PREFIX = "MindestalterAmStichtagProperty.";

    public MindestalterAmStichtagProperty(Personendaten personendaten, AbstractPersonendatenWahlrechtMatcher matcher, Date stichtag, Integer mindestalter) {
      super(personendaten, matcher, stichtag, mindestalter);
    }

    @Override
    protected String getLabelMessageKey() {
      return PROPERTY_MSG_KEY_PREFIX + "label";
    }
  }

  public static final class HoechstalterAmStichtagProperty extends AbstractAlterAmStichtagProperty {

    private static final String PROPERTY_MSG_KEY_PREFIX = "HoechstalterAmStichtagProperty.";

    public HoechstalterAmStichtagProperty(Personendaten personendaten, AbstractPersonendatenWahlrechtMatcher matcher, Date stichtag, Integer hoechstalter) {
      super(personendaten, matcher, stichtag, hoechstalter);
    }

    @Override
    protected String getLabelMessageKey() {
      return PROPERTY_MSG_KEY_PREFIX + "label";
    }
  }

  public static final class StaatsangehoerigkeitProperty extends AbstractPruefSchrittErgebnisStringProperty<AbstractPersonendatenWahlrechtMatcher> {

    private final Locale staatsangehoerigkeit;

    public StaatsangehoerigkeitProperty(Personendaten personendaten, AbstractPersonendatenWahlrechtMatcher matcher, Locale staatsangehoerigkeit) {
      super(personendaten, matcher);

      this.staatsangehoerigkeit = staatsangehoerigkeit;
    }

    public Locale getStaatsangehoerigkeit() {
      return staatsangehoerigkeit;
    }

    public String getStaatsangehoerigkeitFormatted() {
      return getStaatsangehoerigkeit().getDisplayLanguage(getLocale());
    }

    @Override
    public String getDefaultLabel() {
      return getMessage(StaatConstants.MESSAGE_KEY_NAME_STAATSANGEHOERIGKEIT_EINZAHL);
    }

    @Override
    public String getValue() {
      return getStaatsangehoerigkeitFormatted();
    }
  }

  public static final class StaatsangehoerigkeitZugelassenProperty extends AbstractPruefSchrittErgebnisStringProperty<AbstractPersonendatenWahlrechtMatcher> {

    private final WahlrechtStaatsangehoerigkeit wahlrechtStaatsangehoerigkeit;

    public StaatsangehoerigkeitZugelassenProperty(Personendaten personendaten, AbstractPersonendatenWahlrechtMatcher matcher, WahlrechtStaatsangehoerigkeit wahlrechtStaatsangehoerigkeit) {
      super(personendaten, matcher);

      this.wahlrechtStaatsangehoerigkeit = wahlrechtStaatsangehoerigkeit;
    }

    private WahlrechtStaatsangehoerigkeit getWahlrechtStaatsangehoerigkeit() {
      return wahlrechtStaatsangehoerigkeit;
    }

    @Override
    public String getDefaultLabel() {
      if (WahlrechtStaatsangehoerigkeit.DEUTSCH.equals(getWahlrechtStaatsangehoerigkeit())) {
        return getMessage(WahlterminConstants.MESSAGE_KEY_BUERGER_ZUGELASSEN_EINZAHL);
      }

      return getMessage(WahlterminConstants.MESSAGE_KEY_BUERGER_ZUGELASSEN_MEHRZAHL);
    }

    @Override
    public String getValue() {
      if (getWahlrechtStaatsangehoerigkeit() != null) {
        return getMessage(getWahlrechtStaatsangehoerigkeit());
      }

      return "";
    }
  }

  public static final class WahlrechtsausschlussProperty extends AbstractPruefSchrittErgebnisStringProperty<AbstractPersonendatenWahlrechtMatcher> {

    private final Wahlrechtsausschluss wahlrechtsausschluss;

    public WahlrechtsausschlussProperty(Personendaten personendaten, AbstractPersonendatenWahlrechtMatcher matcher, Wahlrechtsausschluss wahlrechtsausschluss) {
      super(personendaten, matcher);

      this.wahlrechtsausschluss = wahlrechtsausschluss;
    }

    public Wahlrechtsausschluss getWahlrechtsausschluss() {
      return wahlrechtsausschluss;
    }

    @Override
    public String getDefaultLabel() {
      return getMessage(PersonendatenConstants.MESSAGE_KEY_WAHLRECHTSAUSSCHLUSS_EINZAHL);
    }

    @Override
    public String getValue() {
      return getMessage(getWahlrechtsausschluss());
    }
  }

  public static final class PersonenregisterAbgleichbarkeitProperty extends AbstractPruefSchrittErgebnisStringProperty<AbstractPersonendatenWahlrechtMatcher> {

    private final WahlrechtPersonenregisterAbgleichbarkeit personenregisterAbgleichbarkeit;

    public PersonenregisterAbgleichbarkeitProperty(Personendaten personendaten, AbstractPersonendatenWahlrechtMatcher matcher,
        WahlrechtPersonenregisterAbgleichbarkeit personenregisterAbgleichbarkeit) {
      super(personendaten, matcher);

      this.personenregisterAbgleichbarkeit = personenregisterAbgleichbarkeit;
    }

    public WahlrechtPersonenregisterAbgleichbarkeit getPersonenregisterAbgleichbarkeit() {
      return personenregisterAbgleichbarkeit;
    }

    @Override
    public String getDefaultLabel() {
      return getMessage(PersonendatenConstants.MESSAGE_KEY_AUSWAERTIG_EINZAHL);
    }

    @Override
    public String getValue() {
      return getMessage(getPersonenregisterAbgleichbarkeit());
    }
  }

  public static final class MindestaufenthaltAnAnchriftArtInGebietAmStichtagProperty extends AbstractPruefSchrittErgebnisStringProperty<AbstractPersonendatenWahlrechtMatcher> {

    private static final String PROPERTY_MSG_KEY_PREFIX = "MindestaufenthaltAnAnschriftArtInGebietAmStichtagProperty.";

    private final Date stichtag;

    private final WahlrechtAnschriftsart anschriftsart;

    private final WahlrechtGebietsart gebietsart;

    private final Integer mindestaufenthalt;

    public MindestaufenthaltAnAnchriftArtInGebietAmStichtagProperty(Personendaten personendaten, AbstractPersonendatenWahlrechtMatcher matcher, Date stichtag, WahlrechtAnschriftsart anschriftsart,
        WahlrechtGebietsart gebietsart, Integer mindestaufenthalt) {
      super(personendaten, matcher);

      this.stichtag = stichtag;
      this.anschriftsart = anschriftsart;
      this.gebietsart = gebietsart;
      this.mindestaufenthalt = mindestaufenthalt;
    }

    public Date getStichtag() {
      return stichtag;
    }

    public String getStichtagFormatted() {
      if (getPersonendaten().getWahldatum().equals(getStichtag())) {
        return getMessage(WahlterminConstants.MESSAGE_KEY_ENTITY_EINZAHL);
      }

      return DateFormat.getDateInstance(DateFormat.MEDIUM, getLocale()).format(getStichtag());
    }

    private boolean isNurAnschriftart() {
      return getGebietsart().isIgnored() && getMindestaufenthalt() <= 0;
    }

    public WahlrechtAnschriftsart getAnschriftsart() {
      return anschriftsart;
    }

    public String getAnschriftsartFormatted() {
      if (WahlrechtAnschriftsart.ALLE.equals(anschriftsart)) {
        return "";
      }

      return getMessage(getAnschriftsart());
    }

    public WahlrechtGebietsart getGebietsart() {
      return gebietsart;
    }

    public String getGebietsartFormatted() {
      return getMessage(getGebietsart());
    }

    public Integer getMindestaufenthalt() {
      return mindestaufenthalt;
    }

    @Override
    public String getDefaultLabel() {
      String msgKeyPrefix = PROPERTY_MSG_KEY_PREFIX + "label.";

      if (isNurAnschriftart()) {
        return getMessage(msgKeyPrefix + "NUR_ANSCHRIFT_ART");
      }

      String anschriftsartFormatted = getAnschriftsartFormatted();

      if (isNotBlank(anschriftsartFormatted)) {
        anschriftsartFormatted = "(" + anschriftsartFormatted + ")";
      }

      return getMessage(msgKeyPrefix + getGebietsart().name(), getStichtagFormatted(), anschriftsartFormatted, getGebietsartFormatted());
    }

    @Override
    public String getValue() {
      if (isNurAnschriftart()) {
        return getAnschriftsartFormatted();
      }

      return getMessage(PROPERTY_MSG_KEY_PREFIX + "value", getMindestaufenthalt());
    }
  }

  private abstract static class AbstractAlterAmStichtagProperty extends AbstractPruefSchrittErgebnisStringProperty<AbstractPersonendatenWahlrechtMatcher> {

    private final Date stichtag;

    private final Integer alter;

    public AbstractAlterAmStichtagProperty(Personendaten personendaten, AbstractPersonendatenWahlrechtMatcher matcher, Date stichtag, Integer alter) {
      super(personendaten, matcher);

      this.stichtag = stichtag;
      this.alter = alter;
    }

    public Date getStichtag() {
      return stichtag;
    }

    public String getStichtagFormatted() {
      if (getPersonendaten().getWahldatum().equals(getStichtag())) {
        return getMessage(WahlterminConstants.MESSAGE_KEY_ENTITY_EINZAHL);
      }

      return DateFormat.getDateInstance(DateFormat.MEDIUM, getLocale()).format(getStichtag());
    }

    public Integer getAlter() {
      return alter;
    }

    @Override
    public String getDefaultLabel() {
      return getMessage(getLabelMessageKey(), getStichtagFormatted());
    }

    protected abstract String getLabelMessageKey();

    @Override
    public String getValue() {
      return String.valueOf(getAlter());
    }
  }
}
