/**
 * @category    BFD Webserver
 * @package     BFD
 * @author      Cameron Guest <cameron@aandtinstruments.com>, Sam Meredith <sam@aandtinstruments.com>
 * @version     2.0
 */

DEFAULT_MENUS = [
    {
        "id": 0x102,
        "name": "Speed",
        "count": 3,
        "channels": [ 65, 100, 127 ]
    },
    {
        "id": 0x103,
        "name": "Log",
        "count": 2,
        "channels": [ 205, 207 ]
    },
    {
        "id": 0x104,
        "name": "Depth",
        "count": 6,
        "channels": [ 193, 194, 195, 198, 199, 200 ]
    },
    {
        "id": 0x105,
        "name": "Navigate",
        "count": 7,
        "channels": [ 73, 105, 211, 129, 131, 132, 72 ]
    },
    {
        "id": 0x106,
        "name": "Wind",
        "count": 9,
        "channels": [ 81, 89, 109, 85, 86, 77, 79, 87, 90 ]
    },
    {}, // There is an empty slot here in the Fastnet menu structure
    {
        "id": 0x107,
        "name": "Perform",
        "count": 9,
        "channels": [ 52, 155, 60, 158, 154, 53, 130, 125, 83 ]
    },
    {
        "id": 0x108,
        "name": "Waypoint",
        "count": 14,
        "channels": [ 230, 229, 228, 227, 225, 224, 233, 234, 236, 238, 232, 231, 235, 237 ]
    },
    {
        "id": 0x10a,
        "name": "Environment",
        "count": 6,
        "channels": [ 29, 28, 31, 30, 135, 134 ]
    },
    {
        "id": 0x10b,
        "name": "Time",
        "count": 3,
        "channels": [ 117, 220, 221 ]
    },
    {
        "id": 0x10c,
        "name": "Analogue",
        "count": 5,
        "channels": [ 11, 56, 57, 58, 59 ]
    },
    {
        "id": 0x113,
        "name": "External",
        "count": 10,
        "channels": [ 239, 240, 241, 242, 243, 244, 245, 246, 247, 248 ]
    }
];

const DEFAULT_CHANNELS = [
    "Reset",
    "CH01",                         //0x01 Unused
    "CH02",                         //0x02 Unused
    "Load Cell 1",                  //0x03 Load Cell
    "Load Cell 2",                  //0x04 Load Cell
    "Load Cell 3",                  //0x05 Load Cell
    "Load Cell 4",                  //0x06 Load Cell
    "Load Cell 5",                  //0x07 Load Cell
    "Load Cell 6",                  //0x08 Load Cell
    "Load Cell 7",                  //0x09 Load Cell
    "Load Cell 8",                  //0x0a Load Cell
    "Rudder Angle",                 //0x0b Rudder Angle
    "Rudder Angle",                 //0x0c Rudder Angle
    "CH13",                         //0x0d Unused
    "CH14",                         //0x0e Unused
    "CH15",                         //0x0f Unused
    "Linear 5",                     //0x10 Linear
    "Linear 6",                     //0x11 Linear
    "Linear 7",                     //0x12 Linear
    "Linear 8",                     //0x13 Linear
    "Linear 9",                     //0x14 Linear
    "Linear 10",                    //0x15 Linear
    "Linear 11",                    //0x16 Linear
    "Linear 12",                    //0x17 Linear
    "Linear 13",                    //0x18 Linear
    "Linear 14",                    //0x19 Linear
    "Linear 15",                    //0x1a Linear
    "Linear 16",                    //0x1b Linear
    "Air Temp &deg;F",              //0x1c Air Temp F
    "Air Temp &deg;C",              //0x1d Air Temp C
    "Sea Temp &deg;F",              //0x1e Sea Temp F
    "Sea Temp &deg;C",              //0x1f Sea Temp C
    "CH32",                         //0x20
    "CH33",                         //0x21 Unused
    "CH34",                         //0x22 Unused
    "CH35",                         //0x23 Unused
    "CH36",                         //0x24 Unused
    "CH37",                         //0x25 Unused
    "CH38",                         //0x26 Unused
    "Head/Lift",                    //0x27 Head/Lift
    "CH40",                         //0x28 Unused
    "Off Course",                   //0x29 Off Course
    "Backstay/T",                   //0x2A Backstay tension from B&G Loadcell Amp
    "Port Runner",                  //0x2B Port runner from B&G Loadcell Amp
    "Stbd Runner",                  //0x2C Starboard runner from B&G Loadcell Amp
    "Port V1",                      //0x2D Port V1 from B&G Loadcell Amp
    "CH46",                         //0x2E Unused
    "CH47",                         //0x2F Unused
    "CH48",                         //0x30 Unused
    "CH49",                         //0x31 Unused
    "Tacking Perf",                 //0x32 Tracking Perf
    "Reaching Perf",                //0x33 Reaching Perf
    "Heel Angle",                   //0x34 Heel Angle
    "Optimum Wind Ang",             //0x35 Optimum Wind Ang
    "Depth Rx Gain",                //0x36 Depth Rx Gain
    "Depth Rx Noise",               //0x37 Depth Rx Noise
    "Linear 1",                     //0x38 Linear 1
    "Linear 2",                     //0x39 Linear 2
    "Linear 3",                     //0x3a Linear 3
    "Linear 4",                     //0x3b Linear 4
    "Roll Rate",                    //0x3c Roll Rate
    "Stbd V1",                      //0x3d Starboard V1 from B&G Loadcell Amp
    "Mainsheet",                    //0x3e Mainsheet tension from B&G Loadcell Amp
    "Inner Stay",                   //0x3f Inner stay from B&G Loadcell Amp
    "Forestay/T",                   //0x40 Forestay tension from B&G Loadcell Amp
    "Boat Speed kt",                //0x41 Boat Speed Kt
    "Boat Speed Raw",               //0x42 Boat Speed Raw
    "CH67",                         //0x43 Unused
    "Yaw Rate",                     //0x44 Yaw Rate
    "CH69",                         //0x45 Unused
    "Man Speed Kt",                 //0x46 Man Speed Kt
    "CH71",                         //0x47 Unused
    "Variation",                    //0x48 Unused
    "Heading &deg;M",               //0x49 Heading
    "Heading Raw",                  //0x4a Heading Raw
    "CH75",                         //0x4b Unused
    "CH76",                         //0x4c Unused
    "App Wind Speed kt",            //0x4d Apparent Wind Speed
    "App Wind Speed Raw",           //0x4e Raw Apparent Wind Speed
    "App Wind Speed m/s",           //0x4f Apparent Wind Speed
    "CH80",                         //0x50 Unused
    "App Wind Angle",               //0x51 Apparent Wind Angle
    "App Wind Angle Raw",           //0x52 Raw Apparent Wind Angle
    "Target TWA",                   //0x53 Target TWA
    "CH84",                         //0x54 Unused
    "True Wind Spd kt",             //0x55 True Wind Speed
    "True Wind Spd m/s",            //0x56 True Wind Speed
    "Measured W Spd kt",            //0x57 Measured Wind Speed
    "Measured W Spd m/s",           //0x58 Measured Wind Speed
    "True Wind Angle",              //0x59 True Wind Angle
    "Measured Wind Ang",            //0x5a Measured Wind Angle
    "CH91",                         //0x5b Unused
    "CH92",                         //0x5c Unused
    "CH93",                         //0x5d Unused
    "CH94",                         //0x5e Unused
    "CH95",                         //0x5f Unused
    "CH96",                         //0x60 Unused
    "CH97",                         //0x61 Unused
    "CH98",                         //0x62 Unused
    "CH99",                         //0x63 Unused
    "Ave Boat Speed kt",            //0x64 Average Boat Speed
    "Pulse 2",                      //0x65
    "CH102",                        //0x66 Unused
    "Canard Angle",                 //0x67 Canard Angle
    "Request for data",             //0x68
    "Course &deg;M",                //0x69 Course
    "Act for data",                 //0x6a
    "CH107",                        //0x6b Unused
    "CH108",                        //0x6c Unused
    "Wind Dir &deg;M",              //0x6d Wind Direction
    "CH110",                        //0x6e Unused
    "Nxt Leg AWA",                  //0x6f Next Leg AWA
    "Nxt Leg Tgt B Spd",            //0x70 Next Leg Target Boat Speed
    "Nxt Leg AWS",                  //0x71 Next Leg AWS
    "CH114",                        //0x72 Unused
    "CH115",                        //0x73 Unused
    "CH116",                        //0x74 Unused
    "Timer",                        //0x75 Timer
    "Watch",                        //0x76 Watch
    "Rolling 5",                    //0x77 
    "CH120",                        //0x78 Unused
    "CH121",                        //0x79 Unused
    "CH122",                        //0x7a Unused
    "CH123",                        //0x7b Unused
    "Polar Perf",                   //0x7c 
    "Target Boat Spd",              //0x7d
    "Polar Spd kt",                 //0x7e
    "VMG kt",                       //0x7f
    "CH128",                        //0x80 Unused
    "D/R Dist",                     //0x81
    "Leeway",                       //0x82
    "Current Rate",                 //0x83
    "Current Direction &deg;M",     //0x84
    "Upwash",                       //0x85
    "Press Trend",                  //0x86
    "Barometer",                    //0x87
    "CH136",                        //0x88 Unused
    "CH137",                        //0x89 Unused
    "CH138",                        //0x8a Unused
    "CH139",                        //0x8b Unused
    "CH140",                        //0x8c Unused
    "Battery Volts",                //0x8d
    "CH142",                        //0x8e Unused
    "CH143",                        //0x8f Unused
    "CH144",                        //0x90 Unused
    "CH145",                        //0x91 Unused
    "CH146",                        //0x92 Unused
    "CH147",                        //0x93 Unused
    "CH148",                        //0x94 Unused
    "CH149",                        //0x95 Unused
    "CH150",                        //0x96 Unused
    "CH151",                        //0x97 Unused
    "CH152",                        //0x98 Unused
    "CH153",                        //0x99 Unused
    "Opposite Tack &deg;M",         //0x9a
    "Fore/Aft Trim",                //0x9b
    "Mast Angle",                   //0x9c
    "Wind Ang to Mast",             //0x9d
    "Pitch Rate",                   //0x9e
    "CH159",                        //0x9f Unused
    "CH160",                        //0xa0 Unused
    "CH161",                        //0xa1 Unused
    "CH162",                        //0xa2 Unused
    "Daggerboard/Boom",             //0xa3
    "CH164",                        //0xa4 Unused
    "CH165",                        //0xa5 Unused
    "Pilot Course ",                //0xa6
    "CH167",                        //0xa7 Unused
    "CH168",                        //0xa8 Unused
    "CH169",                        //0xa9 Unused
    "CH170",                        //0xaa Unused
    "CH171",                        //0xab Unused
    "CH172",                        //0xac Unused
    "CH173",                        //0xad Unused
    "CH174",                        //0xae Unused
    "Comp Course Node",             //0xaf
    "CH176",                        //0xb0 Unused
    "CH177",                        //0xb1 Unused
    "CH178",                        //0xb2 Unused
    "CH179",                        //0xb3 Unused
    "Compass Swing",                //0xb4
    "CH181",                        //0xb5 Unused
    "CH182",                        //0xb6 Unused
    "CH183",                        //0xb7 Unused
    "CH184",                        //0xb8 Unused
    "CH185",                        //0xb9 Unused
    "Man Over",                     //0xba
    "CH187",                        //0xbb Unused
    "CH188",                        //0xbc Unused
    "CH189",                        //0xbd Unused
    "CH190",                        //0xbe Unused
    "CH191",                        //0xbf Unused
    "CH192",                        //0xc0 Unused
    "Depth Metres",                 //0xc1
    "Depth Feet",                   //0xc2
    "Depth Fathoms",                //0xc3
    "CH196",                        //0xc4 Unused
    "CH197",                        //0xc5 Unused
    "Aft Dpth Metres",              //0xc6
    "Aft Dpth Feet",                //0xc7
    "Aft Dpth Fathoms",             //0xc8
    "CH201",                        //0xc9 Unused
    "CH202",                        //0xca Unused
    "CH203",                        //0xcb Unused
    "CH204",                        //0xcc Unused
    "Stored Log nm",                //0xcd
    "CH206",                        //0xce
    "Trip Log nm",                  //0xcf
    "CH208",                        //0xd0 Unused
    "CH209",                        //0xd1 Unused
    "CH210",                        //0xd2 Unused
    "D/R Course &deg;M",            //0xd3 D/R Course
    "Time Elapsed",                 //0xd4 Time since MOB started
    "MOB Bearing &deg;M",           //0xd5 Bearing to MOB
    "MOB Range Metres",             //0xd6 Range to MOB
    "CH215",                        //0xd7 Unused
    "CH216",                        //0xd8 Unused
    "CH217",                        //0xd9 Unused
    "CH218",                        //0xda Unused
    "CH219",                        //0xdb Unused
    "Local Time",                   //0xdc
    "UTC Time",                     //0xdd
    "CH222",                        //0xde Unused
    "CH223",                        //0xdf Unused
    "Bear Wpt to Wpt &deg;T",       //0xe0
    "Bear Wpt to Wpt &deg;M",       //0xe1
    "Dist to Layline",              //0xe2
    "Bear to Wpt RL &deg;T",        //0xe3
    "Bear to Wpt RL &deg;M",        //0xe4
    "Bear to Wpt GC &deg;T",        //0xe5
    "Bear to Wpt GC &deg;M",        //0xe6
    "Dist to Wpt RL",               //0xe7
    "Dist to Wpt GC",               //0xe8
    "COG &deg;T",                   //0xe9
    "COG &deg;M",                   //0xea
    "SOG kt",                       //0xeb
    "VMG to Wpt",                   //0xec
    "Time to Wpt",                  //0xed
    "XTE",                          //0xee
    "Remote 0",                     //0xef
    "Remote 1",                     //0xf0
    "Remote 2",                     //0xf1
    "Remote 3",                     //0xf2
    "Remote 4",                     //0xf3
    "Remote 5",                     //0xf4
    "Remote 6",                     //0xf5
    "Remote 7",                     //0xf6
    "Remote 8",                     //0xf7
    "Remote 9",                     //0xf8
    "Crse to Sail",                 //0xf9
    "Nxt Wpt Dist",                 //0xfa
    "Waypoint Name",                //0xfb
    "Time to Layline",              //0xfc Time to Layline
    "CH253",                        //0xfd Unused
    "IP Address",                   //0xfe Unused
    "CH255",                        //0xff Unused
    "Boat Position"                 //0x100 Lat Long Special Channel
];

class ChannelMenu
{
    constructor() 
    {
        this.channels = [];
        this.menus = DEFAULT_MENUS;

        // Populate channel list with default channels.
        for (let i = 0; i <= 256; ++i)
        {
            this.channels[i] = { "channel": i, "name": DEFAULT_CHANNELS[i] };
        }
    }

    getChannel(channel)
    {
        return this.channels[channel] || this.channels[0];
    }

    getMenus()
    {
        return this.menus;
    }

    getMenuForChannel(channel)
    {
        // Return the first menu containing the given channel
        return this.menus.find(element => element && element.name !== "All" && element.channels && element.channels.indexOf(channel) != -1) || this.menus.find(element => element && element.name === "All");
    }

    getMenuForName(name)
    {
        return this.menus.find(element => element && element.name == name) || this.menus[0];
    }

    loadSavedChannels() 
    {
        let deferred = new $.Deferred();      
        let self = this; 

        $.when(readSection("MFDMenuItems"), readSection("MFDChannelNames"), readSingle("fastnetoutput", "compasstype")).done(function(menuSection, channelSection) 
        {
            let menuItems = JSON.parse(menuSection[0]);
            let channels = JSON.parse(channelSection[0]);

            if (menuItems && menuItems.hasOwnProperty("menuitems")) 
            {
                let ids = menuItems["menuitems"].split(',');
                for (let i = 0; i < ids.length; i++) 
                {
                    // The 0x7FF requirement is a bit arbitrary
                    // The ATP1 puts some menus with IDs 2111 -> 2124 that I want to ignore (no idea where they come from originally)
                    if (menuItems.hasOwnProperty(ids[i]))
                    {
                        const split = menuItems[ids[i]].split(',');
                        const label = split[0];
                        const channels = split.slice(1, split.length) || [];

                        let menu = self.menus.find(menu => menu.id === parseInt(ids[i]));
                        if (menu)
                        {
                            menu.name = label || menu.name;
                            if (channels && channels.length != 0)
                            {
                                menu.channels = channels.map(x => parseInt(x));
                            }
                        }
                        else
                        {
                            self.menus.push(
                                {
                                    "id": parseInt(ids[i]),
                                    "name": label || "Unknown",
                                    "count": channels.length,
                                    "channels": channels
                                }
                            )
                        }
                    }
                }
            }

            if (channels)
            {
                $.each(channels, function(key, value)
                {
                    // Expect a numeric key
                    if (!isNaN(key))
                    {
                        const channel = parseInt(key);
                        const values = value.split(',');
                        if (channel <= 256 && values.length > 2)
                        {
                            // Ignore empty names
                            if (values[1]) self.channels[channel].name = values[1].replace("%", "&deg;");
                        }
                    }                     
                })
            }

            // Finally add the ALL menu
            self.menus.push(
            {
                "id": undefined,
                "name": "All",
                "count": 255,
                "channels": [...Array(255).keys()].map(i => i + 1)
            }
            );

            deferred.resolve();
        });

        return deferred.promise();
    }
}