package de.ivu.elect.nl.x509;

import java.io.Serializable;
import java.util.Date;

import javax.naming.InvalidNameException;
import javax.naming.ldap.LdapName;
import javax.naming.ldap.Rdn;

import org.apache.commons.lang3.StringUtils;

public class NlX509Metadata implements Serializable {

   private static final char ESCAPE_CHARACTER = '\\';//  ELECTVAPP-1380
   private static final char[] SPECIAL_CHARACTERS = new char[]{',', '+', '\"', '<', '>', ';'};//  ELECTVAPP-1380

   private static final String DN_ATTRIBUTE_COUNTRY_NAME = "C=";

   private static final String DN_ATTRIBUTE_LOCALITY_NAME = "L=";

   private static final String DN_ATTRIBUTE_ORGANISATION_NAME = "O=";

   private static final String DN_ATTRIBUTE_ORGANISATION_UNIT = "OU=";

   private static final String DN_ATTRIBUTE_COMMON_NAME = "CN=";

   private static final String DN_ATTRIBUTE_IDENTIFIER = "UID=";

   private static final String SEPARATOR = ", ";

   private static final long serialVersionUID = 1L;

   private final String countryName; // NL

   private final String localityName; // s-Gravenhage

   private final String organisationName; // TK2021

   private final String organisationUnit; // OSV2020-U

   private final String organisationTypeAndRegionName;
//   private final String organisationType;
//
//   private final String regionName;

   private final String identifier; // GSB0518

   private final Date validFrom;

   private final Date validTill;

   private final String signAlgorithm; // SHA256withRSA

   // Example:
   // Attribute ("DN Attribute"): Wert
   // countryName ("C")       : "NL"
   // localityName ("L")      : "s-Gravenhage"
   // organisationName ("O")  : "TK2021"“"
   // organisationUnit("OU")  : "OSV2020-U"
   // identifier (UID)        : "GSB0518“
   //
   // CommonName: CN="<organisationType> <regionName>"
   // organisationType        : "Gemeente"
   // regionName              : "s-Gravenhage“
   //
   public NlX509Metadata(String countryName,
                         String localityName,
                         String organisationName,
                         String organisationUnit,
                         String organisationTypeAndRegionName,
//                         String organisationType,
//                         String regionName,
                         String identifier,
                         Date validvalidFrom,
                         Date validTill,
                         String signAlgorithm) {

      this.countryName = countryName;
      this.localityName = localityName;
      this.organisationName = organisationName;
      this.organisationUnit = organisationUnit;
      this.organisationTypeAndRegionName = organisationTypeAndRegionName;
//      this.organisationType = organisationType;
//      this.regionName = regionName;
      this.identifier = identifier;
      this.validFrom = validvalidFrom;
      this.validTill = validTill;
      this.signAlgorithm = signAlgorithm;
   }

   public static NlX509Metadata fromDistinguihedName(String distinguishedName, Date validFrom, Date validTill, String signAlgorithm) {


      String countryName = null;
      String localityName = null;
      String organisationName = null;
      String organisationUnit = null;
      String organisationTypeAndRegionName = null;
//      String organisationType = null;
//      String regionName = null;
      String identifier = null;

      try {
         LdapName ldapName =new LdapName(distinguishedName); // ELECTVAPP-1380
         for (Rdn rdn : ldapName.getRdns()) {


            String dnParameter = rdn.getType()+"="+rdn.getValue();

//      System.out.println("distinguishedName = " + distinguishedName);
//      String[] metadataList = distinguishedName.split(Pattern.quote(SEPARATOR));
//
//
//      for (String dnParameter : metadataList) {
         if (dnParameter.startsWith(DN_ATTRIBUTE_COUNTRY_NAME)) {
            countryName = dnParameter.substring(DN_ATTRIBUTE_COUNTRY_NAME.length());
         }
         if (dnParameter.startsWith(DN_ATTRIBUTE_LOCALITY_NAME)) {
            localityName = dnParameter.substring(DN_ATTRIBUTE_LOCALITY_NAME.length());
         }
         if (dnParameter.startsWith(DN_ATTRIBUTE_ORGANISATION_NAME)) {
            organisationName = dnParameter.substring(DN_ATTRIBUTE_ORGANISATION_NAME.length());
         }
         if (dnParameter.startsWith(DN_ATTRIBUTE_ORGANISATION_UNIT)) {
            organisationUnit = dnParameter.substring(DN_ATTRIBUTE_ORGANISATION_UNIT.length());
         }
         if (dnParameter.startsWith(DN_ATTRIBUTE_IDENTIFIER)) {
            identifier = dnParameter.substring(DN_ATTRIBUTE_IDENTIFIER.length());
         }
         if (dnParameter.startsWith(DN_ATTRIBUTE_COMMON_NAME)) {
            organisationTypeAndRegionName = dnParameter.substring(DN_ATTRIBUTE_COMMON_NAME.length());
//            String commonName = dnParameter.substring(DN_ATTRIBUTE_COMMON_NAME.length());
//            organisationType = commonName.substring(0, commonName.indexOf(" "));
//            regionName = commonName.substring(commonName.indexOf(" ")).trim();
         }
//      }



         }

      } catch (InvalidNameException e) {
         throw new RuntimeException(distinguishedName+"-"+e.getMessage(), e);
      }

      return new NlX509Metadata(countryName,
          localityName,
          organisationName,
          organisationUnit,
          organisationTypeAndRegionName,
//          organisationType,
//          regionName,
          identifier, validFrom, validTill, signAlgorithm);
   }

   public String getCountryName() {
      return countryName;
   }

   public String getLocalityName() {
      return localityName;
   }

   public String getOrganisationName() {
      return organisationName;
   }

   public String getOrganisationUnit() {
      return organisationUnit;
   }

   public String getOrganisationTypeAndRegionName() {
      return organisationTypeAndRegionName;
   }

   //   public String getOrganisationType() {
//      return organisationType;
//   }
//
//   public String getRegionName() {
//      return regionName;
//   }

   public String getIdentifier() {
      return identifier;
   }

   public Date getValidFrom() {
      return validFrom;
   }

   public Date getValidTill() {
      return validTill;
   }

   public String getSignAlgorithm() {
      return signAlgorithm;
   }

   public String getDistinguishedName() {
      return getDNParameter(DN_ATTRIBUTE_COUNTRY_NAME, getCountryName(), SEPARATOR) +
          getDNParameter(DN_ATTRIBUTE_LOCALITY_NAME, getLocalityName(), SEPARATOR) +
          getDNParameter(DN_ATTRIBUTE_ORGANISATION_NAME, getOrganisationName(), SEPARATOR) +
          getDNParameter(DN_ATTRIBUTE_ORGANISATION_UNIT, getOrganisationUnit(), SEPARATOR) +
          getDNParameter(DN_ATTRIBUTE_COMMON_NAME, getCommonNameValue(), SEPARATOR) +
          getDNParameter(DN_ATTRIBUTE_IDENTIFIER, getIdentifier(), null);
   }

   private String getCommonNameValue() {
      // return getOrganisationType() + " " + getRegionName();
      return organisationTypeAndRegionName;
   }

   private String getDNParameter(String attribute, String value, String separator) {
      StringBuilder result = new StringBuilder();
      if (StringUtils.isNotBlank(attribute) && (StringUtils.isNotBlank(value))) {
         result.append(attribute).append(escape(value));
         if (StringUtils.isNotBlank(separator)) {
            result.append(separator);
         }
      }
      return result.toString();
   }

   private String escape(String value) {
      String result = value.replace(""+ESCAPE_CHARACTER, ""+ESCAPE_CHARACTER+ESCAPE_CHARACTER);


      for (char specialCharacter : SPECIAL_CHARACTERS) {
         result = result.replace("" + specialCharacter, ""+ ESCAPE_CHARACTER + specialCharacter);
      }

      return result;
   }

   @Override
   public String toString() {
      return "NlX509Metadata{" +
          "countryName='" + countryName + '\'' +
          ", localityName='" + localityName + '\'' +
          ", organisationName='" + organisationName + '\'' +
          ", organisationUnit='" + organisationUnit + '\'' +
          ", organisationTypeAndRegionName='" + organisationTypeAndRegionName + '\'' +
          ", identifier='" + identifier + '\'' +
          ", validFrom=" + validFrom +
          ", validTill=" + validTill +
          ", signAlgorithm='" + signAlgorithm + '\'' +
          ", distinguishedName='" + getDistinguishedName() + '\'' +
          '}';
   }

}
