window.intelesense_data.add_view((function( $, intelesense_data )
{
    function chart(options)
    {
        this.model = options.model;
        this.column = options.column;
        this.element = null;

        this.plot_main = null;
        this.el_main = null;
        this.plot_nav = null;
        this.el_nav = null;
        this.selected_range = {};
        this.data = [];
    };

    chart.prototype.show = function()
    {
        var self = this;
        this.element = $('#'+this.column.field_id);
        if(!this.element.length)
        {
            this.element = $([
                '<div id="'+this.column.field_id+'" class="isd-display isd-flash-graph">',
                    '<p class="isd-graph-title" style="position:relative;z-index:999;float:right;width:200px;text-align:right;margin-left:-210px;padding:0 10px 0 0;font-weight:bold"></p>',
                    '<ul>',
                        '<li><a href="#'+this.column.field_id+'-display">Chart</a></li>',
                        '<li><a href="#'+this.column.field_id+'-options">Options</a></li>',
                    '</ul>',
                    '<div id="'+this.column.field_id+'-display">',
                        '<div class="isd-graph-main"><button id="'+this.column.field_id+'-load">Click To Load</button>',
                        '</div>',
                        '<div class="isd-graph-nav ui-widget-content">',
                        '</div>',
                    '</div>',
                    '<div id="'+this.column.field_id+'-options" class="isd-graph-options">',
                        '<div><h3>Chart Options</h3>',
                        '<p><div class="options-scaling">',
                                '<input type="radio" id="'+this.column.field_id+'-options-lin" name="'+this.column.field_id+'-options-scale"/>',
                                '<label for="'+this.column.field_id+'-options-lin">Linear</label>',
                                '<input type="radio" id="'+this.column.field_id+'-options-log" name="'+this.column.field_id+'-options-scale" />',
                                '<label for="'+this.column.field_id+'-options-log">Logarithmic</label>',
                        '</div></p></div>',
                        '<div><h3>Series Options</h3>',
                        '<p><input type="checkbox" id="'+this.column.field_id+'-options-gaps" name="'+this.column.field_id+'-options-gaps"/>',
                        '<label for="'+this.column.field_id+'-options-gaps">Detect Gaps</label></p>',
                        //'<input type="checkbox" id="'+this.column.field_id+'-options-sd" name="'+this.column.field_id+'-options-sd"/>',
                        //'<label for="'+this.column.field_id+'-options-sd">Annotate Chart With Standard Deviations</label><br>',
                        '<p><select id="'+this.column.field_id+'-options-ma" name="'+this.column.field_id+'-options-ma">',
                            '<option value="0">No Moving Average</option>',
                            '<option value="5">Moving Average: 5</option>',
                            '<option value="10">Moving Average: 10</option>',
                            '<option value="20">Moving Average: 20</option>',
                        '</select></p>',
                        '<p><button id="'+this.column.field_id+'-options-submit">Submit</button></p>',
                    '</div></div>',
                    '<div class="ui-widget-content ui-corner-all">',
                        '<p class="isd-graph-dates"></p>',
                    '</div>',
                '</div>'
            ].join(''));
            $('#isd-container').append(this.element);
            this.el_main = this.element.find('.isd-graph-main');
            this.el_nav = this.element.find('.isd-graph-nav');
            
            //scaling
            $('#'+this.column.field_id+'-options-lin')[0].checked=true;
            this.element.find('.options-scaling').buttonset();

            //moving average
            $('#'+this.column.field_id+'-options-ma').val(0).selectmenu({width:'250px'});

            //gaps
            $('#'+this.column.field_id+'-options-gaps')[0].checked=true;
            $('#'+this.column.field_id+'-options-gaps').button();
            
            //standard deviation
            //$('#'+this.column.field_id+'-options-sd')[0].checked=false;

            //button
            $('#'+this.column.field_id+'-options-submit').button();

            //make it pretty
            this.element.tabs();

            //set graph title
            this.element.find('.isd-graph-title').html(this.column.name + ' ' + this.column.units);

            //click to load
            $('#'+this.column.field_id+'-load').button().click(function()
            {
                self.draw();
            });
        }
    };

    chart.prototype.transform_log = function(x,axis)
    {
        if(!axis.transform_offset)
        {
            axis.transform_offset = Math.abs(Math.ceil(axis.min))+1;
        }
        return Math.log(x+axis.transform_offset);
    };

    chart.prototype.transform_log_inverse = function(x,axis)
    {
        return Math.exp(x)-axis.transform_offset;
    };

    chart.prototype.update_selected_range = function(ranges)
    {
        var html,from,to;

        if(ranges)
        {
            this.selected_range = ranges;
        }
        else
        {
            //set to full range
            this.selected_range = {xaxis:{from:this.model.first_loaded_time,to:this.model.last_loaded_time}};
        }

        //update display of dates
        from = this.model.format_date(new Date(this.selected_range.xaxis.from),'%y/%m/%d',this.column,$('#isd-options-timezone').val());
        to = this.model.format_date(new Date(this.selected_range.xaxis.to),'%y/%m/%d',this.column,$('#isd-options-timezone').val());
        if(from==to) html = "Selected Date: " + from;
        else html = "Selected Range: " + from + " to " + to;
        this.element.find('.isd-graph-dates').html(html);

        //set nav chart
        this.plot_nav.setSelection(this.selected_range, true);

        //redraw main chart
        this.build_main_chart();
    }

    chart.prototype.highlight_selected = function(item,action)
    {
        var series = this.plot_main.getData();
        item = item.split(':');
        if(item && action)
        {
            //draw only provided point
            for (i = series.length - 1; i >= 0; --i)
            {
                if (item[0]!=series[i].yaxis.options.column.field_id)
                    continue;

                var s = series[i],
                    axisx = s.xaxis,
                    axisy = s.yaxis,
                    points = s.datapoints.points,
                    ps = s.datapoints.pointsize;

                for (j = 0; j < points.length; j += ps)
                {
                    var x = points[j], y = points[j + 1];
                    if(x==item[1]&&y==item[2])
                    {
                        if(action=='add') this.plot_main.highlight(s, [x,y]);
                        else this.plot_main.unhighlight(s, [x,y]);
                    }
                }
            }
        }
    }

    chart.prototype.build_main_chart = function()
    {
        var self = this;
        var options = {
            xaxis: {
                labelwidth:4,
                mode: "time",
                ticks:4,
                min: this.selected_range.xaxis.from,
                max: this.selected_range.xaxis.to,
                tickFormatter:function(v,axis){
                    var d = new Date(v);
                    var timeUnitSize = {
                        "second": 1000,
                        "minute": 60 * 1000,
                        "hour": 60 * 60 * 1000,
                        "day": 24 * 60 * 60 * 1000,
                        "month": 30 * 24 * 60 * 60 * 1000,
                        "year": 365.2425 * 24 * 60 * 60 * 1000
                    };
                    var t = axis.tickSize[0] * timeUnitSize[axis.tickSize[1]];
                    if (t < timeUnitSize.day) fmt = "%h:%M:%S";
                    else if (t < timeUnitSize.month) fmt = "%m/%d %h:%M";
                    else fmt = "%m/%d";
                    return self.model.format_date(d,fmt,self.column,$('#isd-options-timezone').val());
                }
            },
            yaxis: {
                ticks:5,
                column:this.column
            },
            selection: {
                mode: "x"
            },
            legend: {show: false},
            grid: {
                hoverable: true,
                clickable: true,
                borderWidth:0,
                mouseActiveRadius:20
            },
            series:{
            }
        };

        //set moving average
        var ma = $('#'+this.column.field_id+'-options-ma').val();
        if(ma>0)
        {
            options.series['movingfunction'] = {
                func:function(elements)
                {
                    for (var i = 0, j = elements.length, sum = 0; i < j; sum += elements[i++]);
                    return sum/j;
                },
                range:ma
            }
        }

        //set linear or log scaling
        if($('#'+this.column.field_id+'-options-log')[0].checked)
        {
            options.yaxis['transform'] = this.transform_log;
            options.yaxis['inverseTransform'] = this.transform_log_inverse;
        }

        //set detect gaps
        if($('#'+this.column.field_id+'-options-gaps')[0].checked)
        {
            options.series['showgaps'] = {rounding:60000};
        }


        this.plot_main = $.plot(this.el_main, this.data, options);

        //add any selections
        var selected = self.model.selected;
        for(var i in selected)
        {
            self.highlight_selected(selected[i], 'add');
        }
    }
    chart.prototype.build_nav_chart = function()
    {
        var self = this;
        var options = {
            xaxis:{
                min:this.model.first_loaded_time,
                max:this.model.last_loaded_time
            },
            series: {
                lines: { show: true, lineWidth: 1 },
                shadowSize: 1
            },
            selection: { mode: "x" },
            legend: {show: false},
            grid: { show: false, clickable: true, autoHighlight:false }
        };
        this.plot_nav = $.plot(this.el_nav, this.data, options);
    }

    chart.prototype.draw = function()
    {
        var self = this;
        var main = this.el_main;
        var nav = this.el_nav;

        var func = function(self){return function(){self.draw()}};
        if(!main||main.width()<100||main.height()<50)
        {
            
            setTimeout(func(this),250);
            return;
        }

        //get chart data
        this.data.push({
            'data':this.model.get_data(this.column),
            'label':this.column.name + ' ' + this.column.units
        });

        //build nav chart
        this.build_nav_chart();

        //set initial selection to 1/3 of range - this triggers build of main chart
        this.update_selected_range({xaxis:{
            from:this.model.last_loaded_time - ((this.model.last_loaded_time-this.model.first_loaded_time)/3),
            to:this.model.last_loaded_time
        }});

        //enable range selection on main graph
        main.bind("plotselected", function (event, ranges) {

            $(document).trigger('eventGraphRangeChanged', [ranges]);
        });

        //enable selection on small graph
        nav.bind("plotselected", function (event, ranges) 
        {
            $(document).trigger('eventGraphRangeChanged', [ranges]);
        });

        //double click to remove selection - we trigger the event here
        //so that all graphs will be updated
        nav.bind("dblclick",function (event, pos, item)
        {
            $(document).trigger("eventGraphRangeChanged");
        });

        //handle data selection
        $(document).bind("eventGraphRangeChanged",function(event, ranges)
        {
            self.update_selected_range(ranges);
        });

        //enable hilight of points
        main.bind("plotclick", function (event, pos, item)
        {
            if (item)
            {
                self.model.toggle_select([
                    item.series.yaxis.options.column.field_id,
                    item.datapoint[0],
                    item.datapoint[1]].join(':'));
            }
        });
        $(document).bind('selectionChanged',function(event,item,action)
        {
            self.highlight_selected(item,action);
        });

        //enable tooltips
        var previousPoint = null;
        main.bind("plothover", function (event, pos, item)
        {
            if (item)
            {
                if (previousPoint != item.datapoint)
                {
                    previousPoint = item.datapoint;
                    $("#isd-tooltip").remove();
                    var y = item.datapoint[1].toFixed(2);
                    var d = self.model.format_date(new Date(item.datapoint[0]),'%y/%m/%d %H:%M',self.column,$('#isd-options-timezone').val());
                    $('<p class="ui-widget-header ui-corner-all" id="isd-tooltip">' +
                        item.series.label + ': ' + y + '<br>' + d + '</p>').css( {
                        'position': 'absolute',
                        'top': item.pageY + 8,
                        'left': item.pageX + 8,
                        'z-index':100,
                        'padding':'0.5em'
                    }).hover(function(){$("#isd-tooltip").remove();}).appendTo("body");
                }
            }
            else $("#isd-tooltip").remove();
        });

        //listen for timezone changes
        $(document).bind("eventOptionsTimezoneChanged",function(event, tz)
        {
            self.update_selected_range(self.selected_range);
        });

        //listen for options form submission
        $('#'+this.column.field_id+'-options-submit').click(function()
        {

            self.element.tabs("select",0);
            self.build_main_chart();
        });

    }

    chart.prototype.hide = function()
    {
        this.element.hide();
    };

    return( chart );

})( jQuery, window.intelesense_data ));
