001/*******************************************************************************
002 * Copyright (c) 2017, 2018 Red Hat Inc
003 * All rights reserved. This program and the accompanying materials
004 * are made available under the terms of the Eclipse Public License v1.0
005 * which accompanies this distribution, and is available at
006 * http://www.eclipse.org/legal/epl-v10.html
007 *
008 * Contributors:
009 *     Jens Reimann - initial API and implementation
010 *******************************************************************************/
011package de.dentrassi.varlink.generator.util;
012
013import java.util.LinkedList;
014import java.util.List;
015import java.util.function.Function;
016import java.util.stream.Collectors;
017
018public final class Names {
019    private Names() {
020    }
021
022    @FunctionalInterface
023    private interface CharMapper {
024        char map(char in);
025    }
026
027    @FunctionalInterface
028    private interface CharConsumer {
029        void consume(char in);
030    }
031
032    public static String toCamelCase(final String text, final boolean firstUpper) {
033        return toFormat(text, words -> joinCamel(firstUpper, words));
034    }
035
036    public static String toLowerDash(final String text) {
037        return toFormat(text, words -> joinDelimiter(words, String::toLowerCase, "-"));
038    }
039
040    public static String toUpperUnderscore(final String text) {
041        return toFormat(text, words -> joinDelimiter(words, String::toUpperCase, "_"));
042    }
043
044    private static enum Type {
045        UPPER, LOWER, NUMERIC, OTHER;
046    }
047
048    public static String toFormat(final String text, final Function<List<String>, String> target) {
049        if (text == null) {
050            return null;
051        }
052
053        final List<String> words = new LinkedList<>();
054        final int len = text.length();
055
056        Type lastType = Type.UPPER;
057        StringBuilder sb = new StringBuilder();
058
059        for (int i = 0; i < len; i++) {
060            final char c = text.charAt(i);
061
062            final Type type = typeOf(c);
063
064            if (lastType == Type.LOWER && (type == Type.UPPER || type == Type.NUMERIC)) {
065                sb = split(sb, words);
066                sb = append(sb, c);
067            } else if (lastType == Type.NUMERIC && (type == Type.UPPER || type == Type.LOWER)) {
068                sb = split(sb, words);
069                sb = append(sb, c);
070            } else if (type != Type.OTHER) {
071                sb = append(sb, c);
072            } else {
073                // unknown type: split and ignore
074                sb = split(sb, words);
075            }
076
077            lastType = type;
078        }
079
080        split(sb, words);
081
082        return target.apply(words);
083    }
084
085    private static StringBuilder append(StringBuilder sb, final char c) {
086        if (sb == null) {
087            sb = new StringBuilder();
088        }
089        sb.append(c);
090        return sb;
091    }
092
093    private static StringBuilder split(StringBuilder sb, final List<String> words) {
094        if (sb != null) {
095            words.add(sb.toString());
096            sb = null;
097        }
098        return sb;
099    }
100
101    private static Type typeOf(final char c) {
102        if (Character.isUpperCase(c)) {
103            return Type.UPPER;
104        } else if (Character.isDigit(c)) {
105            return Type.NUMERIC;
106        } else if (Character.isAlphabetic(c)) {
107            return Type.LOWER;
108        }
109        return Type.OTHER;
110    }
111
112    private static String joinDelimiter(final List<String> words, Function<String, String> conversion,
113            final String delimiter) {
114        if (conversion == null) {
115            conversion = str -> str;
116        }
117
118        return words.stream().map(conversion).collect(Collectors.joining(delimiter));
119    }
120
121    private static String joinCamel(final boolean firstUpper, final List<String> words) {
122        CharMapper mapper = firstUpper ? Character::toUpperCase : Character::toLowerCase;
123        final StringBuilder result = new StringBuilder();
124        for (final String word : words) {
125
126            final int wlen = word.length();
127            if (wlen < 1) {
128                continue;
129            }
130
131            result.append(mapper.map(word.charAt(0)));
132
133            if (wlen > 1) {
134                result.append(word.substring(1).toLowerCase());
135            }
136
137            mapper = Character::toUpperCase;
138        }
139        return result.toString();
140    }
141
142    public static String makeVersion(final String version) {
143        return "v" + version.replace(".", "_");
144    }
145
146    public static String toUpperFirst(final String string) {
147        if (string.length() < 2) {
148            return string.toUpperCase();
149        }
150
151        return Character.toUpperCase(string.charAt(0)) + string.substring(1);
152    }
153
154    public static String toLowerFirst(final String string) {
155        if (string.length() < 2) {
156            return string.toLowerCase();
157        }
158
159        return Character.toLowerCase(string.charAt(0)) + string.substring(1);
160    }
161
162}