var chart_util = {
    abbreviate_number: function(number) {
        var n = parseFloat(number, 10), unit = '';
        if (n >= 1000000) {
            n = n/1000000;
            unit = 'M';
        } else if (n >= 1000) {
            n = n/1000;
            unit = 'K';
        }
        return [mp.utility.floatformat(n, 2), unit];
    },
    parse_date: function(datestring) {
        // Expects a datetime string formatted 
        // YYYY-MM-DD HH:MM:SS where the time elements are optional.
        if (typeof(datestring) == "string") {
            var t = datestring.split(' ');
            var result = {year: '', month: '', day: '', hour: '', minute: '', second: ''};
            if (t.length > 1) {
                // We have time elements as well
                var time = t[1].split(":");
                result.hour = (time[0]) ? time[0] : '';
                result.minute = (time[1]) ? time[1] : '';
                result.second = (time[2]) ? time[2] : '';
                t = t[0];
            } else {
                t = t[0];
            }
            t = t.split("-");
            result.year = (t[0]) ? t[0] : '';
            // Month is 0 - 11
            result.month = (t[1]) ? parseInt(t[1], 10) - 1 : '';
            result.day = (t[2]) ? t[2] : '';
            return Date.UTC(result.year, result.month, result.day, result.hour, result.minute, result.second);
        } else {
            return null;
        }
    },
    format_retention_date: function(ms, unit) {
        // Convert milliseconds from parsed string into a Date object
        var date = new Date();
        date.setTime(ms);
        var offset = date.getUTCOffset();
        offset = parseInt(offset, 10) / 100;
        date = date.addHours(offset * -1);
        
        var first = "MMM d", second = "MMM d, yyyy", date2 = date.clone();
        var formatted = '';
        switch(unit) {
            case 'day':
                formatted = date.toString(second);
                break;
            case 'week':
                date2.addWeeks(1).addDays(-1);
                formatted = date.toString(first) + " - " + date2.toString(second);
                break;
            case 'month':
                date2.addMonths(1).addDays(-1);
                formatted = date.toString(first) + " - " + date2.toString(second);
        }
        return formatted;
    },
    add_units_to_date: function(day, num_units, unit) {
        var previous = new Date(day);
        switch (unit) {
            case 'day':
                previous.addDays(num_units);
                break;
            case 'week':
                previous.addWeeks(num_units);
                break;
            case 'month':
                previous.addMonths(num_units);
                break;
        }
        return previous;
    },
    add_zeros: function(data, categories, params) {
        // find earliest date
        var days = {};
        var earliest = categories[0];
        for (var i = 0; i < categories.length; i++) {
            days[categories[i]] = true;
            if (categories[i] < earliest) {
                earliest = categories[i];
            }
        }
        var previous = earliest = Date.parseExact(earliest, 'yyyy-MM-dd');
        var from_date = Date.parseExact(params.from_date, 'yyyy-MM-dd');
        var to_date = Date.parseExact(params.to_date, 'yyyy-MM-dd');
        while (previous >= from_date) {
            earliest = previous;
            previous = chart_util.add_units_to_date(previous, -1, params.unit);
        }
        // find missing values
        while (earliest <= to_date) {
            var text = earliest.toString('yyyy-MM-dd');
            if (!(text in days)) {
                categories.push(text);
                data.push([text, 0]);
            }
            earliest = chart_util.add_units_to_date(earliest, 1, params.unit);
        }
    }
};

function Chart() {
    // Basic line chart -- datetime
    this.chart_type = 'line';
    this.chart_params = {
        chart: {
            zoomType: 'x',
            margin: [10, 200, 25, 55],
            style: {
                zIndex: 1
            }
        },
        xAxis: {
            type: 'datetime',
            title: {
                text: null
            },
            labels: {},
            showLastLabel: true
        },
        yAxis: {
            title: {
                enabled: false
            },
            min: 0,
            labels: {
                formatter: function() {
                    var n = chart_util.abbreviate_number(this.value);
                    return n.join('');
                }
            }
        },
        tooltip: {},
        legend: {
            layout: 'vertical',
            style: {
                left: 'auto',
                bottom: 'auto',
                right: '5px',
                top: '5px'
            },
            labelFormatter: function() {
                var sanitized = mp.utility.sanitize(this.name);
                var shortened =  mp.utility.shorten_string(sanitized, 20);
                var label = '<span title="' + sanitized + '">' + shortened + '</span>';
                return label;
            }
        },
        plotOptions: {
            line: {
                marker: {
                    enabled: true
                },
                shadow: false,
                states: {
                    hover: {
                        marker: {
                            enabled: true
                        },
                        lineWidth: 2
                    }
                }
            }
        },
        credits: {
            enabled: false
        },
        series: [],
        title: {
            style: {
                display: 'none',
                margin: '0px'
            }
        }
    };
    this.events = [];
}

Chart.prototype.set_chart_params = function(params) {
    var chart_params = {
        xAxis: {
            labels: {
                formatter: function() {
                    var d = '';
                    if (params.unit == 'hour') {
                        d = Highcharts.dateFormat("%m/%e %l%P", this.value);
                    } else {
                        d = Highcharts.dateFormat("%b. %e", this.value);
                    }
                    return d;
                }
            }
        },
        tooltip: {
            formatter: function() {
                var n = mp.utility.commaize(mp.utility.floatformat(this.y, 2)), date;
                if (params.unit == 'hour') {
                    date = Highcharts.dateFormat("%b. %e, %Y %l%P:<br />", this.x);
                } else {
                    date = Highcharts.dateFormat("%b. %e, %Y: ", this.x);
                }
                return '<b>'+ mp.utility.sanitize(this.point.name || this.series.name) +'</b><br/>'+
                    date + n;
            }
        }
    };
    
    this.chart_params = $.extend(true, {}, this.chart_params, chart_params);
};

Chart.prototype.create = function(container, info, params, format) {
    if (!format) { 
        format = 'json'; 
    }
    this.container = container;
    this.chart_params.chart.renderTo = container;

    this.params = params;
    
    this.set_chart_params(params);

    var that = this, 
        endpoint = params.endpoint, 
        service = params.service;
        
    delete params.endpoint;
    delete params.service;
    
    this.get_data(endpoint, params, 
        function(data) {
            that.set_title(info.title, info.subtitle);
            that.render(that.format(data));
        },
        format, service
    );
};

Chart.prototype.render = function(formatted_data) {
    var that = this;
    var set_ticks = function(formatted_data) {
        // XXX: Hack: prevents tick mark interpolation, but there must be a better way.
        // UPDATE: Highcharts support says this is the best way, but I still don't like it.
        var intervals = {'day': 86400000, 'week': 604800000 }, ticks = 0, first = Infinity, last = 0;
        var tickinterval = intervals[that.params.unit];
        for (var ev in formatted_data) {
            if (formatted_data[ev].length) {
                if (formatted_data[ev].length > ticks) {
                    ticks = formatted_data[ev].length; 
                }
                var first_item = formatted_data[ev][0];
                var last_item = formatted_data[ev][formatted_data[ev].length - 1];
                if (first_item.length && (first_item[0] < first)) {
                    first = first_item[0];
                }
                if (last_item.length && (last_item[0] > last)) {
                    last = last_item[0];
                }
            }
        }
        if (ticks < 12 && ((last - first) / tickinterval < 12)) {
            if (!that.chart_params.xAxis) {
                that.chart_params.xAxis = {};
            }
            that.chart_params.xAxis.tickInterval = tickinterval;
        }
    };
    for (var e in this.events) {
        if (e) {
            var ev = this.events[e];
            this.chart_params.series.push({
                type: this.chart_type,
                name: ev,
                data: formatted_data[ev]
            });
        }
    }
    set_ticks(formatted_data);
    // Loading chart!
    if (this.chart_params.series.length && this.chart_params.series[0].data.length) {
        var c = new Highcharts.Chart(this.chart_params);
    } else {
        var notice = "Sorry, we don't have any data for this time period yet.  Please try again later.";
        var ep = that.params.endpoint;
        if ( ep == 'unique' || ep == 'average') {
            notice += "<p>You might not be tracking Unique visitors.  Try switching to Total visitors in the menu above.";
        }
        $('#' + this.chart_params.chart.renderTo).html('<div class="nodata">' + notice + '</div>');
    }
};

Chart.prototype.set_title = function(title, subtitle) {
    if (title) { 
        $("#graph_title h1").html(mp.utility.sanitize(title));
    }
    if (subtitle) {
        $("#graph_description").html(mp.utility.sanitize(subtitle));
    }
};

Chart.prototype.format = function(data) {
    var json = data.data;
    
    if (json !== undefined) {
        // Sort & store event names - this will give us the same event with the same color 
        // on all charts.
        var events = [], lines = {};
        for (var event_name in json.values) {
            if (event_name) {
                events[events.length] = event_name;
            }
        }
        events.sort();
        this.events = events;
        // Chart data object - will hold formatted results
    
        var cdata = {};
        for (var e in events) {
            if (e) {
                var ev = json.values[events[e]];         
                cdata[events[e]] = [];
                var found = 0;
                for (var date in json.series) {
                    if (date) {
                        date = json.series[date];
                        if (date) {
                            var amt = 0;
                            if (ev && ev[date]) {
                                amt = ev[date];
                                // Flag for first viable date
                                found = 1;
                            }
                            if (found) {
                                // Only push zero'd points if it is not the first one.
                                // (still push others)
                                cdata[events[e]].push([chart_util.parse_date(date), amt]);
                            }
                        }
                    }
                }
                cdata[events[e]].sort();
            }
        }
        return cdata;
    }
};

Chart.prototype.get_data = function(endpoint, params, callback, format, service) {
    if (! service) { service = 'events'; }
    if (mp.report.globals.api_sig) { params.api_sig = mp.report.globals.api_sig; }
    params.format = (format) ? format : 'json';
    for (var key in params) {
        if (params[key].constructor == Array) {
            params[key] = $.toJSON(params[key]);
        }
    }
    var url = mp.globals.domain + '/api/2.0/' + service + '/';
    if (endpoint) { url += endpoint; }
    $.getJSON(
        url,
        params,
        function(data) {
            callback(data);
        }
    );
};

// Funnel charts
function ChartFunnel() {
    
    chart_funnel = new Chart();
    // Basic line chart -- datetime
    chart_funnel.chart_type = 'line';
    
    chart_funnel.set_chart_params = function(params) {
        var chart_params = {
            chart: {
                zoomType: 'x',
                margin: [40, 20, 40, 50],
                style: {
                    zIndex: 1
                }
            },

            tooltip: {
                formatter: function() {
                    var n = mp.utility.commaize(mp.utility.floatformat(this.y, 2)), 
                        date = Highcharts.dateFormat("%b. %e, %Y: ", this.x);
                    return date + "<b>" + n + "%</b>";
                }
            },
            legend: {
                enabled: false
            },
            plotOptions: {
                line: {
                    marker: {
                        enabled: true
                    },
                    shadow: false,
                    states: {
                        hover: {
                            marker: {
                                enabled: true
                            },
                            lineWidth: 2
                        }
                    }
                }
            },
            credits: {
                enabled: false
            },
            series: []
        };
        chart_funnel.chart_params = $.extend(true, {}, chart_funnel.chart_params, chart_params);

    };
    chart_funnel.events = [];

    chart_funnel.format = function(data) {
        var events = [mp.report.globals.funnel_name];
        this.events = events;

        var funnel_info = data[mp.report.globals.funnel_name];
        var dates = funnel_info.meta.dates;
        var xy_data = [], best_worst = [];

        var num_steps, overall, date;
        for (var i = 0; i < dates.length; ++i) {
            num_steps = funnel_info.data[dates[i]].analysis.steps;
            date = chart_util.parse_date(dates[i]);

            // Check to make sure a step exists at each date. Otherwise, count is zero.
            if (params.step_num - 1 < num_steps) {
                overall = funnel_info.data[dates[i]].steps[params.step_num-1].overall_conv_ratio * 100;
                xy_data.push([date, overall]);
            }
            else {
                xy_data.push([date, 0]);
            }
        }
        $("#graph_name").html(mp.report.globals.funnel_name);
        var formatted_data = {};
        formatted_data[mp.report.globals.funnel_name] = xy_data;
        return formatted_data;
    };
    return chart_funnel;
}

function PieChart() {
    var that = new Chart();
    
    that.chart_type = 'pie';
    that.events = [];
    
    that.set_chart_params = function(params) {
        var chart_params = {
            legend: {
                layout: 'vertical',
                style: {
                    left: 'auto',
                    bottom: 'auto',
                    right: '20px',
                    top: '10px'
                },
                labelFormatter: function() {
                    var sanitized = mp.utility.sanitize(this.name);
                    var shortened =  mp.utility.shorten_string(sanitized, 35);
                    var label = '<span title="' + sanitized + '">' + shortened + '</span>';
                    return label;
                }
            },
            tooltip: {
                formatter: function() {
                    var mpu = mp.utility;
                    var n = mpu.commaize(mpu.floatformat(this.y, 2));
                    return '<b>'+ mp.utility.sanitize(this.point.name || this.series.name) +'</b>: '+
                        Highcharts.numberFormat(this.point.percentage, 2)+ '%<br/>'+
                        '<div style="text-align: right">' + n + '</div>';
                }
            },
            plotOptions: {
                pie: {
                    dataLabels: {
                        enabled: false,
                        formatter: function() {
                            if (this.y > 5) { return this.point.name; }
                        },
                        style: {
                            font: '13px Trebuchet MS, Verdana, sans-serif'
                        }
                    }
                }
            },
            credits: {
                enabled: false
            },
            series: [],
            title: {
                style: {
                    display: 'none',
                    margin: '0px'
                }
            },
            chart: {
                margin: [10, 200, 25, 55]
            }
        };
        that.chart_params = $.extend(true, {}, that.chart_params, chart_params);
    };
    
    that.format = function(data) {
        var json = data.data;
        this.events = [0];
        // Chart data object - will hold formatted results
        var cdata = {0:[]};
        for (var event_name in json.values) {
            if (event_name) {
                var ev = json.values[event_name];         
                var total = 0;
                for (var date in ev) {
                    if (date) {
                        total += ev[date];
                    }
                }
                cdata[0].push({ name: event_name, y: total});
            }
        }
        return cdata;
    };
    
    return that;
}

// Average pie charts need to format differently
function AveragePieChart() {
    var that = new Chart();
    
    that.chart_type = 'pie';

    
    that.events = [];
    
    that.set_chart_params = function(params) {
        var chart_params = {
            legend: {
                layout: 'vertical',
                style: {
                    left: 'auto',
                    bottom: 'auto',
                    right: '20px',
                    top: '10px'
                },
                labelFormatter: function() {
                    var sanitized = mp.utility.sanitize(this.name);
                    var shortened =  mp.utility.shorten_string(sanitized, 35);
                    var label = '<span title="' + sanitized + '">' + shortened + '</span>';
                    return label;
                }
            },
            tooltip: {
                formatter: function() {
                    var mpu = mp.utility;
                    var n = mpu.commaize(mpu.floatformat(this.y, 2));
                    return '<b>'+ mp.utility.sanitize(this.point.name || this.series.name) +'</b>: '+
                        Highcharts.numberFormat(this.point.percentage, 2)+ '%<br/>'+
                        '<div style="text-align: right">' + n + '</div>';
                }
            },
            plotOptions: {
                pie: {
                    dataLabels: {
                        enabled: false,
                        formatter: function() {
                            if (this.y > 5) { return this.point.name; }
                        },
                        style: {
                            font: '13px Trebuchet MS, Verdana, sans-serif'
                        }
                    }
                }
            },
            credits: {
                enabled: false
            },
            series: [],
            title: {
                style: {
                    display: 'none',
                    margin: '0px'
                }
            },
            chart: {
                margin: [10, 200, 25, 55]
            }
        };
        that.chart_params = $.extend(true, {}, that.chart_params, chart_params);
    };
    
    that.format = function(data) {
        json = data.data;
        this.events = [0];
        // Chart data object - will hold formatted results
        var cdata = {0:[]};
        for (var event_name in json.values) {
            if (event_name) {
                var ev = json.values[event_name];         
                var total = 0, num_elements = 0;
                for (var date in ev) {
                    if (date) {
                        num_elements += 1;
                        total += ev[date];
                    }
                }
                cdata[0].push({ name: event_name, y: total / num_elements});
            }
        }
        return cdata;
    };
    
    return that;
}

function LineChart() {
    // Basic line chart -- linear.  Currently used for Retention
    var that = new Chart();
    
    that.chart_type = 'line';

    that.events = [];
    
    that.set_chart_params = function(params) {
        var chart_params = {
            xAxis: {
                type: 'linear',
                title: {
                    text: null
                },
                labels: {
                    formatter: function() {
                        return this.value;
                    }
                },
                categories: [],
                showLastLabel: true

            },
            yAxis: {
                title: {
                    enabled: false
                },
                min: 0,
                labels: {
                    formatter: function() {
                        var n = chart_util.abbreviate_number(this.value);
                        return n.join('') + '%';
                    }
                }
            },
            tooltip: {
                formatter: function() {
                    var n = mp.utility.floatformat(this.y, 2), 
                        cu = chart_util, 
                        u = params.unit;
                           // Global unit lookup is a race condition, but not a terribly critical one
                    return '<b>'+ mp.utility.sanitize(cu.format_retention_date(cu.parse_date(this.series.name), u)) +'</b><br/>'+
                        this.point.category + ': '+ n + '%';
                }
            },
            legend: {
                layout: 'vertical',
                style: {
                    left: 'auto',
                    bottom: 'auto',
                    right: '10px',
                    top: '5px'
                },
                labelFormatter: function() {
                    var cu = chart_util, u = params.unit;
                    return mp.utility.sanitize(cu.format_retention_date(cu.parse_date(this.name), u));
                }
            }
        };
        
        this.chart_params = $.extend(true, {}, that.chart_params, chart_params);
    };
    
    that.format = function(data) {
        var json = data.data;
        // Sort & store event names - this will give us the same event with the same color 
        // on all charts.
        var events = [], lines = {};
        for (var event_name in json) {
            if (event_name) {
                var ev = json[event_name];
                lines[event_name] = {};
                for (var line in ev.values) {
                    if (line) {
                        lines[event_name][line] = json[event_name].values[line];
                        // will break with more than one event
                        events.push(line);
                    }
                }
            }
        }

        events.sort();
        this.events = events;

        // Chart data object - will hold formatted results
        var cdata = {}, categories = {};
        for (var e in lines) {
            if (lines.hasOwnProperty(e)) {
                for (var l in lines[e]) {
                    if (lines[e].hasOwnProperty(l)) {
                        var ln = lines[e][l];
                        cdata[l] = [];
                        for (var point in ln) {
                            if (ln.hasOwnProperty(point)) {
                                cdata[l].push([point, ln[point] * 100]);
                            }
                            // Save category name
                            categories[point] = 0;
                        }
                        cdata[l].sort();
                    }
                }
            }
        }

        // Set categories for x-axis labels
        for (var category in categories) {
            if (categories.hasOwnProperty(category)) {
                this.chart_params.xAxis.categories.push(category);
            }
        }
        this.chart_params.xAxis.categories.sort();
        
        return cdata;
    };
    
    return that;
}

function RetentionChart() {
    var that = new Chart();

    that.chart_type = 'line';

    that.events = [];

    var parse_date = function(d) {
        var parts = d.split('-');
        return new Date(
            parseInt(parts[0], 10),
            parseInt(parts[1], 10) - 1,
            parseInt(parts[2], 10)
        );
    };

    that.set_chart_params = function(params) {
        var chart_params = {
            xAxis: {
                type: 'linear',
                title: {
                    text: null
                },
                labels: {
                    formatter: function() {
                        var modulo = params.unit == 'day' ? 4 : 2;
                        if (this.index % modulo == 1) {
                            return Highcharts.dateFormat("%b. %e", parse_date(this.value));
                        } else {
                            return false;
                        }
                    }
                },
                categories: [],
                showLastLabel: true
            },
            yAxis: {
                title: {
                    enabled: false
                },
                min: 0,
                labels: {
                    formatter: function() {
                        var n = chart_util.abbreviate_number(this.value);
                        return n.join('') + '%';
                    }
                }
            },
            tooltip: {
                formatter: function() {
                    var day = Highcharts.dateFormat("%b. %e", parse_date(this.point.category));
                    return '<b>' + day + '</b><br />' + mp.utility.floatformat(this.y, 2) + '%';
                }
            },
            legend: {
                enabled: false
            },
            chart: {
                margin: [25, 25, 25, 50]
            }
        };
        that.chart_params = $.extend(true, {}, this.chart_params, chart_params);
    };

    that.format = function(data) {
        var json = data.data;
        var formatted_data = {};
        this.events = [];

        for (var event_name in json) {
            var ev = json[event_name];
            var series_name = ev.series[this.params.series];
            formatted_data[series_name] = [];
            this.events.push(series_name);

            for (var day in ev.values) {
                if (ev.values[day][series_name]) {
                    formatted_data[series_name].push([day, ev.values[day][series_name] * 100]);
                    this.chart_params.xAxis.categories.push(day);
                }
            }

            chart_util.add_zeros(formatted_data[series_name], this.chart_params.xAxis.categories, this.params);

            formatted_data[series_name].sort();
            this.chart_params.xAxis.categories.sort();
        }

        return formatted_data;
    };

    return that;
}

function Table() {
    var that = new Chart();
    
    that.events = [];
    that.container = '';
    that.chart_params = {
        series: [],
        chart: {},
        xAxis: {
            type: 'datetime',
            categories: []    
        }
    };
    
    that.format = function(dat) {
        var data = dat.data;
        var wrap = function(text, el, cl) {
            return '<' + el + (cl ? ' class="' + cl + '"' : '') + '>' + 
                    text + '</' + el + '>';
        };
        
        var analyze = function(amt) {
            var color = 'blue';
            if (amt < 0.20) {
                color = 'red';
            } else if (amt > 0.50) {
                color = 'green';
            }
            return color;
        };
        
        var format_label = function(datestring) {
            var cu = chart_util, u = that.params.unit;
            return mp.utility.sanitize(cu.format_retention_date(cu.parse_date(datestring), u));
        };
        
        var ret = {};
        for (var evt in data) {
            ret = data[evt];
            break;
        }

        var table = [[wrap('Start date', 'th')]];
        var columns = ret.series;
        var groups = [];

        for (var group in ret.values) {
            groups.push(group);
        }
        groups.sort();

        // Create table header
        for (var col in columns) {
            table[0].push(wrap(columns[col], 'th'));
        }
        
        // Fill in table
        for (var g in groups) {
            var row = [wrap(format_label(groups[g]), 'td')];
            for (var c in columns) {
                var cell = ret.values[groups[g]][columns[c]];
                if (cell === undefined) {
                    cell = '-';
                } else {
                    cell = wrap(mp.utility.floatformat(cell * 100, 2) + '%', 'span', analyze(cell));
                }
                row.push(wrap(cell, 'td'));
            }
            table.push(row);
        }

        return table;
    };
    
    that.render = function(formatted_data) {
        if (formatted_data.length > 1) {
            var html = '<table>';
            for (var i in formatted_data) {
                var row = formatted_data[i];
                html += '<tr>' + row.join('') + '</tr>';
            }
            html += '</table>';

            $("#" + this.container).html(html);
        } else {
            var notice = "Sorry, we don't have any retention data for this event.  You may not be tracking Unique visitors.";
            $('#' + this.container).html('<div class="nodata">' + notice + '</div>');            
        }
    };
    
    return that;
}

// function Map() {
//     var that = new Chart();
//     that.events = [];
//     that.container = '';
//     that.chart_params = {
//         series: [],
//         chart: {},
//         xAxis: {
//             type: 'datetime',
//             categories: []    
//         }
//     };
//     
//     that.format = function(data) {
//         return data;
//     };
//     
//     that.render = function(data) {
//         var width = 956, height = 500, swf_dir = mp.report.globals.swf_dir;
//         var graph = new SWFObject(
//             swf_dir + "/graphs/map.swf",
//             "ammap",
//             width,
//             height,
//             "8",
//             "#FFFFFF"
//         );
//         graph.addVariable("path", swf_dir + "/graphs/");
//         graph.addVariable("map_data", escape(data.data));
//         graph.addVariable('settings_file', swf_dir + '/graphs/map_settings.xml');
//         graph.addParam("wmode", "transparent");
//         graph.write(this.container);
//     };
//     return that;
// }
// 
// function Bar() {
//     // Basic bar chart -- used for Geo
//     var that = new Chart();
//     that.chart_type = 'bar';
//     that.chart_params = {
//         chart: {
//             margin: [10, 10, 25, 140],
//             defaultSeriesType: 'bar'
//         },
//         xAxis: {
//             title: {
//                 text: null
//             },
//             categories: [],
//             showLastLabel: true
//         },
//         yAxis: {
//             min: 0,
//             labels: {
//                 formatter: function() {
//                     var n = chart_util.abbreviate_number(this.value);
//                     return n.join('');
//                 }
//             }
//         },
//         legend: {
//             enabled: false
//         },
//         tooltip: {
//             formatter: function() {
//                 var text = this.x + ': ' + mp.utility.commaize(mp.utility.floatformat(this.y, 2));
//                 if (mp.report.globals.params.endpoint != 'average') {
//                     return text;
//                 } else {
//                     var info = mp.report.globals.wrappers.bar[this.x];
//                     return text + '<br />' + info.unique + ' unique visitors';
//                 }
//             }
//         },
//         plotOptions: {
//             bar: {
//                 dataLabels: {
//                     enabled: true,
//                     color: 'auto',
//                     formatter: function() {
//                         return mp.utility.commaize(mp.utility.floatformat(this.y, 2));
//                     }
//                 },
//                 lineWidth: 15
//             }
//         },
//         credits: {
//             enabled: false
//         },
//         series: [],
//         title: {
//             style: {
//                 display: 'none',
//                 margin: '0px'
//             }
//         }
//     };
//     that.events = [];
//     
//     that.format = function(data) {
//         json = data.data;
//         // Sort & store event names - this will give us the same event with the same color 
//         // on all charts.
//         var to_sort = [], cdata = {0:[]};
//         this.events = [0];
//         mp.report.globals.wrappers.bar = {};
//         for (var i in json) {
//             if (i) {
//                 to_sort.push([json[i].count, json[i].title]);
//                 mp.report.globals.wrappers.bar[json[i].title] = {};
//                 mp.report.globals.wrappers.bar[json[i].title].unique = json[i].unique;
//                 mp.report.globals.wrappers.bar[json[i].title].general = json[i].general;
//             }
//         }
//         to_sort.sort(function(a,b) { return b[0] - a[0];});
//         to_sort = to_sort.slice(0, 30);
//         for (var country in to_sort) {
//             country = to_sort[country];
//             cdata[0].push(country[0]);
//             this.chart_params.xAxis.categories.push(country[1]);
//         }        
//         var height = to_sort.length * 20, current_height = $('#' + this.container).innerHeight();
//         height = (height > current_height) ? height : current_height;
//         // Insert a wrapper so that the height will not remain changed after switching back to line/pie/etc
//         $('#' + this.container).html('<div id="bar_graph_wrapper" style="height: ' + height + 'px"></div>');
//         this.chart_params.chart.renderTo = 'bar_graph_wrapper';
//         return cdata;
//     };
//     return that;
// }
