/* UDF: f_format_number.sql

Purpose: Provides a simple, non-locale aware way to format a number with user defined  thousands and decimal separator.

2015-11-9: written by sdia

*/


CREATE OR REPLACE FUNCTION f_format_number(value FLOAT, group_sep VARCHAR, decimal_sep VARCHAR,
       group_length INT, prec INT, sign BOOL)

RETURNS VARCHAR IMMUTABLE
AS $$
    from collections import deque
    from math import modf

    def int_grouper_as_string(int_value, group_sep, group_length):
        d = deque(str(int(int_value)))
        grouped = []
        c = 0
        while True:
            try:
                x = d.pop()
            except IndexError:
                break
            if c and not c % group_length:
                grouped.append(group_sep)
            c += 1
            grouped.append(x)
        grouped.reverse()
        return ''.join(grouped)


    def get_decimal_as_string(fract_value, precision):
        if precision > 0:
            prec_string = '{{0:.{precision}f}}'.format(precision=precision)
            fract_string = prec_string.format(fract_value)
            return fract_string.split('.')[-1]
        else:
            return ''


    def f_format_number(value, group_sep=',', decimal_sep='.', group_length=3,
                        precision=2, sign=False):
        if value is None:
            return None
        try:
            value_float = float(value)
        except ValueError, e:
            print('A problem occured with formatting, numeric value was expected.')
            raise(e)
        try:
            assert decimal_sep != group_sep
        except AssertionError, e:
            print('A problem occured with formatting, group and decimal separators should not be equal!')
            raise(e)

        if value < 0:
            sign_symbol = '-'
        elif sign:
            sign_symbol = '+'
        else:
            sign_symbol = ''

        fract_part, int_part = modf(abs(value_float))
        int_group = int_grouper_as_string(int_part, group_sep, group_length)
        dec = get_decimal_as_string(fract_part, prec)

        res = sign_symbol+int_group

        if dec != '':
            res += decimal_sep+dec

        return res


    return f_format_number(value, group_sep, decimal_sep, group_length,
    	   prec, sign)

$$ LANGUAGE plpythonu;
