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

import java.security.PublicKey;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;

import javax.annotation.Nullable;

import org.apache.commons.lang3.StringUtils;

import de.ivu.elect.business.security.control.NlKeyGeneratorConfig;
import de.ivu.elect.encrypt.Base64KeyConverter;
import de.ivu.elect.jee.entity.customdata.DefaultCustomData;
import de.ivu.elect.jee.protokollierung.AttributTyp;
import de.ivu.elect.nl.x509.NlX509Metadata;


import static java.util.Arrays.asList;
import static java.util.Collections.emptyList;
import static org.apache.commons.lang3.StringUtils.isNotBlank;

public class NlGebietCustomData extends DefaultCustomData {

  private static final long serialVersionUID = 1L;

  private NlX509Metadata nlX509Metadata;

  private String publicKey;

  private Map<String, HashSet<String>> protokollEintraegePerKey; // ELECTVAPP-387

  private List<NlGebietSchluessel> uebergeordneteGebieteInMasterElectionTree;

  private Long voteValue;

  private boolean frysianExportAllowed;

  private boolean romanNumerals; // ELECT-13586

  private boolean csb;

  private boolean csbCentralSubmission;

  private String csbName;

  private boolean hsb;

  private boolean hsbCentralSubmission;

  private String hsbName;

  private boolean psb;

  private boolean psbCentralSubmission;

  private String psbName;

  private boolean provsb;

  private boolean provsbCentralSubmission;

  private String provsbName;

  public NlGebietCustomData() {
    super();
  }

  @Nullable
  public PublicKey getPublicKey() {
    if (StringUtils.isBlank(publicKey)) {
      return null;
    }
    try {
      return new Base64KeyConverter(new NlKeyGeneratorConfig()).convertBase64ToPublicKey(publicKey);
    } catch (Exception e) {
      throw new RuntimeException(e.getMessage(), e);
    }
  }

  public boolean isPublicKeyPresent() {
    return StringUtils.isNotBlank(publicKey);
  }

  public boolean isPublicKeyValid() {
    try {
      return getNlX509Metadata() !=null && getPublicKey() != null;
    } catch (Exception e) {
      return false;
    }
  }

  public NlX509Metadata getNlX509Metadata() {
    return nlX509Metadata;
  }

  public void setPublicKey(PublicKey publicKey, NlX509Metadata nlX509Metadata) {
    this.nlX509Metadata = nlX509Metadata;

    String publicKeyAsString = getPublicKeyAsString(publicKey);

    this.notifyEntity("entity.einzahl.GEBIETSBAUM.PUBLIC_KEY", AttributTyp.STRING, this.publicKey, this.publicKey = publicKeyAsString);
  }

  @Nullable
  private String getPublicKeyAsString(PublicKey publicKey) {
    if (publicKey == null) {
      return null;
    }
    return new Base64KeyConverter(new NlKeyGeneratorConfig()).convertToBase64(publicKey);
  }

  public Collection<String> getProtokollEintraege(String key) {
    if (isNotBlank(key)) {
      return getProtokollEintraegePerKey().getOrDefault(key, new HashSet<>());
    }

    return emptyList();
  }

  public void addProtokollEintrag(String key, String protokollEintragZusaetzlich) {
    if (isNotBlank(protokollEintragZusaetzlich)) {
      addProtokollEintraege(key, asList(protokollEintragZusaetzlich));
    }
  }

  public void addProtokollEintraege(String key, Collection<String> protokollEintraegeZusaetzlich) {
    if (isNotBlank(key)) {
      HashSet<String> protokollEintraege = new HashSet<>(getProtokollEintraege(key));
      protokollEintraege.addAll(protokollEintraegeZusaetzlich);

      getProtokollEintraegePerKey().put(key, protokollEintraege);

      this.notifyEntity();
    }
  }

  private Map<String, HashSet<String>> getProtokollEintraegePerKey() {
    if (protokollEintraegePerKey == null) {
      protokollEintraegePerKey = new HashMap<>();
    }

    return protokollEintraegePerKey;
  }

  public List<NlGebietSchluessel> getUebergeordneteGebieteInMasterElectionTree() {
    if (uebergeordneteGebieteInMasterElectionTree == null) {
      return emptyList();
    }
    return uebergeordneteGebieteInMasterElectionTree;
  }

  public void addUebergeornetesGebietInMasterElectionTree(Gebiet gebiet) {
    if (uebergeordneteGebieteInMasterElectionTree == null) {
      uebergeordneteGebieteInMasterElectionTree = new ArrayList<>();
    }
    uebergeordneteGebieteInMasterElectionTree.add(new NlGebietSchluessel(gebiet.getGebietsart().getName(), gebiet.getNummer(), gebiet.getName()));

    this.notifyEntity();
  }

  public Long getVoteValue() {
    return voteValue;
  }

  public void setVoteValue(Long voteValue) {
    this.notifyEntity("entity.einzahl.GEBIETSBAUM.VOTE_VALUE", AttributTyp.LONG, this.voteValue, this.voteValue = voteValue);
  }

  public boolean isRomanNumerals() {
    return romanNumerals;
  }

  public void setRomanNumerals(boolean romanNumerals) {
    this.notifyEntity("entity.einzahl.GEBIETSBAUM.ROMAN_NUMERALS", AttributTyp.BOOLEAN, this.romanNumerals, this.romanNumerals = romanNumerals);
  }

  public boolean isFrysianExportAllowed() {
    return frysianExportAllowed;
  }

  public void setFrysianExportAllowed(boolean frysianExportAllowed) {
    this.notifyEntity("entity.einzahl.GEBIETSBAUM.FRYSIAN_EXPORT", AttributTyp.BOOLEAN, this.frysianExportAllowed,
        this.frysianExportAllowed = frysianExportAllowed);
  }

  public boolean isCsb() {
    return csb;
  }

  public void setCsb(boolean csb) {
    this.notifyEntity("entity.einzahl.GEBIETSBAUM.CSB", AttributTyp.BOOLEAN, this.csb, this.csb = csb);
  }

  public boolean isCsbCentralSubmission() {
    return csbCentralSubmission;
  }

  public void setCsbCentralSubmission(boolean csbCentralSubmission) {
    this.notifyEntity("entity.einzahl.GEBIETSBAUM.CSB.CENTRAL_SUBMISSION", AttributTyp.BOOLEAN, this.csbCentralSubmission,
        this.csbCentralSubmission = csbCentralSubmission);
  }

  public String getCsbName() {
    return csbName;
  }

  public void setCsbName(String csbName) {
    this.notifyEntity("entity.einzahl.GEBIETSBAUM.CSB.NAME", AttributTyp.STRING, this.csbName, this.csbName = csbName);
  }

  public boolean isHsb() {
    return hsb;
  }

  public void setHsb(boolean hsb) {
    this.notifyEntity("entity.einzahl.GEBIETSBAUM.HSB", AttributTyp.BOOLEAN, this.hsb, this.hsb = hsb);
  }

  public boolean isHsbCentralSubmission() {
    return hsbCentralSubmission;
  }

  public void setHsbCentralSubmission(boolean hsbCentralSubmission) {
    this.notifyEntity("entity.einzahl.GEBIETSBAUM.HSB.CENTRAL_SUBMISSION", AttributTyp.BOOLEAN, this.hsbCentralSubmission,
        this.hsbCentralSubmission = hsbCentralSubmission);
  }

  public String getHsbName() {
    return hsbName;
  }

  public void setHsbName(String hsbName) {
    this.notifyEntity("entity.einzahl.GEBIETSBAUM.HSB.NAME", AttributTyp.STRING, this.hsbName, this.hsbName = hsbName);
  }

  public boolean isPsb() {
    return psb;
  }

  public void setPsb(boolean psb) {
    this.notifyEntity("entity.einzahl.GEBIETSBAUM.PSB", AttributTyp.BOOLEAN, this.psb, this.psb = psb);
  }

  public boolean isPsbCentralSubmission() {
    return psbCentralSubmission;
  }

  public void setPsbCentralSubmission(boolean psbCentralSubmission) {
    this.notifyEntity("entity.einzahl.GEBIETSBAUM.PSB.CENTRAL_SUBMISSION", AttributTyp.BOOLEAN, this.psbCentralSubmission,
        this.psbCentralSubmission = psbCentralSubmission);
  }

  public String getPsbName() {
    return psbName;
  }

  public void setPsbName(String psbName) {
    this.notifyEntity("entity.einzahl.GEBIETSBAUM.PSB.NAME", AttributTyp.STRING, this.psbName, this.psbName = psbName);
  }

  public boolean isProvsb() {
    return provsb;
  }

  public void setProvsb(boolean provsb) {
    this.notifyEntity("entity.einzahl.GEBIETSBAUM.PROVSB", AttributTyp.BOOLEAN, this.provsb, this.provsb = provsb);
  }

  public boolean isProvsbCentralSubmission() {
    return provsbCentralSubmission;
  }

  public void setProvsbCentralSubmission(boolean provsbCentralSubmission) {
    this.notifyEntity("entity.einzahl.GEBIETSBAUM.PROVSB.CENTRAL_SUBMISSION", AttributTyp.BOOLEAN, this.provsbCentralSubmission,
        this.provsbCentralSubmission = provsbCentralSubmission);
  }

  public String getProvsbName() {
    return provsbName;
  }

  public void setProvsbName(String provsbName) {
    this.notifyEntity("entity.einzahl.GEBIETSBAUM.PROVSB.NAME", AttributTyp.STRING, this.provsbName, this.provsbName = provsbName);
  }
}
