/**
 * Navigation Bar controller
 * 
 * Handles automatic resizing of the navigation bar
 * as well as drawing the sidebar
 * 
 * @category    Webserver
 * @package     ATProcessor
 * @author      Sam Meredith <sam@aandtinstruments.com>
 * @version     0.1
 */
class NavigationBar {
	constructor() {
		this.listWidthBreaks = [];
		
		this.isMOBActive;
		if (!sessionStorage.getItem('MOBActive')) {
			sessionStorage.setItem('MOBActive', 'false');
			this.isMOBActive = false;
		} else {
			this.isMOBActive = (sessionStorage.getItem('MOBActive') === 'true');
		}

		this.updateNavigationBar();
		this.drawSidebar();
		this.styleActiveHeading();

		$(window).on('resize', this.updateNavigationBar.bind(this));
		$('.nav button').on('click', this.toggleHiddenLinks);
	}
	
	// Retrieve sidebar headings and address object pairs then push them to array.
	retrieveSideBarInformation() {
		let deferred = $.Deferred();
		let heading = $(".content-wrapper").attr("data-heading");
		let headingList = [];

		switch(heading) {
			case "b&g":
				headingList.push(
					{ heading: "B&G Proprietary", address : "bandg.php" }
				);
				deferred.resolve(headingList);
				break;

			case "display":
            {
                let url = new URL(window.location.href);
                let bfd = url.searchParams.get("bfd");

                if (bfd)
                {
                    headingList.push(		
                        { heading : "Damping", address : "damping.php" },
                        { heading : "BFD & QBD", address : 
                            [
                                { heading : "Configuration", address: "dataPages.php?bfd=" + bfd },
                                { heading : "Splash Screen", address: "bfdSplash.php?bfd=" + bfd },
                                { heading : "Settings", address : "bfdSettings.php?bfd=" + bfd }
                            ]
                        },
                        { heading : "Fastnet", address : "fastnet.php" },
                        { heading : "Garmin", address : "garminUserData.php" },
                        { heading : "Pages", address : "dataPages.php" }
                    );
                }
                else
                {
                    headingList.push(		
                        { heading : "Damping", address : "damping.php" },
                        { heading : "BFD & QBD", address : "bfdServerStatus.php" },
                        { heading : "Fastnet", address : "fastnet.php" },
                        { heading : "Garmin", address : "garminUserData.php" },
                        { heading : "Pages", address : "dataPages.php" }
                    );
                }

				deferred.resolve(headingList);
				break;
            }

			case "home":
				headingList.push(		
					{ heading : "Alarms", address : "alarms.php" },
					{ heading : "Home", address : "home.php" },
					{ heading : "Man-Overboard", address : "manOverboard.php" }
				);
				deferred.resolve(headingList);
				break;

			case "other-data":
				headingList.push(
					{ heading : "Analogue", address : "analogue.php" },
					{ heading : "Barometer", address : "barometer.php" },
					{ heading : "CANbus", address : "canFilter.php" },
					{ heading : "Environment", address : "environmentVariables.php" },
					{ heading : "Expedition", address : 
						[
							{ heading : "Expedition Import", address : "externalChannels.php" },
							{ heading : "Expedition Export", address : "expeditionExport.php" }
						]	
					},
					{ heading : "Loadcells", address : "loadcell.php" },
					{ heading : "Navigation", address : "navigation.php" },
					{ heading : "NMEA0183", address : "nmeaFilter.php" },
					{ heading : "Rudder", address : "rudder.php" }
				);
				deferred.resolve(headingList);
				break;

			case "position":
				headingList.push(
					{ heading : "Position", address : "position.php" },
					{ heading : "Heading", address : "heading.php" },
					{ heading : "Heel", address : "heel.php" }
				);
				deferred.resolve(headingList);
				break;

			case "speed":
				readSingle("Settings", "SpeedInputs").done(function(numOfSources) {
					let linkAddress = "#";
					if (numOfSources === "1" || numOfSources === "") {
						linkAddress = "speedLog.php?src=0";
					} else {
						linkAddress = [ { heading : "Input Selection", address : "speedInputSelection.php" } ];
						for (let i = 0; i < numOfSources; i++)
							linkAddress.push( { heading: "Speed Input " + (i + 1), address: "speedLog.php?src=" + i } );
					}

					headingList.push(
						{ heading : "Speed", address : linkAddress }, 
						{ heading : "Trip/Stored Logs", address : "tripLogs.php" },
						{ heading : "Current", address: "current.php" },
						{ heading : "Leeway", address: "leeway.php" }	
					);
					deferred.resolve(headingList);
				} );
				break;
			
			case "depth":
				readSingle("depth", "sourcecount").done(function(numOfSources) {
					let linkAddress = "#"
					if(numOfSources === "1" || numOfSources === "") {
						linkAddress = "depth.php?src=0";
					} else {
						linkAddress = [ {heading: "Input Selection", address : "depthInputSelection.php"} ];
						for (let i = 0; i < numOfSources; i++)
							linkAddress.push( {heading: "Depth Input " + (i + 1), address: "depth.php?src=" + i} );
					}

					headingList.push( {heading : "Depth", address : linkAddress} );
					deferred.resolve(headingList);
				});
				break;
			
			case "wind":
				readSingle("Settings", "WindInputs").done(function(numSources) {
					let linkAddress = "windMeasured.php?src=0";
					let linkHeading = "Wind Measured";
					if (numSources > 1) {
						linkHeading = "Wind";
						linkAddress = [{ heading : "Input Selection", address : "windInputSelection.php" }];
						for (let i = 0; i < numSources; i++) {
							linkAddress.push( { heading : "Wind Input " + (i + 1), address : "windMeasured.php?src=" + i } );
						}
					}

					headingList.push(
						{ heading : linkHeading, address : linkAddress },
						{ heading : "Wind Calculations", address : "windCorrections.php?src=0" }
					);
					deferred.resolve(headingList);
				});
				break;

			case "settings":
			default:
				headingList.push(
					{ heading : "IP Address", address: "networkAddress.php"},
					{ heading : "System Settings", address : "globalSettings.php" },
					{ heading : "Network I/O", address : "dataOutput.php" },
					{ heading : "System Time", address : "time.php" },
					{ heading : "Software Upgrade", address : "softwareUpgrade.php" },
					{ heading : "Saved Configurations", address : "settings.php" },
					{ heading : "Event Logs", address : "logs.php" },
					{ heading : "Diagnostics", address :
						[
							{ heading : "All", address : "debug.php?FieldId=all-refresh" },
							{ heading : "NMEA0183", address : "debug.php?FieldId=NMEA" },
							{ heading : "Fastnet", address : "debug.php?FieldId=Fastnet" },
							{ heading : "Statistics", address : "debug.php?FieldId=statistics" },
							{ heading : "Expedition", address : "debug.php?FieldId=Expedition" },
							{ heading : "CANbus", address : "debug.php?FieldId=CanDevices" },
							{ heading : "TCP Connections", address : "debug.php?FieldId=tcpconnections" }
						]
					}
				);
				deferred.resolve(headingList);
				break;
		}
		return deferred.promise();
	}

	drawSidebar() {
		let self = this;

		this.retrieveSideBarInformation().done(function(headingList) {
			let pathString = (window.location.pathname + window.location.search).substring(1); // Remove '/' at the beggining of the string
			let menuList = $('<ul></ul>');
			let submenuListToggle;

			for (let i = 0; i < headingList.length; i++) {
				let menuItem = $('<li></li>');
				// Construct Menu
				let menu = headingList[i];
				if ($.isArray(menu.address)) {					
					menuItem.append('<a>' +  menu.heading + '<i class="fa fa-angle-double-down"></i></a>');
					
					let submenuList = $('<ul class="submenu"></ul>');
					for (let j = 0; j < menu.address.length; j++) {
						let submenu = menu.address[j];
						submenuList.append('<li><a href="' + submenu.address + '">' + submenu.heading + '</a></li>');

						if (submenu.address == pathString)
							submenuListToggle = submenuList;
					}

					menuItem.append(submenuList);
				} else {
					menuItem.append('<a href="' + menu.address + '">' + menu.heading + '</a>');
				}

				menuList.append(menuItem);				
			}

			// Add to DOM
			$('.sidebar').append(menuList);
			$('.sidebar').append(
					'<div class="MOB-warning" hidden>'
				+		'<i class="fa fa-exclamation-triangle fa-3x"></i><br>'
				+		'Man-Overboard'
				+	'</div>'
				+	'<div class="sidebar-bottom">'
				+		'<div class="flex-row">'
				+			'<div class="flex-half">'
				+				'UT'
				+			'</div>'
				+			'<div class="flex-half" id="UTCTime"></div>'
				+		'</div>'
				+		'<div class="flex-row">'
				+			'<div class="flex-half">'
				+				'Local'
				+			'</div>'
				+			'<div class="flex-half" id="LocalTime"></div>'
				+		'</div>'
				+	'</div>'
			);

			if (submenuListToggle)
				submenuListToggle.toggle();
		});
		
		// Submenu click handler
		$('.sidebar').on('click', 'li' , function() {
			$(this).find('ul').toggle();
			var $i = $(this).find('i');
			if ( $i.hasClass('fa-angle-double-down') ) {
				$i.removeClass('fa-angle-double-down');
				$i.addClass('fa-angle-double-up');
			} else {
				$i.addClass('fa-angle-double-down');
				$i.removeClass('fa-angle-double-up');
			}
		});

		// Check MOB status
		$('.MOB-warning').toggle(sessionStorage.getItem('MOBActive') === 'true');

		// Poll processor for time and MOB status
		setInterval(function() {
			$.ajax({
				type: 'POST',
				datatype: 'application/json',
				url:  '/atp.protocol.php',
				data: {
					action: 'queryProcessor',
					query:  'FieldId=0x1140,0x1141,0x1142,0x1143,0x1117'
				},
				timeout: 1000,
				success: function(result) {
					if (result.status) {
						var response = result.response;
						var fieldMatchRegex = /(0x.*)=\s?(.*)\r/g;
						var match = null;
						var parseFields = {};
						
						while ((match = fieldMatchRegex.exec(response)) !== null) {
							parseFields[match[1]] = match[2];
						}
						$('#UTCTime').html(parseFields['0x1143'] + '<br>' + parseFields['0x1142']);
						$('#LocalTime').html(parseFields['0x1141'] + '<br>' + parseFields['0x1140']);

						var MOBField = (parseFields.hasOwnProperty('0x1117')) ? parseFields['0x1117'] : 'n/a';
						if (MOBField.trim() == 'n/a') {
							$('.MOB-warning').hide();
							if (self.isMOBActive) {
								self.isMOBActive = false;
								sessionStorage.setItem('MOBActive', 'false');
								// Raise event for MOB page
								$(document).trigger('MOB-update');
							}
						} else {
							$('.MOB-warning').show();
							if (!self.isMOBActive) {
								self.isMOBActive = true;
								sessionStorage.setItem('MOBActive', 'true');
								$(document).trigger('MOB-update');
							}
						}
					}
				}
			});
		}, 1000);
	}

	updateNavigationBar() {
		var hamburger = $('.nav button');
		var hiddenLinks = $('.nav .hidden-links');
		var nav = $('.nav');
		var visibleLinks = $('.nav .visible-links');
		
		const hamburgerOffset = 10;		// Gap between right-most menu item and hamburger
		
		var availableSpace = hamburger.is(":visible") ? nav.width() - hamburger.outerWidth() - hamburgerOffset : 
			nav.width();
			
		if (visibleLinks.width() > availableSpace) {
			// Visible list is overflowing nav
			// Record the width of the list
			this.listWidthBreaks.push(visibleLinks.width());
			// Move an item to the hidden list
			visibleLinks.children().last().prependTo(hiddenLinks);
			// Make the hamburger visible
			if (!hamburger.is(":visible")) {
				hamburger.show();
			}
		} else {
			// There is space for another item
			if (availableSpace > this.listWidthBreaks[this.listWidthBreaks.length - 1]) {
				// Move item to visible list
				hiddenLinks.children().first().appendTo(visibleLinks);
				this.listWidthBreaks.pop();
			}
			// If hidden list is empty, hide the hamburger
			if (this.listWidthBreaks.length < 1) {
				hamburger.hide();
				hiddenLinks.hide();
			}
		}
		// Keep hamburger counter updated
		hamburger.attr('count', this.listWidthBreaks.length);
		
		// Adjust nav width, compensating for hamburger, logo and padding
		var sizeConst = parseFloat($('body').css('font-size'));
		var headerWidth = nav.closest('header').width() / sizeConst;
		var logoWidth = $('.site-title').width() / sizeConst;
		var hamburgerWidth = hamburger.is(":visible") ? hamburger.outerWidth() / sizeConst : 0;
		// Default width is 100 - 15 (logo) - 5 (margin) = 80%
		var availableNavWidth = Math.min(80, (headerWidth - logoWidth - hamburgerWidth) / headerWidth * 100);
		$('.nav-container').css("width", availableNavWidth + '%');
		
		// Recurse if visible list still overflowing
		if (visibleLinks.width() > availableSpace) {
			this.updateNavigationBar();
		}
	}
	
	// Show/hide hamburger menu
	toggleHiddenLinks() {
		$('.nav .hidden-links').toggle();
	}

	// Highlight the heading of the current page
	styleActiveHeading() {
		var activeHeading = $('.content-wrapper').attr('data-heading');
		$('.nav a[id="' + activeHeading + '"]').addClass('nav-item--selected');
	}
}
