define([
        'knockout', 'jquery', 'text!./Weather2.html', 'props', 'flot', 'flotresize'
], function(ko, jquery, htmlString, SGPropertyNode) {

    if (typeof Math.roundTo === "undefined") {
        Math.roundTo = function(num, step) {
            return Math.floor((num / step) + .5) * step;
        }
    }

    function ViewModel(params, componentInfo) {
        // componentInfo.element

        var self = this;

        function createIsotherms() {
            var reply = [];
            for (x = -50; x < 50; x += 10) {
                reply.push([
                        x, -0.02
                ]);
                reply.push([
                        x, 16
                ]);
                reply.push(null);
            }
            /*
             * for (x = -160; x < 50; x += 10) { reply.push([ x, -56 ]);
             * reply.push([ x + 116, 50 ]); reply.push(null); }
             */
            return reply;
        }

        function createDryAdiabates() {
            var reply = [];
            /*
             * for (x = -35; x <= 200; x += 20) { reply.push([ x, 1050 ]);
             * reply.push([ x-160, 100 ]); reply.push(null); }
             */
            return reply;
        }

        jquery.get('/json/environment/config?d=4', null, function(data) {
            var wx = new SGPropertyNode(data);

            function createProbes(k) {
                var probes = [];
                wx.getNode("boundary").getChildren("entry").forEach(function(entry) {
                    probes.push([
                            entry.getValue(k, 15), entry.getValue("elevation-ft", 0) * 0.3048 / 1000
                    // km
                    ]);
                });
                wx.getNode("aloft").getChildren("entry").forEach(function(entry) {
                    probes.push([
                            entry.getValue(k, 15), entry.getValue("elevation-ft", 0) * 0.3048 / 1000
                    // km
                    ]);
                });
                return probes;
            }

            function createWind() {
                var wind = [];
                wx.getNode("boundary").getChildren("entry").forEach(function(entry) {
                    wind.push([
                            entry.getValue("wind-speed-kt", 0), entry.getValue("elevation-ft", 0) * 0.3048 / 1000, // km
                            entry.getValue("wind-from-heading-deg", 0),
                    ]);
                });
                wx.getNode("aloft").getChildren("entry").forEach(function(entry) {
                    wind.push([
                            entry.getValue("wind-speed-kt", 0), entry.getValue("elevation-ft", 0) * 0.3048 / 1000, // km
                            entry.getValue("wind-from-heading-deg", 0),
                    ]);
                });
                return wind;
            }

            self.wxData()[3].data = createProbes("temperature-degc");
            self.wxData()[4].data = createProbes("dewpoint-degc");
            self.wxData()[5].data = createWind();
            self.wxData.notifySubscribers(self.wxData.peek());
        });

        jquery.get('/json/environment/clouds?d=4', null, function(data) {
            var clouds = new SGPropertyNode(data);
            function createClouds() {
                var reply = [];
                clouds.getChildren("layer").forEach(function(layer) {
                    var coverage = layer.getValue("coverage");
                    if( coverage == "clear" ) return;

                    var base = layer.getValue("elevation-ft", -9999 );
                    if( base < -9000 ) return;

                    var tops = base + layer.getValue("thickness-ft",0) + base;
                    if( tops == base ) return;

                    base *= 0.3048/1000;
                    tops *= 0.3048/1000;

                    reply.push( [reply.length, tops, base] );
                });

                return reply;
            }


            self.wxData()[2].data = createClouds();
            self.wxData.notifySubscribers(self.wxData.peek());
        });


        self.wxData = ko.observableArray([
                {// Series: Isotherms
                    color : 'rgb(0, 0, 255)',
                    data : createIsotherms(),
                    label : "Isotherm",
                    lines : {
                        lineWidth : 0.5,
                        show : true
                    },
                    points : {
                        show : false
                    },
                    bars : {
                        show : false
                    },
                    shadowSize : 0,
                    yaxis : 2, // on linear scale
                    xaxis : 1,
                }, {// Series: Dry Adiabat
                    color : 'rgb(0, 255, 0)',
                    data : createDryAdiabates(),
                    label : "dry adiabat",
                    lines : {
                        lineWidth : 0.5,
                        show : true
                    },
                    points : {
                        show : true
                    },
                    bars : {
                        show : false
                    },
                    shadowSize : 0,
                    yaxis : 1,
                    xaxis : 1,
                }, { // clouds
                    color : 'rgb(128,128,128)',
                    data : [],
                    label : 'clouds',
                    lines : {
                        show : false
                    },
                    bars : {
                        show : true,
                        lineWidth : 0,
                        barWidth : 1,
                        fillColor : {
                            colors : [
                                    {
                                        opacity : 0.2
                                    }, {
                                        opacity : 0.9
                                    }
                            ]
                        }
                    },
                    shadowSize : 2,
                    yaxis : 2,
                    xaxis : 2,
                }, { // Temperature
                    color : 'rgb(255, 0, 0)',
                    data : [],
                    label : "temperature",
                    lines : {
                        lineWidth : 2,
                        show : true
                    },
                    points : {
                        show : true
                    },
                    bars : {
                        show : false
                    },
                    shadowSize : 0,
                    yaxis : 2,
                    xaxis : 1,
                }, { // dewpoint
                    color : 'rgb(0, 255, 0)',
                    data : [],
                    label : "dewpoint",
                    lines : {
                        lineWidth : 2,
                        show : true
                    },
                    points : {
                        show : true
                    },
                    bars : {
                        show : false
                    },
                    shadowSize : 0,
                    yaxis : 2,
                    xaxis : 1,
                }, {
                    color : 'rgb(0, 255, 0)',
                    data : [],
                    label : "windarrows",
                    lines : {
                        show : false
                    },
                    points : {
                        show : false
                    },
                    bars : {
                        show : false
                    },
                    windarrows : {
                        show : true,
                    },
                    shadowSize : 0,
                    yaxis : 2,
                    xaxis : 1,
                }
        ]);

        self.wxOptions = {
            legend : {
                show : false,
            },
            xaxes : [
                    { // Axis 1: Temperature
                        show : true,
                        position : "bottom",
                        color : 'blue',
                        tickColor : 'green',
                        min : -56,
                        max : 50,
                        tickLength : 0,
                    }, { // Axis 2: Cloud Layer
                        show : false,
                        min : 0,
                        max : 5,
                    },
            ],
            yaxes : [
                    { // Axis 1: Pressure (hpa), Log-P
                        show : true,
                        position : "left",
                        color : 'blue',
                        tickColor : 'blue',
                        min : 100,
                        max : 1050,
                        // tickLength : 0,
                        transform : function(v) {
                            return -Math.log(v);
                        },
                        inverseTransform : function(v) {
                            return Math.exp(-v);
                        },

                    }, { // Axis 2: Altitude (km)
                        show : true,
                        position : "right",
                        color : 'black',
                        tickColor : 'green',
                        min : -.020,
                        max : 16,
                        tickLength : 0,

                    }
            ],

            grid : {
                hoverable : true,
                clickable : true
            },

            hooks : {
                processRawData : function(plot, series, data, datapoints) {
                    if (series.windarrows && series.windarrows.show) {
                        datapoints.format = [
                                {
                                    x : true,
                                    number : true,
                                    required : true

                                }, {
                                    y : true,
                                    number : true,
                                    required : true

                                }, {
                                    number : true,
                                    required : true
                                }
                        ]
                    }

                },

                drawSeries : function(plot, ctx, series) {
                    if (series.windarrows && series.windarrows.show) {
                        function drawSeriesWindarrows(datapoints) {
                            var points = datapoints.points, ps = datapoints.pointsize;
                            for (var i = 0; i < points.length; i += ps) {
                                var ws = Math.roundTo(points[i], 5), y = points[i + 1], wd = points[i + 2];

                                var x = series.xaxis.p2c(40);
                                y = series.yaxis.p2c(y);

                                ctx.save();
                                ctx.translate(x, y);
                                ctx.rotate((wd + 180) * Math.PI / 180);

                                ctx.beginPath();
                                ctx.arc(0, 0, 3, 0, Math.PI * 2, false);
                                ctx.closePath();

                                ctx.moveTo(0, 0);
                                ctx.lineTo(0, 9 * 5);
                                var pos = 0;
                                while (ws >= 5) {
                                    if (ws >= 50) {
                                        ws -= 50;
                                        ctx.moveTo(0, (9 - pos) * 5);
                                        ctx.lineTo(-10, (8.5 - pos) * 5);
                                        ctx.lineTo(0, (8 - pos) * 5);
                                        pos++;
                                    } else if (ws >= 10) {
                                        if (pos > 0)
                                            pos++;
                                        ws -= 10;
                                        ctx.moveTo(0, (9 - pos) * 5);
                                        ctx.lineTo(-10, (9.5 - pos) * 5);
                                    } else {
                                        pos++;
                                        ws -= 5;
                                        ctx.moveTo(0, (9 - pos) * 5);
                                        ctx.lineTo(-5, (9.25 - pos) * 5);
                                    }
                                }

                                ctx.stroke();
                                ctx.restore();

                            }

                        }
                        var plotOffset = plot.getPlotOffset();

                        ctx.save();
                        ctx.translate(plotOffset.left, plotOffset.top);
                        ctx.lineWidth = 1.5;
                        ctx.strokeStyle = 'black';

                        drawSeriesWindarrows(series.datapoints);

                        ctx.restore();

                    }
                }
            },
        };

        self.afterUpdate = function(element) {
            var yaxisLabel = jquery("<div class='axisLabel yaxisLabel'></div>").text("Pressure (hpa)").appendTo(element);

            // Since CSS transforms use the top-left corner of the label as the
            // transform origin,
            // we need to center the y-axis label by shifting it down by half
            // its
            // width.
            // Subtract 20 to factor the chart's bottom margin into the
            // centering.

            yaxisLabel.css("margin-top", yaxisLabel.width() / 2 - 20);
        }

        var highlighted = null;

        self.plotHover = function(pos, item) {

            if (highlighted) {
                self.wxData()[highlighted.seriesIndex].data[highlighted.dataIndex] = [
                        pos.x1, highlighted.datapoint[1]
                ];
                this.setData(self.wxData());
                this.draw();
            }
        }

        self.plotClick = function(pos, item) {
            if (highlighted) {
                this.unhighlight(highlighted.series, highlighted.datapoint);
                highlighted = null;
            } else {
                if (item && item.seriesIndex != 3 && item.seriesIndex != 4)
                    return;

                highlighted = item;
                if (highlighted)
                    this.highlight(highlighted.series, highlighted.datapoint);
            }
        }
    }

    ViewModel.prototype.dispose = function() {
    }

    // Return component definition
    return {
        viewModel : {
            createViewModel : function(params, componentInfo) {
                return new ViewModel(params, componentInfo);
            },
        },
        template : htmlString
    };
});