001/*
002 * Copyright 2011 Atteo.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
005 * in compliance with the License. You may obtain a copy of the License at
006 *
007 * http://www.apache.org/licenses/LICENSE-2.0
008 *
009 * Unless required by applicable law or agreed to in writing, software distributed under the License
010 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
011 * or implied. See the License for the specific language governing permissions and limitations under
012 * the License.
013 */
014package org.atteo.evo.inflector;
015
016import java.util.ArrayList;
017import java.util.List;
018import java.util.regex.Matcher;
019import java.util.regex.Pattern;
020
021public abstract class TwoFormInflector {
022    private interface Rule {
023        String getPlural(String singular);
024    }
025
026    private static class RegExpRule implements Rule {
027        private final Pattern singular;
028        private final String plural;
029
030        private RegExpRule(Pattern singular, String plural) {
031            this.singular = singular;
032            this.plural = plural;
033        }
034
035        @Override
036        public String getPlural(String word) {
037            StringBuffer buffer = new StringBuffer();
038            Matcher matcher = singular.matcher(word);
039            if (matcher.find()) {
040                matcher.appendReplacement(buffer, plural);
041                matcher.appendTail(buffer);
042                return buffer.toString();
043            }
044            return null;
045        }
046    }
047
048    private static class CategoryRule implements Rule {
049        private final String[] list;
050        private final String singular;
051        private final String plural;
052
053        public CategoryRule(String[] list, String singular, String plural) {
054            this.list = list;
055            this.singular = singular;
056            this.plural = plural;
057        }
058
059        @Override
060        public String getPlural(String word) {
061            String lowerWord = word.toLowerCase();
062            for (String suffix : list) {
063                if (lowerWord.endsWith(suffix)) {
064                    if (!lowerWord.endsWith(singular)) {
065                        throw new RuntimeException("Internal error");
066                    }
067                    return word.substring(0, word.length() - singular.length()) + plural;
068                }
069            }
070            return null;
071        }
072    }
073    
074    private final List<Rule> rules = new ArrayList<Rule>();
075    
076    protected String getPlural(String word) {
077        for (Rule rule : rules) {
078            String result = rule.getPlural(word);
079            if (result != null) {
080                return result;
081            }
082        }
083        return null;
084    }
085    
086    protected void uncountable(String[] list) {
087        rules.add(new CategoryRule(list, "", ""));
088    }
089    
090    protected void irregular(String singular, String plural) {
091        if (singular.charAt(0) == plural.charAt(0)) {
092            rules.add(new RegExpRule(Pattern.compile("(?i)(" + singular.charAt(0) + ")" + singular.substring(1)
093                    + "$"), "$1" + plural.substring(1)));
094        } else {
095            rules.add(new RegExpRule(Pattern.compile(Character.toUpperCase(singular.charAt(0)) + "(?i)"
096                    + singular.substring(1) + "$"), Character.toUpperCase(plural.charAt(0))
097                    + plural.substring(1)));
098            rules.add(new RegExpRule(Pattern.compile(Character.toLowerCase(singular.charAt(0)) + "(?i)"
099                    + singular.substring(1) + "$"), Character.toLowerCase(plural.charAt(0))
100                    + plural.substring(1)));
101        }
102    }
103    
104    protected void irregular(String[][] list) {
105        for (String[] pair : list) {
106            irregular(pair[0], pair[1]);
107        }
108    }
109    
110    protected void rule(String singular, String plural) {
111        rules.add(new RegExpRule(Pattern.compile(singular, Pattern.CASE_INSENSITIVE), plural));
112    }
113    
114    protected void rule(String[][] list) {
115        for (String[] pair : list) {
116            rules.add(new RegExpRule(Pattern.compile(pair[0], Pattern.CASE_INSENSITIVE), pair[1]));
117        }
118    }
119
120    protected void categoryRule(String[] list, String singular, String plural) {
121        rules.add(new CategoryRule(list, singular, plural));
122    }
123}