// requires bsd.js and YUI yahoo, event, and connection

BSD.namespace("utils.currency");

BSD.utils.currency = function(locale_fmt) {
    
    var self = this;
    
    this.locale_fmt = locale_fmt || {};
    
    this.fmt_from_str = function(fmt) {
        // format identical to php's money_format syntax
        // http://us2.php.net/money_format
        
        var result = {};
        
        // ignore leading %
        if(fmt.charAt(0) == "%") {
            fmt = fmt.substr(1);
        }
        
        // get flags
        fmt_loop:
        for(var i=0; i<fmt.length; i++) {
            switch(fmt.charAt(i)) {
                case '=':
                    result.fill_char = fmt.charAt(++i);
                    break;
                case '^':
                    result.grouping = [];
                    result.mon_grouping = [];
                    break;
                case '+':
                    result.p_sign_posn = 1;
                    result.n_sign_posn = 1;
                    break;
                case '(':
                    result.p_sign_posn = 0;
                    result.n_sign_posn = 0;
                    break;
                case '!':
                    result.currency_symbol = "";
                    result.int_currency_symbol = "";
                    break;
                case '-':
                    result.is_left_justified = true;
                    break;
                default:
                    break fmt_loop;
            }
        }
        
        function _num_from_str(str, pos) {
            var num = "";
            while(str.charAt(pos) >= "0" && str.charAt(pos) <= "9") {
                num += str.charAt(pos++);
            }
            return {"pos": pos, "number": new Number(num)};
        }
        
        // get width (if any)
        var parts = _num_from_str(fmt, i);
        i = parts.pos;
        result.width = parts.number;
        
        // get left percision (if any)
        if(fmt.charAt(i) == "#") {
            i++;
            var parts = _num_from_str(fmt, i);
            i = parts.pos;
            result.left_precision = parts.number;
        }
        
        // get right percision (if any)
        if(fmt.charAt(i) == ".") {
            i++;
            var parts = _num_from_str(fmt, i);
            i = parts.pos;
            result.frac_digits = parts.number;
            result.int_frac_digits = parts.number;
        }
        
        switch(fmt.charAt(i)) {
            case "i":
                result.is_international = true;
                break;
            case "n":
                result.is_international = false;
                break;
            case "%":
                result.is_percent_sign = true;
            default:
                // throw error
        }
        
        return result;
    }
    
    this.combine_formats = function() {
        if(arguments.length == 0) {
            return undefined;
        }
        
        var result = arguments[0];
        for(var i=1; i<arguments.length; i++) {
            for(j in arguments[i]) {
                result[j] = arguments[i][j];
            }
        }
        
        return result;
    }
    
    this.format_number = function(number, fmt) {
    
        // TODO:  all formatting regarding percision and alignment
    
        var user_fmt = self.fmt_from_str(fmt);
        var number_fmt = self.combine_formats(self.locale_fmt, user_fmt);
        var p_n = number >= 0 ? "p" : "n";
        var intl = number_fmt.is_international ? "int_" : "";
        
        // for the rare case when the string is %% (an escaped percent sign)
        if(number_fmt.is_percent_sign) {
            return "%";
        }
        
        var money_part = new String(Math.abs(number)).split(".");
        
        // do thousands grouping
        money_part[0] = self.group(money_part[0], number_fmt.mon_thousands_sep, number_fmt.mon_grouping);
        
        // format decimal
        if(money_part.length < 2) {
            money_part.push(0);
        }
        money_part[1] = self.decimal_precision(money_part[1], number_fmt[intl + "frac_digits"]);
        
        // define parts of the final formatted string
        var money = {
            cs: number_fmt.is_international ? number_fmt.int_curr_symbol : number_fmt.currency_symbol,
            sign: number >= 0 ? number_fmt.positive_sign : number_fmt.negative_sign,
            number: money_part.join(number_fmt.mon_decimal_point),
            space: "&nbsp;",
            left_paren: "(",
            right_paren: ")"
        };
        
        // determine ordering of formatted string parts
        var order = ["number"];
        
        // set up the string as if we know the currency symbol (cs) preceeds the number
        if(number_fmt[p_n + "_sep_by_space"]) {
            order.unshift("space");
        }
        order.unshift("cs");
        
        // if the currency symbol (cs) actually is suppose to succeed the number just reverse the array order
        if(!number_fmt[p_n + "_cs_precedes"]) {
            order.reverse;
        }
        
        // handle sign placement
        switch(number_fmt[p_n + "_sign_posn"]) {
            case 0:
                // Parentheses surround the quantity and currency_symbol
                order.unshift("left_paren");
                order.push("right_paren");
                break;
            case 1:
                // The sign string precedes the quantity and currency_symbol
                order.unshift("sign");
                break
            case 2:
                // The sign string succeeds the quantity and currency_symbol
                order.push("sign");
                break;
            case 3:
                // The sign string immediately precedes the currency_symbol
                for(var i in order) {
                    if(order[i] == "cs") {
                        order.splice(i, 0, "sign");
                        break;
                    }
                }
                
                break;
            case 4:
                // The sign string immediately succeeds the currency_symbol
                for(var i in order) {
                    if(order[i] == "cs") {
                        order.splice(i + 1, 0, "sign");
                        break;
                    }
                }
                break;
            default:
                // throw error
        }
        
        // build results from money parts in the order we've compiled
        var result = "";
        for(var i=0; i<order.length; i++) {
            result += money[ order[i] ];
        }
        
        return result;
    }
    
    this.group = function(number, separator, groupings) {
        var str = new String(number);
        var result = "";
        var pos = str.length;
        
        while(pos > 0) {
            if(groupings.length > 0) {
                group_size = groupings.shift();
            }
            if(group_size > 0 && group_size < pos) {
                pos -= group_size;
                result = separator + str.substr(pos, group_size) + result;
            } else {
                result = str.substr(0, pos) + result;
                pos = 0;
            }
        }
        return result;
    }
    
    this.decimal_precision = function(decimal, digits) {
        var str = new String(decimal);
        var rounded = Math.round(new Number(str.substr(0, digits) + '.' + str.substr(digits)));
        var result = new String(rounded);
        while(result.length < digits) {
            result += "0";
        }
        return result;
    }
    
    return this;
}


BSD.namespace("utils.currency_manager");

BSD.utils.currency_manager = {
    currencies : {},
    load_currency: function(intl_currency_symbol, callback) {
        intl_currency_symbol = intl_currency_symbol.toUpperCase();
        if(this.currencies.intl_currency_symbol == undefined) {
            YAHOO.util.Connect.asyncRequest(
                "GET",
                "/utils/currency/currency_data.php?symbol=" + intl_currency_symbol,
                {
                    success: function(o) {
                        BSD.utils.currency_manager.set_currency(o.argument.intl_currency_symbol, Ext.util.JSON.decode(o.responseText));
                        callback.success(o);
                    },
                    failure: function(o) {
                        callback.failure(o);
                    },
                    argument: {user_callback: callback, intl_currency_symbol: intl_currency_symbol}
                }
            );
        }
    },
    set_currency: function(intl_currency_symbol, data) {
        this.currencies[intl_currency_symbol] = data;
    },
    get_currency: function(intl_currency_symbol) {
        return this.currencies[intl_currency_symbol];
    }
};
