package de.ivu.elect.nl.eml;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

import javax.annotation.Nullable;

import org.apache.commons.lang3.StringUtils;
import org.w3._2000._09.xmldsig_.CanonicalizationMethodType;
import org.w3c.dom.Element;
import org.w3c.dom.Node;

import de.ivu.elect.nl.eml.readable.AbstractWrapper;
import de.ivu.elect.nl.eml.readable.ContestIdentifierWrapper;
import de.ivu.elect.nl.eml.readable.ElectionIdentifierWrapper;
import de.ivu.wahl.wus.oasis.eml.ContestIdentifierStructure;
import de.ivu.wahl.wus.oasis.eml.EML;
import de.ivu.wahl.wus.oasis.eml.ElectionIdentifierStructure;
import de.ivu.wahl.wus.oasis.eml.ObjectFactory;


import static de.ivu.elect.nl.eml.LocaleTimeZone.createDateFormat;
import static de.ivu.elect.nl.eml.XmlHelper.getOrCreateElement;
import static de.ivu.elect.nl.eml.XmlHelper.mappeDateTimeToCalendar;

public class EmlWrapper extends AbstractWrapper<EML> {

  public static final String PATTERN = "yyyy-MM-dd'T'HH:mm:ss.SSS";

  private final EmlConfig emlConfig;

  public static EmlWrapper createEml(String type) {
    return new EmlWrapper(type, true);
  }

  public static EmlWrapper createEmlNoCanonicalization(String type) {
    return new EmlWrapper(type, false);
  }

  private EmlWrapper(String emlType, boolean useCanonicalization) {
    super(new ObjectFactory().createEML());
    EML eml = getContent();
    eml.setId(emlType);
    eml.setTransactionId("1"); // ?
    eml.setSchemaVersion("5");

    // Zeitstempel
    Date now = new Date();
    eml.setIssueDate(createDateFormat("yyyy-MM-dd").format(now));

    eml.getAny().add(new de.ivu.wahl.wus.oasis.eml.kiesraad.ObjectFactory().createCreationDateTime(mappeDateTimeToCalendar(now)));

    if (useCanonicalization) {
      // für Hash-Berechnung wichtig
      org.w3._2000._09.xmldsig_.ObjectFactory dsObjectFactory = new org.w3._2000._09.xmldsig_.ObjectFactory();
      CanonicalizationMethodType canonicalizationMethodType = dsObjectFactory.createCanonicalizationMethodType();
      canonicalizationMethodType.setAlgorithm("http://www.w3.org/TR/2001/REC-xml-c14n-20010315#WithComments");
      eml.getAny().add(dsObjectFactory.createCanonicalizationMethod(canonicalizationMethodType));
    }
    emlConfig = new EmlConfig(useCanonicalization, false/*ELECTVAPP-492*/);
  }

  public EmlWrapper(EML eml) {
    super(eml);
    emlConfig = new EmlConfig(true, false/*ELECTVAPP-492*/);
  }

  @Nullable
  public Date getCreationDate() {

    for (Object o : getContent().getAny()) {
      if (o instanceof Element) {
        Element e = (Element) o;
        if (StringUtils.isNotBlank(e.getTagName()) && e.getTagName().contains("CreationDateTime")) {
          Node firstChild = e.getFirstChild();
          if (firstChild != null) {
            String nodeValue = firstChild.getNodeValue();
            if (StringUtils.isNotBlank(nodeValue)) {
              try {
                return new SimpleDateFormat(PATTERN).parse(nodeValue);
              } catch (ParseException parseException) {
                return null;
              }
            }

          }

        }
      }
    }
    return null;
  }

  public ElectionIdentifierWrapper getElectionIdentifier() {
    return new ElectionIdentifierWrapper(
            getOrCreateElement(ElectionIdentifierStructure.class,
                    getContent().getNomination().getContent(),
                    () -> of.createElectionIdentifier(of.createElectionIdentifierStructure())));
  }


  public ContestIdentifierWrapper getContestIdentifier() {
    return new ContestIdentifierWrapper(
            getOrCreateElement(ContestIdentifierStructure.class,
                    getContent().getNomination().getContent(),
                    () -> of.createContestIdentifier(of.createContestIdentifierStructure())));
  }

  public EmlConfig getEmlConfig() {
    return emlConfig;
  }
}
