/*
 * LiquidMetal, version: 0.1 (2009-02-05)
 *
 * A mimetic poly-alloy of Quicksilver's scoring algorithm, essentially
 * LiquidMetal.
 *
 * For usage and examples, visit:
 * http://github.com/rmm5t/liquidmetal
 *
 * Licensed under the MIT:
 * http://www.opensource.org/licenses/mit-license.php
 *
 * Copyright (c) 2009, Ryan McGeary (ryanonjavascript -[at]- mcgeary [*dot*] org)
 * Modified by the Horde Project to use compressibility.
 *
 * @category Horde
 * @package  Core
 */
var LiquidMetal = {

    SCORE_NO_MATCH: 0.0,
    SCORE_MATCH: 1.0,
    SCORE_TRAILING: 0.8,
    SCORE_TRAILING_BUT_STARTED: 0.9,
    SCORE_BUFFER: 0.85,

    score: function(str, abbr)
    {
        // Short circuits
        if (abbr.length == 0) {
           return this.SCORE_TRAILING;
        }
        if (abbr.length > str.length) {
            return this.SCORE_NO_MATCH;
        }

        var scores = this.buildScoreArray(str, abbr),
            sum = 0.0;

        scores.each(function(i) {
            sum += i;
        });

        return (sum / scores.size());
    },

    buildScoreArray: function(str, abbr)
    {
        var lastIndex = -1,
            lower = str.toLowerCase(),
            scores = new Array(str.length),
            started = false;

        abbr.toLowerCase().split("").each(function(c) {
            var index = to = lower.indexOf(c, lastIndex + 1),
                val = this.SCORE_BUFFER;

            if (index < 0) {
                return this.fillArray(scores, this.SCORE_NO_MATCH);
            }

            if (index == 0) {
                started = true;
            }

            if (this.isNewWord(str, index)) {
                scores[index - 1] = 1;
                to = index - 1;
            } else if (!this.isUpperCase(str, index)) {
                val = this.SCORE_NO_MATCH;
            }

            this.fillArray(scores, val, lastIndex + 1, val);

            scores[index] = this.SCORE_MATCH;
            lastIndex = index;
        }.bind(this));

        this.fillArray(scores, started ? this.SCORE_TRAILING_BUT_STARTED : this.SCORE_TRAILING, lastIndex + 1);

        return scores;
    },

    isUpperCase: function(str, index)
    {
        var c = str.charAt(index);
        return ("A" <= c && c <= "Z");
    },

    isNewWord: function(str, index)
    {
        var c = str.charAt(index - 1);
        return (c == " " || c == "\t");
    },

    fillArray: function(arr, value, from, to)
    {
        from = Math.max(from || 0, 0);
        to = Math.min(to || arr.length, arr.length);
        for (var i = from; i < to; ++i) {
            arr[i] = value;
        }
        return arr;
    }
};