# The following is largely inspired from the Extra500 Avidyne Entegra 9 
# https://gitlab.com/extra500/extra500.git
# Many thanks to authors: Dirk Dittmann and Eric van den Berg
var RouteItemClass = {
    new : func (canvasGroup, index) {
        var m = {parents:[RouteItemClass]};
        m.index = index;
        m.group = canvasGroup.createChild('group', 'Waypoint-' ~ index).setVisible(0);
        
        m.can = {
            Waypoint : m.group.createChild('path','icon-' ~ index)
                .setStrokeLineWidth(3)
                .setScale(1)
                .setColor(1,1,1)
                .setColorFill(1,1,1)
                .moveTo(-20, 0)
                .lineTo(-5, 5)
                .lineTo(0, 20)
                .lineTo(5, 5)
                .lineTo(20, 0)
                .lineTo(5, -5)
                .lineTo(0, -20)
                .lineTo(-5, -5)
                .close(),
            Label : m.group.createChild('text', 'wptLabel-' ~ index)
                .setFont('LiberationFonts/LiberationMono-Bold.ttf')
                .setTranslation(25,-25)
                .setFontSize(20, 1)
                .setColor(1,1,1)
                .setColorFill(1,1,1),
            track : canvasGroup.createChild('path','track-' ~ index)
                .setStrokeLineWidth(3)
                .setScale(1)
                .setColor(1,1,1)
                .setVisible(1),
        };
        return m;
    },
    setVisible : func (v) {
        me.group.setVisible(v);
        me.can.track.setVisible(v);
    },
    draw : func (wpt) {
        me.can.Label.setText(wpt[0].name);
        me.setColor(1,1,1);
        me.group.setGeoPosition(wpt[0].lat, wpt[0].lon);
        me.group.setVisible(1);
    },
    drawTrack : func (wpt) {
        var cmds = [];
        var coords = [];
        var cmd = canvas.Path.VG_MOVE_TO;
        me.can.track.setVisible(1);
        
        foreach (var pt; wpt) {
            append(coords, 'N' ~ pt.lat);
            append(coords, 'E' ~ pt.lon);
            append(cmds, cmd);
            cmd = canvas.Path.VG_LINE_TO;
        }
        me.can.track.setDataGeo(cmds, coords);
    },
    setColor : func (color) {
        me.can.Label.setColor(color).setColorFill(color);
        me.can.Waypoint.setColor(color).setColorFill(color);
    },
    del : func {
        me.can.track.del();
        me.group.del();
        me = nil;
    },
};

var FMSIcon = {
    new : func (canvasGroup, text) {
        var m = {parents:[ FMSIcon ]};
        m.group = canvasGroup.createChild('group', 'FMS-' ~ text).setVisible(0);   
        m.can = {
            icon : m.group.createChild('path','FMS-icon' ~ text)
                .setStrokeLineWidth(3)
                .setScale(1)
                .setColor(0,1,0)
                .setColorFill(0,1,0)
                .moveTo(-15, 0)
                .lineTo(0, 15)
                .lineTo(15, 0)
                .lineTo(0, -15)
                .close(),
            label : m.group.createChild('text', 'FMS-label-' ~ text)
                .setFont('LiberationFonts/LiberationMono-Bold.ttf')
                .setTranslation(20,12)
                .setFontSize(32, 1)
                .setColor(0,1,0)
                .setColorFill(0,1,0)
                .setText(text),
        };
        return m;
    },
    setVisible : func (v)
        me.group.setVisible(v),
    setGeoPosition : func (lat, lon)
        me.group.setGeoPosition(lat, lon),
};

var FMSIconRTA = {
    new : func (canvasGroup, text) {
        var m = {parents:[FMSIconRTA]};
        m.group = canvasGroup.createChild('group', 'FMS-' ~ text).setVisible(0);   
        m.can = {
            icon : m.group.createChild('path','FMS-icon' ~ text)
                .setStrokeLineWidth(3)
                .setScale(1)
                .setColor(0,1,0)
                .setColorFill(0,1,0)
                .moveTo(-15, 0)
                .lineTo(0, 15)
                .lineTo(15, 0)
                .lineTo(0, -15)
                .close(),
            label : m.group.createChild('text', 'FMS-label-' ~ text)
                .setFont('LiberationFonts/LiberationMono-Bold.ttf')
                .setTranslation(-80,12)
                .setFontSize(32, 1)
                .setColor(0,1,0)
                .setColorFill(0,1,0)
                .setText(text),
        };
        return m;
    },
    setVisible : func (v)
        me.group.setVisible(v),
    setGeoPosition : func (lat, lon)
        me.group.setGeoPosition(lat, lon),
};

var MapRoute = {
    new : func (device, group) {
        var m = {parents:[ MapRoute ]}; 
        m.item       = [];
        m.itemIndex  = 0;
        m.visibility = 0;
        m.device = device;
        m.group = group.createChild('map', 'route map')
            .setTranslation(
                m.device.role == 'MFD' ? (m.device.data.mapview[0] + m.device.data.mapclip.left)/2 : 120,
                m.device.role == 'MFD' ? 400 : 600)
            .setVisible(m.visibility);
        m.group._node
            .getNode('range', 1).setDoubleValue(m.device.data['range-factor']);
        m.group._node
            .getNode('ref-lat', 1).setDoubleValue(data.lat);
        m.group._node
            .getNode('ref-lon', 1).setDoubleValue(data.lon);

        m.groupTrack = m.group.createChild('group', 'Track')
            .setVisible(1);
        m.groupOBS   = m.group.createChild('group', 'OBS')
            .setVisible(0);
        m.groupFMS   = m.group.createChild('group', 'FMS')
            .setVisible(1);
        
        m.can = {
            track : m.group.createChild('path', 'track')
                .setStrokeLineWidth(3)
                .setScale(1)
                .setColor(1,1,1),
            currentLeg : m.groupFMS.createChild('path', 'currentLeg')
                .setStrokeLineWidth(5)
                .setScale(1)
                .setColor(1,0,1),
            nextLeg : m.groupFMS.createChild('path', 'nextLeg')
                .setStrokeLineWidth(5)
                .setScale(1)
                .setStrokeDashArray([25,25])
                .setColor(1,0,1),
            obsCourse : m.groupOBS.createChild('path', 'obsCourse')
                .setStrokeLineWidth(5)
                .setScale(1)
                .setColor(1,0,1),
        };
        
        m.TOD = FMSIcon.new(m.groupFMS, 'TOD');
        m.TOC = FMSIcon.new(m.groupFMS, 'TOC');
        m.RTA = FMSIconRTA.new(m.groupFMS, 'RTA');
        
        m.track = {
            cmds  : [],
            coords: [],
        };
        m.currentLeg = {
            cmds: [ canvas.Path.VG_MOVE_TO, canvas.Path.VG_LINE_TO ],
            coords: [0, 0, 0, 0],
            index : -1,
        };
        m.nextLeg = {
            cmds: [ canvas.Path.VG_MOVE_TO, canvas.Path.VG_LINE_TO ],
            coords: [0, 0, 0, 0],
            index : -1,
        };
        
        m.mapOptions = {
            orientation : 0,
        };
        
        m.obsMode = 0;
        m.obsCourse = 0;
        m.obsWaypoint = RouteItemClass.new(m.groupOBS, 'obs_wp');
        m.obsCourseData = {
            cmds: [ canvas.Path.VG_MOVE_TO, canvas.Path.VG_LINE_TO ],
            coords: [0, 0, 0, 0]};

        m.flightPlan = [];
        m.currentWpIndex = getprop('/autopilot/route-manager/current-wp');
        
        if (m.device.role == 'PFD')
            m.device.softkeys.colored.INSETROUTE = 1;
        if (m.device.role == 'MFD')
            m.device.softkeys.colored.MAPROUTE = 1;

        return m;
    },
    update: func {
        me.visibility != 0 or return;
        me.group._node
            .getNode('range', 1).setDoubleValue(me.device.data['range-factor']);
        me.group._node.getNode('ref-lat', 1).setDoubleValue(data.lat);
        me.group._node.getNode('ref-lon', 1).setDoubleValue(data.lon);
    },
    setVisible : func (v) {
        if (me.visibility != v) {
            me.visibility = v;
            me.group.setVisible(v);
        }
    },
    updateOrientation : func (value) {
        me.mapOptions.orientation = value;
        me.can.obsCourse.setRotation((me.obsCourse - me.mapOptions.orientation) * D2R);
    },
    onFlightPlanChange : func {
        for (var i = size(me.item) - 1; i >= 0; i -= 1) {
            me.item[i].del();
            pop(me.item);
        }
        me.itemIndex = 0;
        me.flightPlan = [];
        var route = props.globals.getNode('/autopilot/route-manager/route');
        var planSize = getprop('/autopilot/route-manager/route/num');
        for (var i=0; i < planSize - 1; i+=1) {
            var wp0  = route.getNode('wp[' ~   i   ~ ']');
            var wp1  = route.getNode('wp[' ~ (i+1) ~ ']');
            append(me.flightPlan, [
                {
                    lat : wp0.getNode('latitude-deg').getValue(),
                    lon : wp0.getNode('longitude-deg').getValue(),
                    name: wp0.getNode('id').getValue(),
                },
                {
                    lat : wp1.getNode('latitude-deg').getValue(),
                    lon : wp1.getNode('longitude-deg').getValue(),
                    name: wp1.getNode('id').getValue(),
                }
            ]);
            append(me.item, RouteItemClass.new(me.groupTrack, i));
        }
        me.setVisible(me.device.map.visibility);
        me.drawWaypoints();
    },
    onCurrentWaypointChange : func (n) {
        me.currentWpIndex = n.getValue();
        me.currentLeg.index = me.currentWpIndex - 1;
        me.nextLeg.index = me.currentWpIndex;
        if (me.currentWpIndex == 0) {
            n.setIntValue(1);
            me.currentWpIndex = 1;
        }
        me.drawLegs();
    },
    drawWaypoints : func {
        me.visibility != 0 or return;
        var cmd = canvas.Path.VG_MOVE_TO;

        for (var i=0; i < size(me.flightPlan); i+=1) {
#            me.item[me.itemIndex].draw(me.flightPlan[i]);
            me.item[me.itemIndex].drawTrack(me.flightPlan[i]);
            me.itemIndex +=1;
        }
        me.groupTrack.setVisible(me.visibility and (me.obsMode == 0));
    },
    drawLegs : func {
        me.visibility != 0 or return;
        if (me.currentLeg.index >= 0 and me.currentLeg.index < size(me.flightPlan)) {
            var cmd = canvas.Path.VG_MOVE_TO;
            me.currentLeg.coords = [];
            me.currentLeg.cmds = [];
            foreach (var pt; me.flightPlan[me.currentLeg.index]) {
                append(me.currentLeg.coords, 'N' ~ pt.lat);
                append(me.currentLeg.coords, 'E' ~ pt.lon);
                append(me.currentLeg.cmds, cmd);
                cmd = canvas.Path.VG_LINE_TO;
            }
            me.can.currentLeg.setDataGeo(me.currentLeg.cmds, me.currentLeg.coords);
            me.can.currentLeg.setVisible(1);
        }
        else
            me.can.currentLeg.setVisible(0);
        
        if (me.nextLeg.index >= 1 and me.nextLeg.index < size(me.flightPlan)) {
            var cmd = canvas.Path.VG_MOVE_TO;
            me.nextLeg.coords = [];
            me.nextLeg.cmds = [];
            foreach (var pt; me.flightPlan[me.nextLeg.index]) {
                append(me.nextLeg.coords,'N' ~ pt.lat);
                append(me.nextLeg.coords,'E' ~ pt.lon);
                append(me.nextLeg.cmds,cmd);
                cmd = canvas.Path.VG_LINE_TO;
            }
            me.can.nextLeg.setDataGeo(me.nextLeg.cmds, me.nextLeg.coords);
            me.can.nextLeg.setVisible(1);
        }
        else
            me.can.nextLeg.setVisible(0);
    },
#    _onVisibilityChange : func {
#        me.group.setVisible(me.visibility and (me.obsMode == 0));
#        me.groupTrack.setVisible(me.visibility and (me.obsMode == 0));
#        me.groupFMS.setVisible(me.visibility and (me.obsMode == 0));
#        me.groupOBS.setVisible(me.visibility and (me.obsMode == 1));
#        me.TOD.setVisible(fms._dynamicPoint.TOD.visible and me.visibility);
#        me.TOC.setVisible(fms._dynamicPoint.TOC.visible and me.visibility);
#        me.RTA.setVisible(fms._dynamicPoint.RTA.visible and me.visibility);
#    },
#    _onFplReadyChange : func (n) {
#        me.TOD.setVisible(fms._dynamicPoint.TOD.visible and me.visibility);
#        me.TOC.setVisible(fms._dynamicPoint.TOC.visible and me.visibility);
#        me.RTA.setVisible(fms._dynamicPoint.RTA.visible and me.visibility);
#    },
#    _onFplUpdatedChange : func (n) {
#        if (fms._dynamicPoint.TOD.visible)
#            me.TOD.setGeoPosition(fms._dynamicPoint.TOD.position.lat, fms._dynamicPoint.TOD.position.lon);
#        if (fms._dynamicPoint.TOC.visible)
#            me.TOC.setGeoPosition(fms._dynamicPoint.TOC.position.lat, fms._dynamicPoint.TOC.position.lon);
#        if (fms._dynamicPoint.RTA.visible)
#            me.RTA.setGeoPosition(fms._dynamicPoint.RTA.position.lat, fms._dynamicPoint.RTA.position.lon);  
#        
#        me.TOD.setVisible(fms._dynamicPoint.TOD.visible and me.visibility);
#        me.TOC.setVisible(fms._dynamicPoint.TOC.visible and me.visibility);
#        me.RTA.setVisible(fms._dynamicPoint.RTA.visible and me.visibility);
#    },
#    _onObsModeChange : func (n) {
#        me.obsMode = n.getValue();
#        
#        if (me.obsMode==1) {
#            var wp = {
#                wp_lat : getprop('/instrumentation/gps[0]/scratch/latitude-deg'),
#                wp_lon : getprop('/instrumentation/gps[0]/scratch/longitude-deg'),
#                wp_name : getprop('/instrumentation/gps[0]/scratch/ident'),
#            };
#            var acLat = getprop('/position/latitude-deg');
#            var acLon = getprop('/position/longitude-deg');
#            
#            me.groupOBS.setGeoPosition(wp.wp_lat, wp.wp_lon);
#            
#            me.obsCourseData.coords = [
#                0,
#                0,
#                0,
#                5000,
#            ];
#            
#            me.obsWaypoint._can.Label.setText(wp.wp_name);
#            me.obsWaypoint.setColor(1,0,1);
#            me.obsWaypoint._group.setVisible(1);
#            
#            me.can.obsCourse.setData(me.obsCourseData.cmds,me.obsCourseData.coords);
#        }
#        
#        me.groupTrack.setVisible(me.visibility and (me.obsMode == 0));
#        me.groupFMS.setVisible(me.visibility and (me.obsMode == 0));
#        me.groupOBS.setVisible(me.visibility and (me.obsMode == 1));
#    },
#    _onObsCourseChange : func (n) {
#        me.obsCourse = n.getValue();
#        me.can.obsCourse.setRotation((me.obsCourse - me.mapOptions.orientation) * global.CONST.DEG2RAD);
#    },
};

