001/**
002 * Logback: the reliable, generic, fast and flexible logging framework.
003 * Copyright (C) 1999-2015, QOS.ch. All rights reserved.
004 *
005 * This program and the accompanying materials are dual-licensed under
006 * either the terms of the Eclipse Public License v1.0 as published by
007 * the Eclipse Foundation
008 *
009 *   or (per the licensee's choosing)
010 *
011 * under the terms of the GNU Lesser General Public License version 2.1
012 * as published by the Free Software Foundation.
013 */
014package ch.qos.logback.core.joran.spi;
015
016import java.util.ArrayList;
017import java.util.List;
018
019public class CaseCombinator {
020
021    List<String> combinations(String in) {
022        int length = in.length();
023        List<String> permutationsList = new ArrayList<String>();
024
025        int totalCombinations = computeTotalNumerOfCombinations(in, length);
026
027        for (int j = 0; j < totalCombinations; j++) {
028            StringBuilder newCombination = new StringBuilder();
029            int pos = 0;
030            for (int i = 0; i < length; i++) {
031                char c = in.charAt(i);
032                if (isEnglishLetter(c)) {
033                    c = permute(c, j, pos);
034                    pos++;
035                }
036                newCombination.append(c);
037            }
038            permutationsList.add(newCombination.toString());
039        }
040        return permutationsList;
041
042    }
043
044    private char permute(char c, int permutation, int position) {
045        int mask = 1 << position;
046        boolean shouldBeInUpperCase = (permutation & mask) != 0;
047        boolean isEffectivelyUpperCase = isUpperCase(c);
048        if (shouldBeInUpperCase && !isEffectivelyUpperCase)
049            return toUpperCase(c);
050        if (!shouldBeInUpperCase && isEffectivelyUpperCase)
051            return toLowerCase(c);
052        return c;
053    }
054
055    private int computeTotalNumerOfCombinations(String in, int length) {
056        int count = 0;
057        for (int i = 0; i < length; i++) {
058            char c = in.charAt(i);
059            if (isEnglishLetter(c))
060                count++;
061        }
062        // return 2^count (2 to the power of count)
063        return (1 << count);
064    }
065
066    private char toUpperCase(char c) {
067        if ('A' <= c && c <= 'Z') {
068            return c;
069        }
070        if ('a' <= c && c <= 'z') {
071            return (char) ((int) c + 'A' - 'a');
072        }
073        // code should never reach this point
074        return c;
075    }
076
077    private char toLowerCase(char c) {
078        if ('a' <= c && c <= 'z') {
079            return c;
080        }
081        if ('A' <= c && c <= 'Z') {
082            return (char) ((int) c + 'a' - 'A');
083        }
084        // code should never reach this point
085        return c;
086    }
087
088    private boolean isEnglishLetter(char c) {
089        if ('a' <= c && c <= 'z')
090            return true;
091
092        if ('A' <= c && c <= 'Z')
093            return true;
094        return false;
095    }
096
097    private boolean isUpperCase(char c) {
098        return ('A' <= c && c <= 'Z');
099    }
100}