package com.hida.model;

import java.security.SecureRandom;
import java.util.Set;
import java.util.LinkedHashSet;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * An abstract Id generator used to create Pids
 *
 * @author Brittany Cruz
 * @author lruffin
 */
public abstract class IdGenerator {

    protected long maxPermutation_;

    /**
     * Creates and new random number generator to aid in the production of
     * non-deterministic ids.
     */
    private static final SecureRandom rng_ = new SecureRandom();

    /**
     * LOGGER; logfile to be stored in resource folder
     */
    private static final Logger LOGGER = LoggerFactory.getLogger(IdGenerator.class);

    /**
     * The string that will be at the front of every id
     */
    protected String prefix_;

    public IdGenerator(String prefix) {
        this.prefix_ = prefix;
    }

    public abstract long getMaxPermutation();

    public abstract void incrementPid(Pid pid);

    protected abstract String longToName(long value);

    protected abstract long PidToLong(Pid pid);

    /**
     * Creates Pids without regard to a natural order.
     *
     * @param amount The number of Pids to be created
     * @return A set of Pids
     */
    public Set<Pid> randomMint(long amount) {
        // checks to see if its possible to produce or add requested amount of
        if (maxPermutation_ < amount) {
            throw new NotEnoughPermutationsException(maxPermutation_, amount);
        }
        // generate ids        
        Set<Pid> pidSet = new LinkedHashSet<>();

        // randomly generate pids using a random number generator
        for (int i = 0; i < amount; i++) {
            long value = Math.abs(rng_.nextLong()) % maxPermutation_;
            Pid pid = new Pid(this.longToName(value));

            // create pid and add it to the set
            while (!pidSet.add(pid)) {
                this.incrementPid(pid);
            }

            LOGGER.trace("Generated Auto Random ID: {}", pid);
        }

        return pidSet;
    }

    /**
     * Creates Pids in ascending order
     *
     * @param amount The number of PIDs to be created
     * @return A set of Pids
     */
    public Set<Pid> sequentialMint(long amount) {
        // checks to see if its possible to produce or add requested amount of
        if (maxPermutation_ < amount) {
            throw new NotEnoughPermutationsException(maxPermutation_, amount);
        }

        // create a set to contain Pids
        Set<Pid> pidSet = new LinkedHashSet<>();

        long startVal = 0;
        for (int i = 0; i < amount; i++) {

            Pid newPid = new Pid(longToName(startVal));
            pidSet.add(newPid);
            startVal++;

            LOGGER.trace("Generated Custom Sequential ID: {}", newPid);
        }
        return pidSet;
    }

    /**
     * Creates Pids in ascending order starting at an arbitrary value.
     *
     * @param amount The number of Pids to be created
     * @param startingValue The value to start sequentially generating Pids
     * @return A set of Pids
     */
    public Set<Pid> sequentialMint(long amount, long startingValue) {
        if (maxPermutation_ < amount) {
            throw new NotEnoughPermutationsException(maxPermutation_, amount);
        }

        // create a set to contain Pids
        Set<Pid> pidSet = new LinkedHashSet<>();

        long ordinal = startingValue;
        Pid basePid = new Pid(this.longToName(ordinal));
        for (int i = 0; i < amount; i++) {

            Pid newPid = new Pid(longToName(startingValue));
            pidSet.add(newPid);
            startingValue++;

            LOGGER.trace("Generated Custom Sequential ID: {}", newPid);
        }

        return pidSet;
    }

    /**
     * Checks whether or not the prefix is valid.
     *
     * @param prefix The string that will be at the front of every id.
     * @return true if it contains numbers and letters and does not exceed 20
     * characters.
     */
    public static final boolean isValidPrefix(String prefix) {
        return prefix.matches("^[0-9a-zA-Z]*$") && prefix.length() <= 20;
    }

    /**
     * Checks whether or not the requested amount is valid.
     *
     * @param amount The amount of ids requested.
     * @return True if amount is non-negative.
     */
    public static final boolean isValidAmount(long amount) {
        return amount >= 0;
    }

    /**
     * Checks whether or not the requested root length is valid
     *
     * @param rootLength Designates the length of the id's root.
     * @return True if rootLength is non-negative and less than or equal to 10.
     */
    public static final boolean isValidRootLength(long rootLength) {
        return rootLength >= 0 && rootLength <= 10;
    }

    /**
     * Checks whether or not the given charMap is valid for this minter.
     *
     * @param charMap The mapping used to describe range of possible characters
     * at each of the id's root's digits.
     * @return True if charMap only contains the characters: 'd', 'l', 'u', 'm',
     * or 'e'.
     */
    public static final boolean isValidCharMap(String charMap) {
        return charMap.matches("^[dlume]+$");
    }

    /* typical getter and setter methods */
    public String getPrefix() {
        return prefix_;
    }

    public void setPrefix(String Prefix) {
        this.prefix_ = Prefix;
    }
}

@@ -1474,32 +1474,41 @@
 unt);%0A        %7D%0A
+        %0A
         // gener
@@ -1511,19 +1511,28 @@
 enerate 
-ids
+longs       
         
@@ -1540,32 +1540,34 @@
         Set%3C
-Pid%3E pid
+Long%3E long
 Set = new Li
@@ -1586,75 +1586,8 @@
 %3E();
-%0A%0A        // randomly generate pids using a random number generator
 %0A   
@@ -1712,51 +1712,8 @@
     
-Pid pid = new Pid(this.longToName(value));%0A
 %0A   
@@ -1731,19 +1731,21 @@
  create 
-pid
+value
  and add
@@ -1779,27 +1779,28 @@
 while (!
-pid
+long
 Set.add(
 pid)) %7B%0A
@@ -1791,19 +1791,21 @@
 Set.add(
-pid
+value
 )) %7B%0A   
@@ -1821,46 +1821,82 @@
     
-this.incrementPid(pid);%0A            %7D%0A
+value = (value + 1) %25 maxPermutation_;%0A            %7D            %0A        %7D
 %0A   
@@ -1904,60 +1904,174 @@
     
+%0A
     
-LOGGER.trace(%22Generated Auto Random ID: %7B%7D%22, pid
+    // convert the longs into Pids%0A        Set%3CPid%3E pidSet = new LinkedHashSet%3C%3E();%0A        for (long l : longSet)%7B%0A            pidSet.add(new Pid(longToName(l))
 );%0A 
@@ -2070,32 +2070,40 @@
 (l)));%0A        %7D
+        
 %0A%0A        return
@@ -2674,33 +2674,32 @@
  amount; i++) %7B%0A
-%0A
             Pid 
@@ -3452,104 +3452,8 @@
 %3E();
-%0A%0A        long ordinal = startingValue;%0A        Pid basePid = new Pid(this.longToName(ordinal));
 %0A   
@@ -3492,17 +3492,16 @@
  i++) %7B%0A
-%0A
         
@@ -3610,20 +3610,70 @@
 ingValue
-++;%0A
+ = (startingValue + 1) %25 maxPermutation_;%0A            
 %0A       

Remove incrementPid from randomMint