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

import java.io.Serializable;
import java.util.Collections;
import java.util.List;

import javax.annotation.Nullable;

import java.util.function.Function;

import de.ivu.elect.business.gruppeimgebiet.entity.GruppeImGebietTK;
import de.ivu.elect.jee.entity.tk.EntityFieldValue;
import de.ivu.elect.jee.entity.tk.EntityTK;
import de.ivu.elect.jee.faces.Messages;

/**
 * Der fachliche Schluessel von Kadidaturen lässt sich nicht einfach in Takatuka definieren. Daher hier per Hand:
 * <p/>
 * <ul>
 * <li>Art der Kandidatur (Direkt, Liste, Ersatz)</li>
 * <li>GruppeImGebietTK</li>
 * <li>Listenposition (Im Falle einer Liste)</li>
 * <li>übergeordneter KandidaturExtendedTK (im Falle einer Ersatzkandidatur)</li>
 * </ul>
 */
public class KandidaturExtendedTK implements EntityTK, Serializable {

  private static final long serialVersionUID = 1L;

  public static final Function<Kandidatur, Long> LISTENKANDIDATUR_RELATIVE_POSITION = new Function<Kandidatur, Long>() {

    @Nullable
    @Override
    public Long apply(@Nullable Kandidatur input) {
      if (input != null && input.isListenkandidatur()) {
        return input.castTo(Listenkandidatur.class).getEntity().getRelativePosition();
      }

      return null;
    }
  };

  public static final Function<Kandidatur, Long> LISTENKANDIDATUR_VORGEGEBENE_POSITION = new Function<Kandidatur, Long>() {

    @Nullable
    @Override
    public Long apply(@Nullable Kandidatur input) {
      if (input != null && input.isListenkandidatur()) {
        return input.castTo(Listenkandidatur.class).getEntity().getVorgegebenePosition();
      }

      return null;
    }
  };

  public static final Function<Kandidatur, Long> LISTENKANDIDATUR_EINGEREICHTE_POSITION = new Function<Kandidatur, Long>() {

    @Nullable
    @Override
    public Long apply(@Nullable Kandidatur input) {
      if (input != null && input.isListenkandidatur()) {
        return input.castTo(Listenkandidatur.class).getEntity().getEingereichtePosition();
      }

      return null;
    }
  };

  private final KandidaturArt kandidaturArt;

  private final GruppeImGebietTK gruppeImGebietTK;

  private final Long listenposition;

  private final KandidaturExtendedTK uebergeordneteKandidatur;

  public KandidaturExtendedTK(Kandidatur kandidatur) {
    this(kandidatur, LISTENKANDIDATUR_RELATIVE_POSITION);
  }

  /**
   * HINT (zulassungPruefer): Bei Angabe eines Prüfers wird die Stimmzettelposition verwendet, sonst die relative
   * Position. Nicht beide vermischen!!
   */
  public KandidaturExtendedTK(Kandidatur kandidatur, Function<Kandidatur, Long> kandidaturToListenpositionFunction) {
    this.kandidaturArt = kandidatur.getKandidaturArt();
    this.gruppeImGebietTK = kandidatur.getGruppeImGebiet().getGruppeImGebietTK();
    if (kandidatur.isListenkandidatur()) {
      listenposition = kandidaturToListenpositionFunction.apply(kandidatur);
    } else {
      listenposition = null;
    }
    if (kandidatur.isErsatzkandidatur()) {
      uebergeordneteKandidatur = kandidatur.castTo(Ersatzkandidatur.class).getEntity().getUebergeordneteKandidatur()
          .getKandidaturExtendedTK();
    } else {
      uebergeordneteKandidatur = null;
    }
  }

  @Override
  public int hashCode() {
    final int prime = 31;
    int result = 1;
    result = prime * result + (gruppeImGebietTK == null ? 0 : gruppeImGebietTK.hashCode());
    result = prime * result + (kandidaturArt == null ? 0 : kandidaturArt.hashCode());
    result = prime * result + (listenposition == null ? 0 : listenposition.hashCode());
    result = prime * result + (uebergeordneteKandidatur == null ? 0 : uebergeordneteKandidatur.hashCode());
    return result;
  }

  @Override
  public boolean equals(Object obj) {
    if (this == obj) {
      return true;
    }
    if (obj == null) {
      return false;
    }
    if (getClass() != obj.getClass()) {
      return false;
    }
    KandidaturExtendedTK other = (KandidaturExtendedTK) obj;
    if (gruppeImGebietTK == null) {
      if (other.gruppeImGebietTK != null) {
        return false;
      }
    } else if (!gruppeImGebietTK.equals(other.gruppeImGebietTK)) {
      return false;
    }
    if (kandidaturArt != other.kandidaturArt) {
      return false;
    }
    if (listenposition == null) {
      if (other.listenposition != null) {
        return false;
      }
    } else if (!listenposition.equals(other.listenposition)) {
      return false;
    }
    if (uebergeordneteKandidatur == null) {
      if (other.uebergeordneteKandidatur != null) {
        return false;
      }
    } else if (!uebergeordneteKandidatur.equals(other.uebergeordneteKandidatur)) {
      return false;
    }
    return true;
  }

  private static final Function<Kandidatur, KandidaturExtendedTK> TO_TK = new Function<Kandidatur, KandidaturExtendedTK>() {

    @Override
    public KandidaturExtendedTK apply(Kandidatur value) {
      return new KandidaturExtendedTK(value);
    }
  };

  public static Function<Kandidatur, KandidaturExtendedTK> getKandidaturToTKFunction() {
    return TO_TK;
  }

  @Override
  public String getEntityMessageKey() {
    return KandidaturConstants.MESSAGE_KEY_ENTITY_EINZAHL;
  }

  @Override
  public List<EntityFieldValue> getAllEntityFieldValues() {
    return Collections.emptyList();
  }

  @Override
  public List<EntityFieldValue> getEntityFieldValuesForEntity() {
    return Collections.emptyList();
  }

  @Override
  public String toString() {
    return "KandidaturExtendedTK [kandidaturArt=" + kandidaturArt + ", gruppeImGebietTK=" + gruppeImGebietTK
        + ", listenposition=" + listenposition + ", uebergeordneteKandidatur=" + uebergeordneteKandidatur + "]";
  }

  @Override
  public String toStringLokalisiert(Messages messages) {
    return getEntityMessageKey() + " [Kandidaturart=" + kandidaturArt + ", "
        + gruppeImGebietTK.toStringLokalisiert(messages) + ", "
        + messages.getMessageForMessageKey(ListenkandidaturConstants.MESSAGE_KEY_RELATIVE_POSITION_EINZAHL) + "="
        + listenposition + ", Übergeordnete Kandidatur=" + uebergeordneteKandidatur + "]";
  }
}
