/**
 * addEvent written by Dean Edwards, 2005
 * with input from Tino Zijdel
 *
 * http://dean.edwards.name/weblog/2005/10/add-event/
 **/
function addEvent(element, type, handler) {
    // assign each event handler a unique ID
    if (!handler.$$guid) handler.$$guid = addEvent.guid++;
    // create a hash table of event types for the element
    if (!element.events) element.events = {};
    // create a hash table of event handlers for each element/event pair
    var handlers = element.events[type];
    if (!handlers) {
        handlers = element.events[type] = {};
        // store the existing event handler (if there is one)
        if (element["on" + type]) {
            handlers[0] = element["on" + type];
        }
    }
    // store the event handler in the hash table
    handlers[handler.$$guid] = handler;
    // assign a global event handler to do all the work
    element["on" + type] = handleEvent;
};
// a counter used to create unique IDs
addEvent.guid = 1;

function removeEvent(element, type, handler) {
    // delete the event handler from the hash table
    if (element.events && element.events[type]) {
        delete element.events[type][handler.$$guid];
    }
};

function handleEvent(event) {
    var returnValue = true;
    // grab the event object (IE uses a global event object)
    event = event || fixEvent(window.event);
    // get a reference to the hash table of event handlers
    var handlers = this.events[event.type];
    // execute each event handler
    for (var i in handlers) {
        this.$$handleEvent = handlers[i];
        if (this.$$handleEvent(event) === false) {
            returnValue = false;
        }
    }
    return returnValue;
};

function fixEvent(event) {
    // add W3C standard event methods
    event.preventDefault = fixEvent.preventDefault;
    event.stopPropagation = fixEvent.stopPropagation;
    return event;
};
fixEvent.preventDefault = function () {
    this.returnValue = false;
};
fixEvent.stopPropagation = function () {
    this.cancelBubble = true;
};

// end from Dean Edwards

/**
 * Creates an Element for insertion into the DOM tree.
 * From http://simon.incutio.com/archive/2003/06/15/javascriptWithXML
 *
 * @param element the element type to be created.
 *              e.g. ul (no angle brackets)
 **/
function createElement(element) {
    if (typeof document.createElementNS != 'undefined') {
        return document.createElementNS('http://www.w3.org/1999/xhtml', element);
    }
    if (typeof document.createElement != 'undefined') {
        return document.createElement(element);
    }
    return false;
}

/**
 * "targ" is the element which caused this function to be called
 * from http://www.quirksmode.org/js/events_properties.html
 **/
function getEventTarget(e) {
    var targ;
    if (!e) {
        e = window.event;
    }
    if (e.target) {
        targ = e.target;
    } else if (e.srcElement) {
        targ = e.srcElement;
    }
    if (targ.nodeType == 3) { // defeat Safari bug
        targ = targ.parentNode;
    }

    return targ;
}

/*
 * Functions used for creating, reading and deleting cookies on javascript
 **/

function createCookie(name, value, days) {
    if (days) {
        var date = new Date();
        date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000));
        var expires = "; expires=" + date.toGMTString();
    } else
    var expires = "";
    document.cookie = name + "=" + value + expires + "; path=/";
}

function readCookie(name) {
    var nameEQ = name + "=";
    var ca = document.cookie.split(';');
    for (var i = 0; i < ca.length; i++) {
        var c = ca[i];
        while (c.charAt(0) == ' ') c = c.substring(1, c.length);
        if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length, c.length);
    }
    return null;
}

function eraseCookie(name) {
    createCookie(name, "", -1);
}

jQuery.fn.dataTableExt.oSort['id-numeric-asc'] = function (a, b) {
    var x = a.match(/id="*(-?[0-9]+)/)[1];
    var y = b.match(/id="*(-?[0-9]+)/)[1];
    x = parseFloat(x);
    y = parseFloat(y);
    return ((x < y) ? -1 : ((x > y) ? 1 : 0));
};

jQuery.fn.dataTableExt.oSort['id-numeric-desc'] = function (a, b) {
    var x = a.match(/id="*(-?[0-9]+)/)[1];
    var y = b.match(/id="*(-?[0-9]+)/)[1];
    x = parseFloat(x);
    y = parseFloat(y);
    return ((x < y) ? 1 : ((x > y) ? -1 : 0));
};

jQuery.fn.dataTableExt.oSort['id-alpha-asc'] = function (a, b) {
    var x = a.match(/id="(.*?)"/)[1].toLowerCase();
    var y = b.match(/id="(.*?)"/)[1].toLowerCase();
    return x.localeCompare(y);
};

jQuery.fn.dataTableExt.oSort['id-alpha-desc'] = function (a, b) {
    var x = a.match(/id="(.*?)"/)[1].toLowerCase();
    var y = b.match(/id="(.*?)"/)[1].toLowerCase();
    return y.localeCompare(x);
};

jQuery.fn.dataTableExt.oSort['numeric-comma-asc'] = function (a, b) {
    var x = (a == "-") ? 0 : a.replace(/,/, ".");
    var y = (b == "-") ? 0 : b.replace(/,/, ".");
    x = parseFloat(x);
    y = parseFloat(y);
    return ((x < y) ? -1 : ((x > y) ? 1 : 0));
};

jQuery.fn.dataTableExt.oSort['numeric-comma-desc'] = function (a, b) {
    var x = (a == "-") ? 0 : a.replace(/,/, ".");
    var y = (b == "-") ? 0 : b.replace(/,/, ".");
    x = parseFloat(x);
    y = parseFloat(y);
    return ((x < y) ? 1 : ((x > y) ? -1 : 0));
};

function strftime(fmt, timestamp) {
    // http://kevin.vanzonneveld.net
    // +      original by: Blues (http://tech.bluesmoon.info/)
    // + reimplemented by: Brett Zamir (http://brett-zamir.me)
    // +   input by: Alex
    // +   bugfixed by: Brett Zamir (http://brett-zamir.me)
    // +   improved by: Brett Zamir (http://brett-zamir.me)
    // -       depends on: setlocale
    // %        note 1: Uses global: php_js to store locale info
    // *        example 1: strftime("%A", 1062462400); // Return value will depend on date and locale
    // *        returns 1: 'Tuesday'
    // BEGIN STATIC
    var _xPad = function (x, pad, r) {
            if (typeof r === 'undefined') {
                r = 10;
            }
            for (; parseInt(x, 10) < r && r > 1; r /= 10) {
                x = pad.toString() + x;
            }
            return x.toString();
        };

    var _formats = {
            a: function (d) {
                return lc_time.a[d.getDay()];
            },
            A: function (d) {
                return lc_time.A[d.getDay()];
            },
            b: function (d) {
                return lc_time.b[d.getMonth()];
            },
            B: function (d) {
                return lc_time.B[d.getMonth()];
            },
            C: function (d) {
                return _xPad(parseInt(d.getFullYear() / 100, 10), 0);
            },
            d: ['getDate', '0'],
            e: ['getDate', ' '],
            g: function (d) {
                return _xPad(parseInt(this.G(d) / 100, 10), 0);
            },
            G: function (d) {
                var y = d.getFullYear();
                var V = parseInt(_formats.V(d), 10);
                var W = parseInt(_formats.W(d), 10);

                if (W > V) {
                    y++;
                } else if (W === 0 && V >= 52) {
                    y--;
                }

                return y;
            },
            H: ['getHours', '0'],
            I: function (d) {
                var I = d.getHours() % 12;
                return _xPad(I === 0 ? 12 : I,
                0);
            },
            j: function (d) {
                var ms = d - new Date('' + d.getFullYear() + '/1/1 GMT');
                ms += d.getTimezoneOffset() * 60000; // Line differs from Yahoo implementation which would be equivalent to replacing it here with:
                // ms = new Date('' + d.getFullYear() + '/' + (d.getMonth()+1) + '/' + d.getDate() + ' GMT') - ms;
                var doy = parseInt(ms / 60000 / 60 / 24, 10) + 1;
                return _xPad(doy, 0, 100);
            },
            k: ['getHours', '0'],
            // not in PHP, but implemented here (as in Yahoo)
            l: function (d) {
                var l = d.getHours() % 12;
                return _xPad(l === 0 ? 12 : l,
                ' ');
            },
            m: function (d) {
                return _xPad(d.getMonth() + 1, 0);
            },
            M: ['getMinutes', '0'],
            p: function (d) {
                return lc_time.p[d.getHours() >= 12 ? 1 : 0];
            },
            P: function (d) {
                return lc_time.P[d.getHours() >= 12 ? 1 : 0];
            },
            s: function (d) { // Yahoo uses return parseInt(d.getTime()/1000, 10);
                return Date.parse(d) / 1000;
            },
            S: ['getSeconds', '0'],
            u: function (d) {
                var dow = d.getDay();
                return ((dow === 0) ? 7 : dow);
            },
            U: function (d) {
                var doy = parseInt(_formats.j(d), 10);
                var rdow = 6 - d.getDay();
                var woy = parseInt((doy + rdow) / 7, 10);
                return _xPad(woy, 0);
            },
            V: function (d) {
                var woy = parseInt(_formats.W(d), 10);
                var dow1_1 = (new Date('' + d.getFullYear() + '/1/1')).getDay();
                // First week is 01 and not 00 as in the case of %U and %W,
                // so we add 1 to the final result except if day 1 of the year
                // is a Monday (then %W returns 01).
                // We also need to subtract 1 if the day 1 of the year is
                // Friday-Sunday, so the resulting equation becomes:
                var idow = woy + (dow1_1 > 4 || dow1_1 <= 1 ? 0 : 1);
                if (idow === 53 && (new Date('' + d.getFullYear() + '/12/31')).getDay() < 4) {
                    idow = 1;
                } else if (idow === 0) {
                    idow = _formats.V(new Date('' + (d.getFullYear() - 1) + '/12/31'));
                }
                return _xPad(idow, 0);
            },
            w: 'getDay',
            W: function (d) {
                var doy = parseInt(_formats.j(d), 10);
                var rdow = 7 - _formats.u(d);
                var woy = parseInt((doy + rdow) / 7, 10);
                return _xPad(woy, 0, 10);
            },
            y: function (d) {
                return _xPad(d.getFullYear() % 100, 0);
            },
            Y: 'getFullYear',
            z: function (d) {
                var o = d.getTimezoneOffset();
                var H = _xPad(parseInt(Math.abs(o / 60), 10), 0);
                var M = _xPad(o % 60, 0);
                return (o > 0 ? '-' : '+') + H + M;
            },
            Z: function (d) {
                return d.toString().replace(/^.*\(([^)]+)\)$/, '$1');
                /*
                 // Yahoo's: Better?
                 var tz = d.toString().replace(/^.*:\d\d( GMT[+-]\d+)? \(?([A-Za-z ]+)\)?\d*$/, '$2').replace(/[a-z ]/g, '');
                 if(tz.length > 4) {
                 tz = Dt.formats.z(d);
                 }
                 return tz;
                 */
            },
            '%': function (d) {
                return '%';
            }
        };

    var _date = ((typeof (timestamp) == 'undefined') ? new Date() : // Not provided
        (typeof (timestamp) == 'object') ? new Date(timestamp) : // Javascript Date()
        new Date(timestamp * 1000) // PHP API expects UNIX timestamp (auto-convert to int)
        );

    var _aggregates = {
            c: 'locale',
            D: '%m/%d/%y',
            F: '%y-%m-%d',
            h: '%b',
            n: '\n',
            r: 'locale',
            R: '%H:%M',
            t: '\t',
            T: '%H:%M:%S',
            x: 'locale',
            X: 'locale'
        };

    // First replace aggregates (run in a loop because an agg may be made up of other aggs)
    while (fmt.match(/%[cDFhnrRtTxX]/)) {
        fmt = fmt.replace(/%([cDFhnrRtTxX])/g, function (m0, m1) {
            var f = _aggregates[m1];
            return (f === 'locale' ? lc_time[m1] : f);
        });
    }

    // Now replace formats - we need a closure so that the date object gets passed through
    var str = fmt.replace(/%([aAbBCdegGHIjklmMpPsSuUVwWyYzZ%])/g, function (m0, m1) {
            var f = _formats[m1];
            if (typeof f === 'string') {
                return _date[f]();
            } else if (typeof f === 'function') {
                return f(_date);
            } else if (typeof f === 'object' && typeof (f[0]) === 'string') {
                return _xPad(_date[f[0]](), f[1]);
            } else { // Shouldn't reach here
                return m1;
            }
        });
    return str;
}

function number_format(number, decimals, dec_point, thousands_sep) {
    if (typeof decimalComma != 'undefined') {
        dec_point = ','
        thousands_sep = '.'
    } else {
        dec_point = '.'
        thousands_sep = ','
    }
    // http://kevin.vanzonneveld.net
    // + original by: Jonas Raoni Soares Silva (http://www.jsfromhell.com)
    // + improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
    // + bugfix by: Michael White (http://getsprink.com)
    // + bugfix by: Benjamin Lupton
    // + bugfix by: Allan Jensen (http://www.winternet.no)
    // + revised by: Jonas Raoni Soares Silva (http://www.jsfromhell.com)
    // + bugfix by: Howard Yeend
    // + revised by: Luke Smith (http://lucassmith.name)
    // + bugfix by: Diogo Resende
    // + bugfix by: Rival
    // + input by: Kheang Hok Chin (http://www.distantia.ca/)
    // + improved by: davook
    // + improved by: Brett Zamir (http://brett-zamir.me)
    // + input by: Jay Klehr
    // + improved by: Brett Zamir (http://brett-zamir.me)
    // + input by: Amir Habibi (http://www.residence-mixte.com/)
    // + bugfix by: Brett Zamir (http://brett-zamir.me)
    // + improved by: Theriault
    // + input by: Amirouche
    // + improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
    // * example 1: number_format(1234.56);
    // * returns 1: '1,235'
    // * example 2: number_format(1234.56, 2, ',', ' ');
    // * returns 2: '1 234,56'
    // * example 3: number_format(1234.5678, 2, '.', '');
    // * returns 3: '1234.57'
    // * example 4: number_format(67, 2, ',', '.');
    // * returns 4: '67,00'
    // * example 5: number_format(1000);
    // * returns 5: '1,000'
    // * example 6: number_format(67.311, 2);
    // * returns 6: '67.31'
    // * example 7: number_format(1000.55, 1);
    // * returns 7: '1,000.6'
    // * example 8: number_format(67000, 5, ',', '.');
    // * returns 8: '67.000,00000'
    // * example 9: number_format(0.9, 0);
    // * returns 9: '1'
    // * example 10: number_format('1.20', 2);
    // * returns 10: '1.20'
    // * example 11: number_format('1.20', 4);
    // * returns 11: '1.2000'
    // * example 12: number_format('1.2000', 3);
    // * returns 12: '1.200'
    // * example 13: number_format('1 000,50', 2, '.', ' ');
    // * returns 13: '100 050.00'
    // Strip all characters but numerical ones.
    number = (number + '').replace(/[^0-9+\-Ee.]/g, '');
    var n = !isFinite(+number) ? 0 : +number,
        prec = !isFinite(+decimals) ? 0 : Math.abs(decimals),
        sep = (typeof thousands_sep === 'undefined') ? ',' : thousands_sep,
        dec = (typeof dec_point === 'undefined') ? '.' : dec_point,
        s = '',
        toFixedFix = function (n, prec) {
            var k = Math.pow(10, prec);
            return '' + Math.round(n * k) / k;
        };
    // Fix for IE parseFloat(0.55).toFixed(0) = 0;
    s = (prec ? toFixedFix(n, prec) : '' + Math.round(n)).split('.');
    if (s[0].length > 3) {
        s[0] = s[0].replace(/\B(?=(?:\d{3})+(?!\d))/g, sep);
    }
    if ((s[1] || '').length < prec) {
        s[1] = s[1] || '';
        s[1] += new Array(prec - s[1].length + 1).join('0');
    }
    return s.join(dec);
}

(function ($) {

    $.fn.priceFormat = function (options) {

        var defaults = {
                prefix: 'US$ ',
                centsSeparator: '.',
                thousandsSeparator: ',',
                limit: false,
                centsLimit: 2,
                clearPrefix: false,
                allowNegative: false
            };

        var options = $.extend(defaults, options);

        return this.each(function () {

            // pre defined options
            var obj = $(this);
            var is_number = /[0-9]/;

            // load the pluggings settings
            var prefix = options.prefix;
            var centsSeparator = options.centsSeparator;
            var thousandsSeparator = options.thousandsSeparator;
            var limit = options.limit;
            var centsLimit = options.centsLimit;
            var clearPrefix = options.clearPrefix;
            var allowNegative = options.allowNegative;

            // skip everything that isn't a number
            // and also skip the left zeroes
            function to_numbers(str) {
                var formatted = '';
                for (var i = 0; i < (str.length); i++) {
                    char = str.charAt(i);
                    if (formatted.length == 0 && char == 0) char = false;

                    if (char && char.match(is_number)) {
                        if (limit) {
                            if (formatted.length < limit) formatted = formatted + char;
                        } else {
                            formatted = formatted + char;
                        }
                    }
                }

                return formatted;
            }

            // format to fill with zeros to complete cents chars
            function fill_with_zeroes(str) {
                while (str.length < (centsLimit + 1)) str = '0' + str;
                return str;
            }

            // format as price
            function price_format(str) {
                // formatting settings
                var formatted = fill_with_zeroes(to_numbers(str));
                var thousandsFormatted = '';
                var thousandsCount = 0;

                // split integer from cents
                var centsVal = formatted.substr(formatted.length - centsLimit, centsLimit);
                var integerVal = formatted.substr(0, formatted.length - centsLimit);

                // apply cents pontuation
                formatted = integerVal + centsSeparator + centsVal;

                // apply thousands pontuation
                if (thousandsSeparator) {
                    for (var j = integerVal.length; j > 0; j--) {
                        char = integerVal.substr(j - 1, 1);
                        thousandsCount++;
                        if (thousandsCount % 3 == 0) char = thousandsSeparator + char;
                        thousandsFormatted = char + thousandsFormatted;
                    }
                    if (thousandsFormatted.substr(0, 1) == thousandsSeparator) thousandsFormatted = thousandsFormatted.substring(1, thousandsFormatted.length);
                    formatted = thousandsFormatted + centsSeparator + centsVal;
                }

                // if the string contains a dash, it is negative - add it to the begining (except for zero)
                if (allowNegative && str.indexOf('-') != -1 && (integerVal != 0 || centsVal != 0)) formatted = '-' + formatted;

                // apply the prefix
                if (prefix) formatted = prefix + formatted;

                return formatted;
            }

            // filter what user type (only numbers and functional keys)
            function key_check(e) {
                var code = (e.keyCode ? e.keyCode : e.which);
                var typed = String.fromCharCode(code);
                var functional = false;
                var str = obj.val();
                var newValue = price_format(str + typed);

                // allow key numbers, 0 to 9
                if ((code >= 48 && code <= 57) || (code >= 96 && code <= 105)) functional = true;

                // check Backspace, Tab, Enter, Delete, and left/right arrows
                if (code == 8) functional = true;
                if (code == 9) functional = true;
                if (code == 13) functional = true;
                if (code == 46) functional = true;
                if (code == 37) functional = true;
                if (code == 39) functional = true;
                if (allowNegative && (code == 189 || code == 109)) functional = true; // dash as well
                if (!functional) {
                    e.preventDefault();
                    e.stopPropagation();
                    if (str != newValue) obj.val(newValue);
                }

            }

            // inster formatted price as a value of an input field
            function price_it() {
                var str = obj.val();
                var price = price_format(str);
                if (str != price) obj.val(price);
            }

            // Add prefix on focus
            function add_prefix() {
                var val = obj.val();
                obj.val(prefix + val);
            }

            // Clear prefix on blur if is set to true
            function clear_prefix() {
                if ($.trim(prefix) != '' && clearPrefix) {
                    var array = obj.val().split(prefix);
                    obj.val(array[1]);
                }
            }

            // bind the actions
            $(this).bind('keydown', key_check);
            $(this).bind('keyup', price_it);

            // Clear Prefix and Add Prefix
            if (clearPrefix) {
                $(this).bind('focusout', function () {
                    clear_prefix();
                });

                $(this).bind('focusin', function () {
                    add_prefix();
                });
            }

            // If value has content
            if ($(this).val().length > 0) {
                price_it();
                clear_prefix();
            }

        });

    };

})(jQuery);
