/*
 * Copyright 2006-2007 Queplix Corp.
 *
 * Licensed under the Queplix Public License, Version 1.1.1 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.queplix.com/solutions/commercial-open-source/queplix-public-license/
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 *
 */

package com.queplix.core.utils;

/**
 * Encodes words using the soundex phonetic algorithm.
 */
public class Soundex {

    // Private Fields
    // ----------------

    /**
     * Length of code to build.
     */
    private static int LengthInt = 4;


    /**
     * Soundex code table.
     */
    private final static int[] SoundexInts = createArray();

    // Public Methods
    // --------------

    /**
     * Returns the soundex code for the specified word.
     *
     * @param string The word to encode.
     */
    public static String getSoundex(String word) {
        return encode(word);
    }

    /**
     * Returns the soundex code for the specified word.
     *
     * @param string The word to encode.
     * @param int    The Length of code to build.
     */
    public static String getSoundex(String word, int length) {
        if(length > 0) {
            LengthInt = length;
        }
        return encode(word);
    }

    /**
     * Returns the soundex code for the specified word.
     *
     * @param string The word to encode.
     */
    private final static String encode(String word) {
        word = word.trim();
        word = reduce(word);
        int wordLength = word.length(); //original word size
        int sofar = 0; //how many codes have been created
        int max = LengthInt - 1; //max codes to create (less the first char)
        if(LengthInt < 0) //if NO_MAX
        {
            max = wordLength; //wordLength was the max possible size.
        }
        int code = 0;
        StringBuffer buf = new StringBuffer(max);
        buf.append(Character.toLowerCase(word.charAt(0)));
        for(int i = 1; (i < wordLength) && (sofar < max); i++) {
            code = getCode(word.charAt(i));
            if(code > 0) {
                buf.append(code);
                sofar++;
            }
        }
        if(LengthInt > 0) {
            for(; sofar < max; sofar++) {
                buf.append('0');
            }
        }
        return buf.toString().toUpperCase();
    }

    // Private Methods
    // -----------------

    /**
     * Returns the Soundex code for the specified character.
     *
     * @param ch Should be between A-Z or a-z
     * @return -1 if the character has no phonetic code.
     */
    private final static int getCode(char ch) {
        int arrayidx = -1;
        if(('a' <= ch) && (ch <= 'z')) {
            arrayidx = (int) ch - (int) 'a';
        } else if(('A' <= ch) && (ch <= 'Z')) {
            arrayidx = (int) ch - (int) 'A';
        }
        if((arrayidx >= 0) && (arrayidx < SoundexInts.length)) {
            return SoundexInts[arrayidx];
        } else {
            return -1;
        }
    }

    /**
     * Creates the Soundex code table.
     */
    private final static int[] createArray() {
        return new int[]{
                -1,
                //a
                1,
                //b
                2,
                //c
                3,
                //d
                -1,
                //e
                1,
                //f
                2,
                //g
                -1,
                //h
                -1,
                //i
                2,
                //j
                2,
                //k
                4,
                //l
                5,
                //m
                5,
                //n
                -1,
                //o
                1,
                //p
                2,
                //q
                6,
                //r
                2,
                //s
                3,
                //t
                -1,
                //u
                1,
                //v
                -1,
                //w
                2,
                //x
                -1,
                //y
                2
                //z
        };
    }

    /**
     * Removes adjacent sounds.
     */
    private final static String reduce(String word) {
        int len = word.length();
        StringBuffer buf = new StringBuffer(len);
        char ch = word.charAt(0);
        int currentCode = getCode(ch);
        buf.append(ch);
        int lastCode = currentCode;
        for(int i = 1; i < len; i++) {
            ch = word.charAt(i);
            currentCode = getCode(ch);
            if((currentCode != lastCode) && (currentCode >= 0)) {
                buf.append(ch);
                lastCode = currentCode;
            }
        }
        return buf.toString();
   }


 }//Soundex
