package io.bootique.names;

import java.util.Objects;

/**
 * A configurable strategy for converting Java class names to command names, configuration keys, etc.
 *
 * @since 0.21
 */
public class ClassToName {

    private String stripSuffix;
    private boolean convertToLowerCase;
    private String partsSeparator;

    private ClassToName() {
    }

    public static Builder builder() {
        return new Builder();
    }

    public String toName(Class<?> type) {

        String name = type.getSimpleName();

        name = applyStripSuffix(name);
        name = applyPartsSeparator(name);
        name = applyCaseConversion(name);

        return name;
    }

    protected String applyStripSuffix(String name) {
        return stripSuffix != null && name.endsWith(stripSuffix)
                ? name.substring(0, name.length() - stripSuffix.length())
                : name;
    }

    protected String applyCaseConversion(String name) {
        return convertToLowerCase ? name.toLowerCase() : name;
    }

    protected String applyPartsSeparator(String name) {
        if (partsSeparator == null) {
            return name;
        }

        StringBuilder transformed = new StringBuilder();

        boolean wasUpper = false;
        for (char c : name.toCharArray()) {

            boolean isUpper = Character.isUpperCase(c);

            if (isUpper && transformed.length() > 0) {

                if (!wasUpper) {
                    transformed.append(partsSeparator);
                }
                wasUpper = true;
            } else {
                wasUpper = isUpper;
            }

            transformed.append(c);
        }

        return transformed.toString();
    }

    public static class Builder {
        private ClassToName strategy;

        private Builder() {
            this.strategy = new ClassToName();
        }

        public ClassToName build() {
            return strategy;
        }

        public Builder stripSuffix(String suffix) {
            if (Objects.requireNonNull(suffix).length() == 0) {
                throw new IllegalArgumentException("Empty suffix");
            }

            strategy.stripSuffix = suffix;
            return this;
        }

        public Builder convertToLowerCase() {
            strategy.convertToLowerCase = true;
            return this;
        }

        public Builder partsSeparator(String separator) {
            if (Objects.requireNonNull(separator).length() == 0) {
                throw new IllegalArgumentException("Empty separator");
            }

            strategy.partsSeparator = separator;
            return this;
        }
    }
}

@@ -21,16 +21,67 @@
 names;%0A%0A
+import java.util.ArrayList;%0Aimport java.util.List;%0A
 import j
@@ -98,16 +98,16 @@
 bjects;%0A
-
 %0A/**%0A * 
@@ -267,22 +267,28 @@
 private 
+List%3C
 String
+%3E
  stripSu
@@ -287,24 +287,26 @@
  stripSuffix
+es
 ;%0A    privat
@@ -395,24 +395,73 @@
 sToName() %7B%0A
+        this.stripSuffixes = new ArrayList%3C%3E(2);%0A
     %7D%0A%0A    p
@@ -649,16 +649,18 @@
 ipSuffix
+es
 (name);%0A
@@ -801,32 +801,34 @@
 applyStripSuffix
+es
 (String name) %7B%0A
@@ -819,32 +819,355 @@
 (String name) %7B%0A
+        %0A        // the order of suffixes matters... strip them in the same order they were added to the builder%0A        for (String suffix : stripSuffixes) %7B%0A            name = applyStripSuffix(name, suffix);%0A        %7D%0A%0A        return name;%0A    %7D%0A%0A    protected String applyStripSuffix(String name, String stripSuffix) %7B%0A%0A
         return s
@@ -2601,17 +2601,22 @@
 ffix
- = 
+es.add(
 suffix
+)
 ;%0A  

allow multiple strip suffixes