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

import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

import org.apache.commons.lang3.RandomStringUtils;

import de.ivu.elect.util.ElectRandom;

public enum GebietPruefkennzeichenGenerierenArt {

  ALPHANUMERISCH_ACHTSTELLIG {
    @Override
    protected String getCharacterSet() {
      return ZEICHENSATZ_N_STELLIG;
    }

    @Override
    public int getAnzahlStellen() {
      return 8;
    }

    @Override
    public String generiereKennzeichen() {
      String result = super.generiereKennzeichen();
      return result.substring(0, 2) + "-" + result.substring(2, 4) + "-" + result.substring(4, 6) + "-" + result.substring(6, 8);
    }
  },
  ALPHANUMERISCH_SECHSTELLIG {
    @Override
    protected String getCharacterSet() {
      return ZEICHENSATZ_N_STELLIG;
    }

    @Override
    public int getAnzahlStellen() {
      return 6;
    }

    @Override
    public String generiereKennzeichen() {
      String result = super.generiereKennzeichen();
      return result.substring(0, 3) + "-" + result.substring(3, 6);
    }

  },
  ALPHANUMERISCH_FUENFSTELLIG {
    @Override
    protected String getCharacterSet() {
      return ZEICHENSATZ_N_STELLIG;
    }

    @Override
    public int getAnzahlStellen() {
      return 5;
    }
  },
  NUMERISCH_ZWEISTELLIG {
    @Override
    protected String getCharacterSet() {
      return "1234567890";
    }

    @Override
    protected int getAnzahlStellen() {
      return 2;
    }

    @Override
    public String generiereKennzeichen() {
      while (true) {
        String result = super.generiereKennzeichen();
        if (!result.startsWith("0")) {
          return result;
        }
      }
    }

    @Override
    public long getAnzahlVerschiedenerKennzeichenMoeglich() {
      return super.getAnzahlVerschiedenerKennzeichenMoeglich() - getCharacterSet().length();
    }
  },
  NUMERISCH_DREISTELLIG {
    @Override
    protected String getCharacterSet() {
      return NUMERISCH_ZWEISTELLIG.getCharacterSet();
    }

    @Override
    protected int getAnzahlStellen() {
      return 3;
    }

    @Override
    public String generiereKennzeichen() {
      while (true) {
        String result = super.generiereKennzeichen();
        if (!result.startsWith("0")) {
          return result;
        }
      }
    }

    @Override
    public long getAnzahlVerschiedenerKennzeichenMoeglich() {
      return super.getAnzahlVerschiedenerKennzeichenMoeglich() - getCharacterSet().length();
    }
  },
  NUMERISCH_VIERSTELLIG {
    @Override
    protected String getCharacterSet() {
      return NUMERISCH_ZWEISTELLIG.getCharacterSet();
    }

    @Override
    protected int getAnzahlStellen() {
      return 4;
    }

    @Override
    public String generiereKennzeichen() {
      while (true) {
        String result = super.generiereKennzeichen();
        if (!result.startsWith("0")) {
          return result;
        }
      }
    }

    @Override
    public long getAnzahlVerschiedenerKennzeichenMoeglich() {
      return super.getAnzahlVerschiedenerKennzeichenMoeglich() - getCharacterSet().length();
    }
  },
  UUID {
    @Override
    protected String getCharacterSet() {
      throw new UnsupportedOperationException();
    }

    @Override
    protected int getAnzahlStellen() {
      throw new UnsupportedOperationException();
    }

    @Override
    public long getAnzahlVerschiedenerKennzeichenMoeglich() {
      return Long.MAX_VALUE;
    }

    @Override
    public String generiereKennzeichen() {
      return java.util.UUID.randomUUID().toString().toUpperCase();
    }
  },

  KENNZEICHEN_LOESCHEN {
    @Override
    public List<Set<Gebiet>> gruppiereNachEindeutigkeit(List<Set<Gebiet>> gebieteNachEindeutigkeit) {
      return gebieteNachEindeutigkeit.stream().flatMap(Collection::stream).map(Collections::singleton).collect(Collectors.toList());
    }

    @Override
    protected String getCharacterSet() {
      return "";
    }

    @Override
    protected int getAnzahlStellen() {
      return 0;
    }

    @Override
    public String generiereKennzeichen() {
      return "";
    }

    @Override
    public long getAnzahlVerschiedenerKennzeichenMoeglich() {
      return 1;
    }
  };

  public static final String ZEICHENSATZ_N_STELLIG = "ACDEFGHKMNPQRSTUVWXYZ2345679"; // kein I,J,L,0,O,B,8 um Verwechslungen zu vermeiden

  public List<Set<Gebiet>> gruppiereNachEindeutigkeit(List<Set<Gebiet>> gebieteNachEindeutigkeit) {
    return gebieteNachEindeutigkeit;
  }

  protected abstract String getCharacterSet();

  protected abstract int getAnzahlStellen();

  public long getAnzahlVerschiedenerKennzeichenMoeglich() {
    return (long) Math.pow(getCharacterSet().length(), getAnzahlStellen());
  }

  public String generiereKennzeichen() {
    char[] chars = getCharacterSet().toCharArray();
    return RandomStringUtils.random(getAnzahlStellen(), 0, chars.length, false, false, chars, ElectRandom.getRandom());
  }

  public static GebietPruefkennzeichenGenerierenArt from(PruefzifferAutomatischGenerierenFormat pruefzifferAutomatischGenerierenFormat) {
    if (pruefzifferAutomatischGenerierenFormat.isDeaktiviert()) {
      throw new IllegalArgumentException(pruefzifferAutomatischGenerierenFormat.name());
    }
    return valueOf(pruefzifferAutomatischGenerierenFormat.name());
  }

}
