define([
        'jquery', 'knockout', 'text!./Holding.html', 'sprintf', 'kojqui/button', 'kojqui/spinner'
], function(jquery, ko, htmlString, sprintf) {

    function ViewModel(params) {
        var self = this;

        function normDeg(val, min, max) {
            var d = max - min;
            while (val >= max)
                val -= d;
            while (val < min)
                val += d;
            return val;
        }

        self.standard = ko.observable(true);
        self.nonStandard = ko.pureComputed(function() {
            return false == self.standard();
        });

        self.inboundTrack = ko.observable(0);
        self.heading = ko.observable(270);
        self.entry = ko.observable("");

        self.entryClass = function(p) {
            console.log(p, self.entry());
            if (p == self.entry())
                return 'holding-pattern-' + p;
            else
                return 'active-holding-pattern-' + p;

        }

        self.holdingTransform = ko.pureComputed(function() {
            return sprintf.sprintf("rotate(%f 50 50)", self.inboundTrack());
        });

        self.trackTransform = ko.pureComputed(function() {
            return sprintf.sprintf("rotate(%f 50 50)", self.heading());
        });
        
        function test() {
            var v = [ -1, 0 ];
            var phi = 0 * Math.PI/180;
            
            var cosPhi = Math.cos(phi);
            var sinPhi = Math.sin(phi);
            var m = [ [ cosPhi, sinPhi ], [ -sinPhi, cosPhi ] ];
            
            var r = [ m[0][0] * v[0] + m[1][0]*v[1], m[0][1] * v[0] + m[1][1]*v[1]];
            
            console.log(v,m,r);
        }
        
        function moveOnArc( targetHeading, r, dir ) {
            dir = dir || 1;
            var phi = targetHeading * Math.PI/180;
            var cosPhi = Math.cos(phi);
            var sinPhi = Math.sin(phi);
            var x = dir*r*(1- cosPhi);
            var y = r * sinPhi;
            return [ Number(x.toFixed(1)), Number(-y.toFixed(1)) ];
        }

        function moveStraight( heading, dist ) {
            var phi = heading * Math.PI/180;
            var cosPhi = Math.cos(phi);
            var sinPhi = Math.sin(phi);
            var x = dist * sinPhi;
            var y = dist * cosPhi;
            return [ Number(x.toFixed(1)), Number(-y.toFixed(1)) ];
        }

        self.trackDraw = ko.pureComputed(function() {
            function entryProcedure(s, t, h) {
                var d = normDeg(t - h, -180, 180);
                var reply = "";
                
                var dir = s ? 1 : -1;

                if ((s && d >= -110 && d < 70) || (!s && d >= -70 && d < 110)) {
                    self.entry("direct");
                    // turn to outbound track
                    var turn = normDeg(dir*d+180,0,360);
                    var p = moveOnArc(turn, 7.5, dir );
                    reply += sprintf.sprintf(" a 7.5 7.5, 0, %d, %d, %f %f ", turn>180?1:0, s?1:0, p[0], p[1] );

                    // fly outbound 
                    p = moveStraight(d+180, 25);
                    reply += sprintf.sprintf(" l %f,%f", p[0], p[1] );

                    // turn back to the holding pattern, intercept inbound
                    p = moveStraight(d-dir*90, 15 );
                    reply += sprintf.sprintf(" a 7.5 7.5, 0, %d, %d, %f %f ", 0, s?1:0, p[0], p[1] );

                    // and to the fix
                    reply += " L50,50";
                } else if ((s && d >= -180 && d < -110) || (!s && d >= 110 && d < 180)) {
                    self.entry("teardrop");

                    // fly outbount for 1minute
                    var p = moveStraight(d+180-dir*30, 30 );
                    reply += sprintf.sprintf(" l %f,%f", p[0], p[1] );

                    // turn back to station
                    p = moveOnArc(d-dir*30, 7.5, dir );
                    reply += sprintf.sprintf(" a 7.5 7.5, 0, %d, %d, %f %f ", 0, s?1:0, p[0], p[1] );

                    reply += " L50,50";
                } else if ((s && d >= 70 && d < 180) || (!s && d >= -180 && d < -70)) {
                    self.entry("parallel");
                    // turn to outbound track
                    var turn = normDeg(dir*d+180,0,360);
                    var p = moveOnArc(180-dir*d, 7.5, -dir );
                    reply += sprintf.sprintf(" a 7.5 7.5, 0, %d, %d, %f %f ", 0, s?0:1, p[0], p[1] );

                    // fly outbound 
                    p = moveStraight(d+180, 25);
                    reply += sprintf.sprintf(" l %f,%f", p[0], p[1] );

                    // turn back to the holding pattern, intercept inbound
                    p = moveStraight(d+dir*90, 15 );
                    reply += sprintf.sprintf(" a 7.5 7.5, 0, %d, %d, %f %f ", 0, s?0:1, p[0], p[1] );

                    reply += " L50,50";
                } else {
                    self.entry("unknown");
                }
                return reply;
            }
            return "M50,100 v-50 " + entryProcedure(self.standard(), self.inboundTrack(), self.heading());
        });

        self.setStandard = function(a, b) {
            self.standard(true);
        }

        self.setNonStandard = function(a, b) {
            self.standard(false);
        }

        self.inboundTrackSpin = function(event, ui) {
            $(event.target).spinner("value", normDeg(ui.value, 0, 360));
            return false;
        }

        self.headingSpin = function(event, ui) {
            $(event.target).spinner("value", normDeg(ui.value, 0, 360));
            return false;
        }

    }

    // ViewModel.prototype.dispose = function() {
    // }

    // Return component definition
    return {
        viewModel : ViewModel,
        template : htmlString
    };
});