
package de.ivu.elect.business.security;

import java.util.ArrayList;
import java.util.Collection;
import java.util.EnumSet;
import java.util.HashSet;
import java.util.List;

import javax.annotation.Nullable;

import de.ivu.elect.business.lokalisierung.entity.LokalisierungLocale;


import static java.util.Arrays.asList;
import static java.util.Collections.singletonList;

public enum Customer {

  TEST {

    @Override
    public String getBezeichnung() {
      return "Test";
    }
  },
  MINIMAL {

    @Override
    public String getBezeichnung() {
      return "Minimales System";
    }
  },
  DOKUMENTENGENERATOR {

    @Override
    public String getBezeichnung() {
      return "Dokumentengenerator";
    }
  },
  SKRIPT_CONSOLE_SUPPORT {

    @Override
    public String getBezeichnung() {
      return "Skript Console";
    }
  },
  VIRUS_SCAN_SUPPORT {

    @Override
    public String getBezeichnung() {
      return "Virus scan";
    }
  },
  BASE(MINIMAL, DOKUMENTENGENERATOR /* , ELECT-12546 SKRIPT_CONSOLE_SUPPORT */) {

    @Override
    public String getBezeichnung() {
      return "Basis Wahl-System";
    }

  },
  ACTIVE_DIRECTORY_SUPPORT(BASE) {

    @Override
    public String getBezeichnung() {
      return "Active Directory Unterstützung";
    }
  },
  TFA_SUPPORT(BASE) {

    @Override
    public String getBezeichnung() {
      return "TFA Unterstützung";
    }

  },
  TAG_SUPPORT(MINIMAL) {

    @Override
    public String getBezeichnung() {
      return "Tag-Support";
    }
  },
  DASHBOARD(MINIMAL) {

    @Override
    public String getBezeichnung() {
      return "Dashboard";
    }
  },
  DASHBOARD_NEWS(DASHBOARD) {

    @Override
    public String getBezeichnung() {
      return "Dashboard News";
    }
  },
  COMMON(BASE) {

    @Override
    public String getBezeichnung() {
      return "WOS-WAS-WUS Common";
    }
  },
  MANDANT_EXCHANGE(BASE) {

    @Override
    public String getBezeichnung() {
      return "Mandant-Export";
    }
  },

  PERSONENREGISTER {

    @Override
    public String getBezeichnung() {
      return "Personenregister";
    }
  },

  COMMON_INTERFACES_MESO(COMMON, PERSONENREGISTER) {

    @Override
    public String getBezeichnung() {
      return "Common Interfaces Meso";
    }
  },
  COMMON_INTERFACES_OK_KOMM_XOEV(COMMON, PERSONENREGISTER) {

    @Override
    public String getBezeichnung() {
      return "Common Interfaces OK.KOMM XÖV";
    }
  },
  COMMON_INTERFACES_DVDV_PERSONENREGISTER(COMMON, PERSONENREGISTER) {

    @Override
    public String getBezeichnung() {
      return "Common Interfaces DVDV Personenregister";
    }
  },
  // Modul elect-base-extension-mail hinzufügen!
  MAIL_SUPPORT() {

    @Override
    public String getBezeichnung() {
      return "E-Mail-Support";
    }
  },
  CORE(COMMON) {

    @Override
    public String getBezeichnung() {
      return "WAS-WUS Common";
    }
  },
  WUS(CORE) {

    @Override
    public String getBezeichnung() {
      return "Wus";
    }
  },
  WAS(CORE) {

    @Override
    public String getBezeichnung() {
      return "Was";
    }

  },
  REPLIKATION_SUPPORT(WAS) {

    @Override
    public String getBezeichnung() {
      return "Replikation Support";
    }
  },
  STIMMENUEBERGABE_SUPPORT(WAS) {

    @Override
    public String getBezeichnung() {
      return "Stimmenübergabe Support";
    }
  },
  WES(MINIMAL, DASHBOARD, DOKUMENTENGENERATOR) {

    @Override
    public String getBezeichnung() {
      return "Wes";
    }

    @Override
    public boolean isMandantUnterstuetzt() {
      return false; // nicht vorgesehen
    }

  },
  WOS(COMMON, MAIL_SUPPORT, TAG_SUPPORT) {

    @Override
    public String getBezeichnung() {
      return "Wos";
    }
  },
  WVZ(BASE) {

    @Override
    public String getBezeichnung() {
      return "Wvz";
    }

    @Override
    public boolean isMandantUnterstuetzt() {
      return false; // nicht vorgesehen
    }
  },
  WAS_STIMMZETTEL_EINZELERFASSUNG(WAS) {

    @Override
    public String getBezeichnung() {
      return "Stimmzetteleinzelerfassung im WAS";
    }
  },
  WES_UNTERSTUETZUNG(WAS_STIMMZETTEL_EINZELERFASSUNG) {

    @Override
    public String getBezeichnung() {
      return "WES-Funktionalitäten im WAS";
    }
  },
  PRAESENTATION_WUS(WUS) {

    @Override
    public String getBezeichnung() {
      return "Präsentation im WUS vorhanden";
    }
  },
  PRAESENTATION_WAS(WAS) {

    @Override
    public String getBezeichnung() {
      return "Präsentation im WAS vorhanden";
    }
  },
  WUS_INTERFACES_WVP(WUS) {

    @Override
    public String getBezeichnung() {
      return "Wus Interfaces Wvp";
    }
  },
  DESTATIS_COMMON(COMMON, TFA_SUPPORT) {

    @Override
    protected String getJiraProjektIdInternal() {
      return "10390";
    }

    @Override
    public String getBezeichnung() {
      return "Destatis " + COMMON.getBezeichnung();
    }
  },
  DESTATIS_WUS(DESTATIS_COMMON, WUS, WUS_INTERFACES_WVP) {

    @Override
    public String getBezeichnung() {
      return "Destatis " + WUS.getBezeichnung();
    }

    @Override
    public Collection<LokalisierungLocale> getUnterstuetzteSprachen() {
      return SPRACHEN_DESTATIS;
    }
  },
  DESTATIS_WUS_EXTERN(DESTATIS_WUS) {

    @Override
    public String getBezeichnung() {
      return "Destatis (extern) " + WUS.getBezeichnung();
    }

    @Override
    public Collection<LokalisierungLocale> getUnterstuetzteSprachen() {
      return SPRACHEN_DESTATIS;
    }
  },
  DESTATIS_WAS(DESTATIS_COMMON, WAS, REPLIKATION_SUPPORT) {

    @Override
    public String getBezeichnung() {
      return "Destatis " + WAS.getBezeichnung();
    }

    @Override
    public Collection<LokalisierungLocale> getUnterstuetzteSprachen() {
      return SPRACHEN_DESTATIS;
    }
  },

  MUC_BASE(BASE) {

    @Override
    public String getBezeichnung() {
      return "München " + BASE.getBezeichnung();
    }
  },
  MUC_COMMON(MUC_BASE, COMMON, PERSONENREGISTER) {

    @Override
    protected String getJiraProjektIdInternal() {
      return "11685";
    }

    @Override
    public String getBezeichnung() {
      return "München " + COMMON.getBezeichnung();

    }
  },
  MUC_CORE(MUC_COMMON) {

    @Override
    public String getBezeichnung() {
      return "München " + CORE.getBezeichnung();
    }
  },
  MUC_WUS(MUC_CORE, WUS, WUS_INTERFACES_WVP, PRAESENTATION_WUS) {

    @Override
    public String getBezeichnung() {
      return "München " + WUS.getBezeichnung();
    }

    @Override
    public Collection<LokalisierungLocale> getUnterstuetzteSprachen() {
      return SPRACHEN_MUC;
    }
  },
  MUC_WAS(MUC_CORE, WAS, /* WES_UNTERSTUETZUNG, */ PRAESENTATION_WAS, STIMMENUEBERGABE_SUPPORT /* ELECT-12062 */) {

    @Override
    public String getBezeichnung() {
      return "München " + WAS.getBezeichnung();
    }

    @Override
    public Collection<LokalisierungLocale> getUnterstuetzteSprachen() {
      return SPRACHEN_MUC;
    }
  },
  MUC_WOS(MUC_COMMON, WOS) {

    @Override
    public String getBezeichnung() {
      return "München " + WOS.getBezeichnung();
    }

    @Override
    public Collection<LokalisierungLocale> getUnterstuetzteSprachen() {
      return SPRACHEN_MUC;
    }
  },
  MUC_WVZ(MUC_BASE, WVZ) {

    @Override
    public String getBezeichnung() {
      return "München " + WVZ.getBezeichnung();
    }

    @Override
    public Collection<LokalisierungLocale> getUnterstuetzteSprachen() {
      return SPRACHEN_MUC;
    }
  },

  DD_COMMON(COMMON, COMMON_INTERFACES_MESO, ACTIVE_DIRECTORY_SUPPORT) {

    @Override
    protected String getJiraProjektIdInternal() {
      return "12295";
    }

    @Override
    public String getBezeichnung() {
      return "Dresden " + COMMON.getBezeichnung();
    }
  },
  DD_CORE(DD_COMMON) {

    @Override
    protected String getJiraProjektIdInternal() {
      return "12295";
    }

    @Override
    public String getBezeichnung() {
      return "Dresden " + COMMON.getBezeichnung();
    }
  },
  DD_WUS(DD_CORE, WUS, PRAESENTATION_WUS) {

    @Override
    public String getBezeichnung() {
      return "Dresden " + WUS.getBezeichnung();
    }

    @Override
    public Collection<LokalisierungLocale> getUnterstuetzteSprachen() {
      return SPRACHEN_DD;
    }
  },
  DD_WAS(DD_CORE, WAS, PRAESENTATION_WAS) {

    @Override
    public String getBezeichnung() {
      return "Dresden " + WAS.getBezeichnung();
    }

    @Override
    public Collection<LokalisierungLocale> getUnterstuetzteSprachen() {
      return SPRACHEN_DD;
    }
  },
  DD_WOS(DD_COMMON, WOS) {

    @Override
    public String getBezeichnung() {
      return "Dresden " + WOS.getBezeichnung();
    }

    @Override
    public Collection<LokalisierungLocale> getUnterstuetzteSprachen() {
      return SPRACHEN_DD;
    }
  },

//  BB_COMMON(COMMON) {
//
//    @Override
//    protected String getJiraProjektIdInternal() {
//      return "TODO";
//    }
//
//    @Override
//    public String getBezeichnung() {
//      return "Berlin " + COMMON.getBezeichnung();
//    }
//  },
//  BB_WUS(BB_COMMON, WUS, PRAESENTATION_WUS) {
//
//    @Override
//    public String getBezeichnung() {
//      return "Berlin " + WUS.getBezeichnung();
//    }
//
//    @Override
//    public Collection<LokalisierungLocale> getUnterstuetzteSprachen() {
//      return SPRACHEN_BB;
//    }
//  },
//  BB_WAS_SHARED(BB_COMMON, WAS, PRAESENTATION_WAS) {
//
//    @Override
//    public String getBezeichnung() {
//      return "Berlin/Brandenburg " + WAS.getBezeichnung();
//    }
//  },
//  BB_WAS_BER(BB_WAS_SHARED, REPLIKATION_SUPPORT) {
//
//    @Override
//    public String getBezeichnung() {
//      return "Berlin " + WAS.getBezeichnung();
//    }
//
//    @Override
//    public Collection<LokalisierungLocale> getUnterstuetzteSprachen() {
//      return SPRACHEN_BB;
//    }
//  },
//  BB_WAS_BRB(BB_WAS_SHARED) {
//
//    @Override
//    public String getBezeichnung() {
//      return "Brandenburg " + WAS.getBezeichnung();
//    }
//
//    @Override
//    public Collection<LokalisierungLocale> getUnterstuetzteSprachen() {
//      return SPRACHEN_BB;
//    }
//  },

  SL_COMMON(COMMON) {
    @Override
    protected String getJiraProjektIdInternal() {
      return "TODO";
    }

    @Override
    public String getBezeichnung() {
      return "Saarland " + COMMON.getBezeichnung();
    }
  },
  SL_WUS(SL_COMMON, WUS, PRAESENTATION_WUS) {

    @Override
    public String getBezeichnung() {
      return "Saarland " + WUS.getBezeichnung();
    }

    @Override
    public Collection<LokalisierungLocale> getUnterstuetzteSprachen() {
      return SPRACHEN_SL;
    }
  },
  SL_WAS(SL_COMMON, WAS, PRAESENTATION_WAS, REPLIKATION_SUPPORT) {

    @Override
    public String getBezeichnung() {
      return "Saarland " + WAS.getBezeichnung();
    }

    @Override
    public Collection<LokalisierungLocale> getUnterstuetzteSprachen() {
      return SPRACHEN_SL;
    }
  },
  KOM_COMMON(COMMON, COMMON_INTERFACES_MESO, COMMON_INTERFACES_OK_KOMM_XOEV, COMMON_INTERFACES_DVDV_PERSONENREGISTER, DASHBOARD_NEWS, MANDANT_EXCHANGE, VIRUS_SCAN_SUPPORT) {

    @Override
    public String getBezeichnung() {
      return "KOM " + COMMON.getBezeichnung();
    }
  },
  // ELECT-6886 Das WAS für KOM umfasst alle WUS-Funktionalitäten
  KOM_WAS(KOM_COMMON, WAS, WUS, PRAESENTATION_WUS, PRAESENTATION_WAS, STIMMENUEBERGABE_SUPPORT/* ELECT-12380 */) {

    @Override
    public String getBezeichnung() {
      return "KOM " + WAS.getBezeichnung();
    }

    @Override
    public Collection<LokalisierungLocale> getUnterstuetzteSprachen() {
      return SPRACHEN_KOM;
    }
  },
  KOM_WES(WES) {

    @Override
    public String getBezeichnung() {
      return "KOM " + WES.getBezeichnung();
    }

    @Override
    public Collection<LokalisierungLocale> getUnterstuetzteSprachen() {
      return SPRACHEN_KOM;
    }
  },
  KOM_WOS(KOM_COMMON, WOS) {

    @Override
    public String getBezeichnung() {
      return "KOM " + WOS.getBezeichnung();
    }

    @Override
    public Collection<LokalisierungLocale> getUnterstuetzteSprachen() {
      return SPRACHEN_KOM;
    }
  },
  KOM_BE_WAS(KOM_WAS, TFA_SUPPORT, STIMMENUEBERGABE_SUPPORT /* ELECT-12062 */) {

    @Override
    public String getBezeichnung() {
      return KOM_WAS.getBezeichnung() + " BE";
    }
  },
  KOM_BB_WOS(KOM_WOS, TFA_SUPPORT) {

    @Override
    public String getBezeichnung() {
      return KOM_WOS.getBezeichnung() + " BB";
    }
  },

  KOM_BB_WAS(KOM_WAS, TFA_SUPPORT, STIMMENUEBERGABE_SUPPORT/* ELECT-12062 */) {

    @Override
    public String getBezeichnung() {
      return KOM_WAS.getBezeichnung() + " BB";
    }
  },
  KOM_BY_WOS(KOM_WOS) {

    @Override
    public String getBezeichnung() {
      return KOM_WOS.getBezeichnung() + " BY";
    }
  },
  KOM_BY_WAS(KOM_WAS, WES_UNTERSTUETZUNG, WAS_STIMMZETTEL_EINZELERFASSUNG, STIMMENUEBERGABE_SUPPORT) {

    @Override
    public String getBezeichnung() {
      return KOM_WAS.getBezeichnung() + " BY";
    }
  },
  KOM_MV_WOS(KOM_WOS) {

    @Override
    public String getBezeichnung() {
      return KOM_WOS.getBezeichnung() + " MV";
    }
  },
  KOM_MV_WAS(KOM_WAS) {

    @Override
    public String getBezeichnung() {
      return KOM_WAS.getBezeichnung() + " MV";
    }
  },
  KOM_NI_WOS(KOM_WOS, ACTIVE_DIRECTORY_SUPPORT) {

    @Override
    public String getBezeichnung() {
      return KOM_WOS.getBezeichnung() + " NI";
    }
  },
  KOM_NI_WAS(KOM_WAS, ACTIVE_DIRECTORY_SUPPORT) {

    @Override
    public String getBezeichnung() {
      return KOM_WAS.getBezeichnung() + " NI";
    }
  },
  KOM_RP_WOS(KOM_WOS) {

    @Override
    public String getBezeichnung() {
      return KOM_WOS.getBezeichnung() + " RP";
    }
  },
  KOM_RP_WAS(KOM_WAS) {

    @Override
    public String getBezeichnung() {
      return KOM_WAS.getBezeichnung() + " RP";
    }
  },
  KOM_SH_WOS(KOM_WOS, ACTIVE_DIRECTORY_SUPPORT /* ELECT-11850 */) {

    @Override
    public String getBezeichnung() {
      return KOM_WOS.getBezeichnung() + " SH";
    }
  },
  KOM_SH_WAS(KOM_WAS, ACTIVE_DIRECTORY_SUPPORT /* ELECT-11850 */) {

    @Override
    public String getBezeichnung() {
      return KOM_WAS.getBezeichnung() + " SH";
    }
  },
  KOM_ST_WOS(KOM_WOS, ACTIVE_DIRECTORY_SUPPORT) {

    @Override
    public String getBezeichnung() {
      return KOM_WOS.getBezeichnung() + " ST";
    }
  },
  KOM_ST_WAS(KOM_WAS, ACTIVE_DIRECTORY_SUPPORT) {

    @Override
    public String getBezeichnung() {
      return KOM_WAS.getBezeichnung() + " ST";
    }
  },

  KOM_HH_WAS(KOM_WAS, ACTIVE_DIRECTORY_SUPPORT /* ELECT-11850 */) {

    @Override
    public String getBezeichnung() {
      return KOM_WAS.getBezeichnung() + " HH";
    }
  },

  KOM_TH_WAS(KOM_WAS, ACTIVE_DIRECTORY_SUPPORT) {

    @Override
    public String getBezeichnung() {
      return KOM_WAS.getBezeichnung() + " TH";
    }
  },

  KOM_TH_WOS(KOM_WOS, ACTIVE_DIRECTORY_SUPPORT) {

    @Override
    public String getBezeichnung() {
      return KOM_WOS.getBezeichnung() + " TH";
    }
  },

  NL_COMMON(COMMON) {

    @Override
    protected String getJiraProjektIdInternal() {
      return "TODO";
    }

    @Override
    public String getBezeichnung() {
      return "Niederlande " + BASE.getBezeichnung();
    }
  },
  NL_WUS(NL_COMMON, WUS, WUS_INTERFACES_WVP, PERSONENREGISTER) {

    @Override
    public String getBezeichnung() {
      return "Niederlande " + WUS.getBezeichnung();
    }

    @Override
    public Collection<LokalisierungLocale> getUnterstuetzteSprachen() {
      return SPRACHEN_NL;
    }
  },
  NL_WAS(NL_COMMON, WAS) {

    @Override
    public String getBezeichnung() {
      return "Niederlande " + WAS.getBezeichnung();
    }

    @Override
    public Collection<LokalisierungLocale> getUnterstuetzteSprachen() {
      return SPRACHEN_NL;
    }
  }

  ;

  private static final Collection<LokalisierungLocale> NUR_DEUTSCH = singletonList(LokalisierungLocale.DEUTSCH);

  private static final Collection<LokalisierungLocale> DEUTSCH_ENGLISCH = asList(LokalisierungLocale.DEUTSCH, LokalisierungLocale.ENGLISCH);

  private static final Collection<LokalisierungLocale> SPRACHEN_MUC = /* NUR_DEUTSCH; */ DEUTSCH_ENGLISCH; // für Screenshots ocs

  private static final Collection<LokalisierungLocale> SPRACHEN_KOM = /* NUR_DEUTSCH; */ DEUTSCH_ENGLISCH; // Irgendwelche Demos für WUS/WAS zusammen

  private static final Collection<LokalisierungLocale> SPRACHEN_DD = NUR_DEUTSCH;

  private static final Collection<LokalisierungLocale> SPRACHEN_BB = NUR_DEUTSCH;

  private static final Collection<LokalisierungLocale> SPRACHEN_DESTATIS = NUR_DEUTSCH;

  private static final Collection<LokalisierungLocale> SPRACHEN_SL = NUR_DEUTSCH;

  private static final Collection<LokalisierungLocale> SPRACHEN_NL = asList(LokalisierungLocale.NIEDERLAENDISCH, LokalisierungLocale.DEUTSCH);

  private final List<Customer> parents = new ArrayList<>();

  Customer(Customer... parents) {
    if (parents != null) {
      this.parents.addAll(asList(parents));
    }
  }

  public List<Customer> getParents() {
    return parents;
  }

  /**
   * @return The complete customer-hierarchy inclusive itself
   */
  public Collection<Customer> getContainedCustomers() {
    Collection<Customer> result = new HashSet<>();

    result.add(this);

    for (Customer parent : getParents()) {
      result.addAll(parent.getContainedCustomers());
    }

    return result;
  }

  public String getJiraProjektId() {
    if (getJiraProjektIdInternal() != null) {
      return getJiraProjektIdInternal();
    }

    return getParents().stream().filter(customer -> customer.getJiraProjektIdInternal() != null).findFirst().map(Customer::getJiraProjektIdInternal).orElse(null);
  }

  @Nullable
  protected String getJiraProjektIdInternal() {
    return null;
  }

  /**
   * Name des Kunden, keine Lokalisierung, weil diese bei Verwendung noch nicht initialisiert ist
   */
  public abstract String getBezeichnung();

  public boolean containsAny(Collection<Customer> customers) {
    Collection<Customer> others = new HashSet<>(getContainedCustomers());
    others.retainAll(customers);

    return !others.isEmpty();
  }

  public boolean contains(Customer one, Customer... more) {
    Collection<Customer> others = new HashSet<>(asList(more));
    others.add(one);

    return getContainedCustomers().containsAll(others);
  }

  public Collection<LokalisierungLocale> getUnterstuetzteSprachen() {
    return EnumSet.allOf(LokalisierungLocale.class);
  }

  public boolean isMandantUnterstuetzt() {
    return getContainedCustomers().stream().filter(containedCustomer -> !this.equals(containedCustomer)).allMatch(Customer::isMandantUnterstuetzt);
  }
}
