WME Road Shield Assistant

Adds shield information display to WME

// ==UserScript==
// @name         WME Road Shield Assistant
// @namespace    https://greasyfork.org/en/users/286957-skidooguy
// @version      2023.08.26.00
// @description  Adds shield information display to WME 
// @author       SkiDooGuy
// @match        https://www.waze.com/editor*
// @match        https://www.waze.com/*/editor*
// @match        https://beta.waze.com/editor*
// @match        https://beta.waze.com/*/editor*
// @exclude      https://www.waze.com/user/editor*
// @require      https://greasyfork.org/scripts/24851-wazewrap/code/WazeWrap.js
// @grant        none
// @contributionURL https://github.com/WazeDev/Thank-The-Authors
// ==/UserScript==

/* global W */
/* global WazeWrap */
/* global $ */
/* global OL */
/* global _ */
/* global require */

const GF_LINK = 'https://greasyfork.org/en/scripts/425050-wme-road-shield-assisstant';
const FORUM_LINK = 'https://www.waze.com/forum/viewtopic.php?f=1851&t=315748';
const RSA_UPDATE_NOTES = `<b>NEW:</b><br>
- Updated shields for Canada<br><br>
<b>FIXES:</b><br>
- No longer highlights alt street names when it shouldn't<br><br>`;

    var [zm0, zm1, zm2, zm3, zm4, zm5, zm6, zm7, zm8, zm9, zm10] = [12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22]

const RoadAbbr = {
    //Canada    
	40: {
        "Alberta": {
            'Hwy 1$': 5000, 						            // 5000: National-Trans-Canada Highway
            'Hwy 1A': 5011,  						            // 5011: Alberta - Provincial Hwy
            'Hwy 2': 5011,							            // 5011: Alberta - Provincial Hwy
            'Hwy 3$' : 5015,						            // 5015: Alberta - Crowsnext Hwy
            'Hwy 3A' : 5011,						            // 5011: Alberta - Provincial Hwy
            'Hwy 16$' : 5000,						            // 5000: National-Trans-Canada Highway
            'Hwy 16A' : 5011,						            // 5011: Alberta - Provincial Hwy
            'Hwy ([4-9]|1[0-5])\b' : 5011, 					    // 5011: Alberta - Provincial Hwy
            'Hwy (1[7-9]|[2-9]\d|1\d{2}|20\d|21[0-6])\b' : 5011,// 5011: Alberta - Provincial Hwy
            'Hwy (21[7-9]|2[2-9]\d|[3-9]\d{2})\b' : 5011		// 5011: Alberta - Provincial Hwy
		},
		"British Columbia": {
            'Hwy 1': 5000, 							            // 5000: National-Trans-Canada Highway
            'Hwy 2': 5001,  						            // 5001: BC - Provincial Hwy
            'Hwy 3': 5002,  						            // 5002: BC - Crowsnest Hwy
            'Hwy 16': 5000,							            // 5000: National-Trans-Canada Highway
            'Hwy 113': 5004,						            // 5004: BC - Nisga'a Hwy
            'Hwy ([4-9]|[1-9]\d|10\d|11[0-2])\b' : 5001,		// 5001: BC - Provincial Hwy
            'Hwy (11[4-9]|1[2-9]\d|[2-9]\d{2})\b' : 5001		// 5001: BC - Provincial Hwy
		},
		"Saskatchewan": {
            'Hwy 1': 5000, 							            // 5000: National - Trans-Canada Hwy
            'Hwy 16' : 5000,						            // 5000: National - Trans-Canada Hwy
            'Hwy ([2-9]|1[0-5])\b' : 5030,					    // 5030: Saskatchewan - Provincial Hwy
            'Hwy (1[7-9]|[2-9]\d|[1-3]\d{2})\b' : 5030,			// 5030: Saskatchewan - Provincial Hwy
            'Hwy (90\d|9[1-9]\d)\b' : 5031,					    // 5031: Saskatchewan - Northern Secondary Hwy
            'Hwy (60\d|6[1-9]\d|7\d{2})\b' : 5032			    // 5032: Saskatchewan - Municipal Road
		},
		"Manitoba": {
            'Hwy 1': 5000, 							            // 5000: National - Trans-Canada Hwy
            'Hwy 16': 5000,							            // 5000: National - Trans-Canada Hwy
            'Hwy ([2-9]|1[0-5])\b': 5038,					    // 5038: Manitoba - Provincial Trunk Highway
            'Hwy (1[7-9]|[2-9]\d|1\d{2})\b': 5038,				// 5038: Manitoba - Provincial Trunk Highway
            'Hwy (20\d|2[1-9]\d|[3-9]\d{2})\b': 5039			// 5039: Manitoba - Provincial Rd
        },
		"Ontario": {
            'QEW': 5058, 							            // 5058: Ontario QEW
            'Hwy 17' : 5000,						            // 5000: National - Trans-Canada Hwy
            'Hwy 407 ETR' : 5060,						        // 5060: Ontario ETR
            'Hwy 412' : 5059,						            // 5059: Ontario Toll Hwy
            'Hwy 418' : 5059,						            // 5059: Ontario Toll Hwy
            'Hwy ([1-9]|1[0-6])\b' : 5057,					    // 5057: Ontario King's Hwy 1-16
            'Hwy (1[89]|[2-9]\d|[1-3]\d{2}|40[0-6])\b' : 5057,	// 5057: Ontario King's Hwy 18-406
            'Hwy (40[89]|41[01])\b' : 5057,					    // 5057: Ontario King's Hwy 408-411
            'Hwy (41[3-7])\b' : 5057,					        // 5057: Ontario King's Hwy 413-417
            'Hwy (419|4[2-9]\d)\b' : 5057,					    // 5057: Ontario King's Hwy 419-499
            'Hwy (50\d|5[1-9]\d|6\d{2})\b' : 5061,				// 5061: Ontario Secondary Hwy 500-699
            'Hwy (80\d|8[1-9]\d)\b' : 5057					    // 5057: Ontario Tertiary Hwy
		},
		"Quebec": {
            'Rte Transcanadienne' : 5093,					    // 5093: Quebec: Route Transcanadienne
            'Aut ([1-9]|[1-9]\d{1,2})\b' : 5090,				// 5090: Quebec Autoroute 1-999
            'Rte (10\d|1[1-9]\d|[23]\d{2})\b' : 5091,			// 5091: Quebec Route 100-399
            'R (10\d|1[1-9]\d|[2-9]\d{2}|1[0-4]\d{2}|15[0-5]\d)\b' : 5092	// 5092: Quebec Route 100-1559
		},
		"New Brunswick": {
            'Rte 2': 5000, 							            // 5000: Trans-Canada Hwy
            'Rte 16': 5000,							            // 5000: Trans-Canada Hwy
            'Rte 1': 5112,							            // 5112: NB Arterial Highway 1
            'Rte ([3-9]|1[0-5])\b' : 5112,					    // 5112: NB Arterial Highway 3-15
            'Rte (1[7-9]|[2-9]\d)\b' : 5112,				    // 5112: NB Arterial Highway 17-99
            'Rte (10\d|1[1-9]\d)\b' : 511,					    // 5113: NB Collector Highway 100-199
            'Rte (20\d|2[1-9]\d|[3-9]\d{2})\b' : 5114			// 5114: NB Local Highway 200-999
		},
		"Nova Scotia": {
            'Hwy ([1-9]|[1-9]\d)\b': 5116, 					    // 5116: NS Trunk Hwy 1-99
            'Hwy (10[0-4])\b': 5115,					        // 5115: NS Arterial Hwy 100-104
            'Hwy (10[5-6])\b': 5000,					        // 5000: National Trans Canada Highway 105-106
            'Hwy (10[7-9]|1[1-9]\d)\b' : 5115,				    // 5115: NS Aterial Hwy 107-199
            'Hwy (20\d|2[1-9]\d|3\d{2})\b' : 5117				// 5117: NS Collector Hwy 200-399
		},
		"Newfoundland & Labrador": {
            'Hwy 1': 5000, 							            // 5000: National - Trans-Canada Hwy 1
            'Hwy ([2-9]|[1-9]\d|[1-5]\d{2})\b' : 5129			// NLR: Newfoundland Labrador Route 2-599
		},
		"Prince Edward Island": {
            'Rte 1$': 5000,							            // 5000: National Trans-Canada Hwy
            'Rte ([2-9]|[1-9]\d{1,2})\b' : 5144				    // 5144: PEI - Provincial Highway
		},
		"Yukon": {
            'Hwy 1': 5145, 							            // 5145: Yukon - Territorial Hwy - Orange
            'Hwy 2': 5146, 							            // 5146: Yukon - Territorial Hwy - Amber
            'Hwy 3': 5147, 							            // 5147: Yukon - Territorial Hwy - Maroon
            'Hwy 4': 5148, 							            // 5148: Yukon - Territorial Hwy - Brown
            'Hwy 5': 5149, 							            // 5149: Yukon - Territorial Hwy - Blue
            'Hwy 6': 5150, 							            // 5150: Yukon - Territorial Hwy - Teal
            'Hwy 7': 5147, 							            // 5147: Yukon - Territorial Hwy - Maroon
            'Hwy 8': 5148, 							            // 5148: Yukon - Territorial Hwy - Brown
            'Hwy 9': 5151, 							            // 5151: Yukon - Territorial Hwy - Black
            'Hwy 10': 5151, 						            // 5151: Yukon - Territorial Hwy - Black
            'Hwy 11': 5149, 						            // 5149: Yukon - Territorial Hwy - Blue
            'Hwy 37': 5147 							            // 5147: Yukon - Territorial Hwy - Maroon
		},
		"Northwest Territories": {
            'Hwy ([1-9]|10)\b': 5152					        // 5152: NWT - Territorial Hwy 1-10
		}
	},
    // France
    73: {
        '': {
            'D[0-9]+[^:]*': 1092,
            'N[0-9]+[^:]*': 1072,
            'A[0-9]+[^:]*': 1072,
            'M[0-9]+[^:]*': 1067,
            'C[0-9]+[^:]*': 3333,
            'T[0-9]+[^:]*': 3037
        }
    },
    // Germany
    81: {
        '': {
            '(A[0-9]{1,3})': 1012,
            '(B[0-9]{1,3})': 1094
        }
    },
    // Mexico
    // 145: {

    // },

    // Ukraine
    232: {
        '': {
           '(E[0-9]{2,3})': 1048,
           '(М-[0-9]{2})': 1071,
           '(Н-[0-9]{2})': 1071,
           '(Р-[0-9]{2})': 1008,
           '(Т-[0-9]{2}-[0-9]{2,3})': 1008,
           '(О[0-9]{6,7})': 1085,
           '(С[0-9]{6,7})': 1085
       } 
    },
    // US
    235: {
        "Alabama": {
            'I-': 5,
            'US-': 6,
            "CR-": 2002,
            "SR-": 2019
        },
        "Alaska": {
            'I-': 5,
            'US-': 6,
            "CR-": 2002,
            "SR-": 2017
        },
        "Arizona": {
            'I-': 5,
            'US-': 6,
            "CR-": 2002,
            "SR-": 2022
        },
        "Arkansas": {
            'I-': 5,
            'US-': 6,
            "CR-": 2002,
            "AR-": 2020,
            "AR-$1 SPUR": 2020
        },
        "California": {
            'I-': 5,
            'US-': 6,
            "CR-": 2002,
            "SH-": 1082,
            "SR-": 1082
        },   
        "Colorado": {
            'I-': 5,
            'US-': 6,
            "CR-": 2002,
            "SH-": 2025,
            "SR-": 2025
        },
        "Connecticut": {
            'I-': 5,
            'US-': 6,
            "CR-": 2002,
            "SH-": 2027,
            "SR-": 2027
        },
        "Delaware": {
            'I-': 5,
            'US-': 6,
            "CR-": 2002,
            "SH-": 7,
            "SR-": 7
        },
        "District of Columbia": {
            'I-': 5,
            'US-': 6,
            "DC-": 7
        },
        "Florida": {
            'I-': 5,
            'US-': 6,
            "CR-": 2002,
            "SH-": 2030,
            "SR-": 2030
        },
        "Georgia": {
            'I-': 5,
            'US-': 6,
            "CR-": 2002,
            "SH-": 2036,
            "SR-": 2036
        },
        "Hawaii": {
            'I-': 5,
            'US-': 6,
            "CR-": 2002,
            "SH-": 2041,
            "SR-": 2041
        },
        "Idaho": {
            'I-': 5,
            'US-': 6,
            "CH-": 2002,
            "CR-": 2002,
            "SH-": 2043,
            "SR-": 2043
        },
        "Illinois": {
            'I-': 5,
            'US-': 6,
            "CH-": 2002,
            "CR-": 2002,
            "SH-": 2044,
            "SR-": 2044
        },
        "Indiana": {
            'I-': 5,
            'US-': 6,
            "CH-": 2002,
            "CR-": 2002,
            "SH-": 2045,
            "SR-": 2045,
            "IN-": 2045
        },
        "Iowa": {
            'I-': 5,
            'US-': 6,
            "CH-": 2002,
            "CR-": 2002,
            "SH-": 7,
            "SR-": 7,
            "IA-": 7
        },
        "Kansas": {
            'I-': 5,
            'US-': 6,
            "CH-": 2002,
            "CR-": 2002,
            "SH-": 2046,
            "SR-": 2046,
            "K-": 2046
        },
        "Kentucky": {
            'I-': 5,
            'US-': 6,
            "CH-": 2002,
            "CR-": 2002,
            "SH-": 7,
            "SR-": 7,
        },
        "Louisiana": {
            'I-': 5,
            'US-': 6,
            "CH-": 2002,
            "CR-": 2002,
            "SH-": 1117,
            "SR-": 1117,
            "LA-": 1117,
            "LA SPUR": 1115
        },
        "Maine": {
            'I-': 5,
            'US-': 6,
            "CH-": 2002,
            "CR-": 2002,
            "SH-": 2051,
            "SR-": 2051
        },
        "Maryland": {
            'I-': 5,
            'US-': 6,
            "CH-": 2002,
            "CR-": 2002,
            "SH-": 2053,
            "SR-": 2053,
            "MD-": 2053
        },
        "Massachusetts": {
            'I-': 5,
            'US-': 6,
            "CH-": 2002,
            "CR-": 2002,
            "SH-": 2055,
            "SR-": 2055
        },
        "Michigan": {
            'I-': 5,
            'US-': 6,
            'CR-': 2056,
            'M-': 2056,
            'SR-': 2056
        },
        "Minnesota": {
            'I-': 5,
            'US-': 6,
            "CH-": 2002,
            "CR-": 2002,
            "SH-": 2060,
            "SR-": 2060,
            "MN-": 2060
        },
        "Mississippi": {
            'I-': 5,
            'US-': 6,
            "SH-": 7,
            "SR-": 7,
            "MS-": 7
        },
        "Missouri": {
            'I-': 5,
            'US-': 6,
            "CH-": 2002,
            "CR-": 2002,
            "SH-": 2061,
            "SR-": 2061,
            "MO-": 2061
        },
        "Montana": {
            'I-': 5,
            'US-': 6,
            "CH-": 2002,
            "CR-": 2002,
            "SH-": 2063,
            "SR-": 2063
        },
        "Nebraska": {
            'I-': 5,
            'US-': 6,
            "CH-": 2002,
            "CR-": 2002,
            "SH-": 7,
            "SR-": 7,
            "L-": 7,
            "N-": 7,
            "S-": 7
        },
        "Nevada": {
            'I-': 5,
            'US-': 6,
            "CH-": 2002,
            "CR-": 2002,
            "SH-": 2086,
            "SR-": 2086
        },
        "New Hampshire": {
            'I-': 5,
            'US-': 6,
            "CH-": 2002,
            "CR-": 2002,
            "SH-": 2076,
            "SR-": 2076
        },
        "New Jersey": {
            'I-': 5,
            'US-': 6,
            "CH-": 2002,
            "CR-": 2002,
            "SH-": 7,
            "SR-": 7
        },
        "New Mexico": {
            'I-': 5,
            'US-': 6,
            "CH-": 2002,
            "CR-": 2002,
            "SH-": 2085,
            "SR-": 2085
        },
        "New York": {
            'I-': 5,
            'US-': 6,
            "CH-": 2002,
            "CR-": 2002,
            "SH-": 2087,
            "SR-": 2087,
            "NY-": 2087,
            "NY SPUR": 2087
        },
        "North Carolina": {
            'I-': 5,
            'US-': 6,
            "CH-": 2002,
            "CR-": 2002,
            "SH-": 2065,
            "SR-": 2065,
            "NC-": 2065
        },
        "North Dakota": {
            'I-': 5,
            'US-': 6,
            "CH-": 2002,
            "CR-": 2002,
            "SH-": 2070,
            "SR-": 2070,
            "ND-": 2070
        },
        "Ohio": {
            'I-': 5,
            'US-': 6,
            "CH-": 2002,
            "CR-": 2002,
            "SH-": 2095,
            "SR-": 2095
        },
        "Oklahoma": {
            'I-': 5,
            'US-': 6,
            "SH-": 2097,
            "SR-": 2097
        },
        "Oregon": {
            'I-': 5,
            'US-': 6,
            "CH-": 2002,
            "CR-": 2002,
            "SH-": 2099,
            "SR-": 2099
        },
        "Pennsylvania": {
            'I-': 5,
            'US-': 6,
            "CH-": 2002,
            "CR-": 2002,
            "SH-": 2101,
            "SR-": 2101
        },
        "Rhode Island": {
            'I-': 5,
            'US-': 6,
            "CH-": 2002,
            "CR-": 2002,
            "SH-": 2108,
            "SR-": 2108
        },
        "South Carolina": {
            'I-': 5,
            'US-': 6,
            "CH-": 2002,
            "CR-": 2002,
            "SH-": 2109,
            "SR-": 2109,
            "SC-": 2109
        },
        "South Dakota": {
            'I-': 5,
            'US-': 6,
            "CH-": 2002,
            "CR-": 2002,
            "SH-": 2114,
            "SR-": 2114,
            "SD-": 2114
        },
        "Tennessee": {
            'I-': 5,
            'US-': 6,
            "CH-": 2002,
            "CR-": 2002,
            "SH-": 2115,
            "SR-": 2115
        },
        "Texas": {
            'I-': 5,
            'US-': 6,
            "SH-": 2117,
            "SR-": 2117
        },
        "Utah": {
            'I-': 5,
            'US-': 6,
            "CH-": 2002,
            "CR-": 2002,
            "SH-": 2127,
            "SR-": 2127
        },
        "Vermont": {
            'I-': 5,
            'US-': 6,
            "CH-": 2002,
            "CR-": 2002,
            "SH-": 2131,
            "SR-": 2131
        },
        "Virginia": {
            'I-': 5,
            'US-': 6,
            "CH-": 2002,
            "CR-": 2002,
            "SH-": 2128,
            "SR-": 2128
        },
        "Washington": {
            'I-': 5,
            'US-': 6,
            "CH-": 2002,
            "CR-": 2002,
            "SH-": 2133,
            "SR-": 2133
        },
        "West Virginia": {
            'I-': 5,
            'US-': 6,
            "CH-": 2002,
            "CR-": 2002,
            "SH-": 2138,
            "SR-": 2138,
            "WV-": 2138,
        },
        "Wisconsin": {
            'I-': 5,
            'US-': 6,
            "CH-": 2137,
            "CR-": 2137,
            "SH-": 2135,
            "SR-": 2135,
            "WIS-": 2135,
            "WIS SPUR": 2135
        },
        "Wyoming": {
            'I-': 5,
            'US-': 6,
            "CH-": 2002,
            "CR-": 2002,
            "SH-": 2143,
            "SR-": 2143,
            "WY-": 2143,
        }
    },
    // Uruguay
    236: {
       '': {
           'Ruta': 1111
       } 
    },

    // Réunion
    262: {
        '': {
            'D[0-9]+[^:]*': 1092,
            'N[0-9]+[^:]*': 1072
        }
    },
    // Guadeloupe
    590: {
        '': {
            'D[0-9]+[^:]*': 1092,
            'N[0-9]+[^:]*': 1072
        }
    },
    // French Guyana
    594: {
        '': {
            'D[0-9]+[^:]*': 1092,
            'N[0-9]+[^:]*': 1072
        }
    },
    // Martinique
    596: {
        '': {
            'D[0-9]+[^:]*': 1092,
            'N[0-9]+[^:]*': 1072
        }
    },
    // Wallis and Futuna
    681: {
        '': {
            'D[0-9]+[^:]*': 1092,
            'N[0-9]+[^:]*': 1072
        }
    },
    // French Polynesia
    689: {
        '': {
            'D[0-9]+[^:]*': 1092,
            'N[0-9]+[^:]*': 1072
        }
    }
};
const Strings = {
    'en': {
        'enableScript': 'Script enabled',
        'HighSegShields': 'Segments with Shields',
        'HighSegShieldsClr': 'Segments with Shields',
        'ShowSegShields': 'Show Segment Shields on Map',
        'SegShieldMissing': 'Segments that might be missing shields',
        'SegShieldMissingClr': 'Segments that might be missing shields',
        'SegShieldError': "Segments that have shields but maybe shouldn't",
        'SegShieldErrorClr': "Segments that have shields but maybe shouldn't",
        'HighNodeShields': 'Nodes with Shields (TG)',
        'HighNodeShieldsClr': 'Nodes with Shields (TG)',
        'ShowNodeShields': 'Show Node Shield Info',
        'ShowExitShields': 'Has Exit Signs',
        'ShowTurnTTS': 'Has TIO',
        'AlertTurnTTS': 'Alert if TTS is different from default',
        'NodeShieldMissing': 'Nodes that might be missing shields',
        'NodeShieldMissingClr': 'Nodes that might be missing shields',
        'resetSettings': 'Reset Settings',
        'disabledFeat': '(Feature not configured for this country)',
        'ShowTowards': 'Has Towards',
        'ShowVisualInst': 'Has Visual Instruction',
        'SegHasDir': 'Segment Shields with direction',
        'SegHasDirClr': 'Segment Shields with direction',
        'SegInvDir': 'Segment Shields without direction',
        'SegInvDirClr': 'Segment Shields without direction',
        'IconHead': 'Map Icons',
        'HighlightHead': 'Highlights',
        'HighlightColors': 'Highlight Colors',
        'ShowRamps': 'Include Ramps',
        'mHPlus': 'Only show on minor highways or greater',
        'titleCase': 'Segments/nodes with direction not in large-and-small-caps format',
        'TitleCaseClr': 'Segments/nodes with direction not in large-and-small-caps format',
        'TitleCaseSftClr': 'Direction in free text might not be in large-and-small-caps format',
        'checkTWD': 'Include Towards field',
        'checkTTS': 'Include TTS field',
        'checkVI': 'Include Visual Instruction field'
    },
    'en-us': {
        'enableScript': 'Script enabled',
        'HighSegShields': 'Segments with Shields',
        'HighSegShieldsClr': 'Segments with Shields',
        'ShowSegShields': 'Show Segment Shields on Map',
        'SegShieldMissing': 'Segments that might be missing shields',
        'SegShieldMissingClr': 'Segments that might be missing shields',
        'SegShieldError': "Segments that have shields but maybe shouldn't",
        'SegShieldErrorClr': "Segments that have shields but maybe shouldn't",
        'HighNodeShields': 'Nodes with Shields (TG)',
        'HighNodeShieldsClr': 'Nodes with Shields (TG)',
        'ShowNodeShields': 'Show Node Shield Info',
        'ShowExitShields': 'Has Exit Signs',
        'ShowTurnTTS': 'Has TIO',
        'AlertTurnTTS': 'Alert if TTS is different from default',
        'NodeShieldMissing': 'Nodes that might be missing shields',
        'NodeShieldMissingClr': 'Nodes that might be missing shields',
        'resetSettings': 'Reset Settings',
        'disabledFeat': '(Feature not configured for this country)',
        'ShowTowards': 'Has Towards',
        'ShowVisualInst': 'Has Visual Instruction',
        'SegHasDir': 'Segment Shields with direction',
        'SegHasDirClr': 'Segment Shields with direction',
        'SegInvDir': 'Segment Shields without direction',
        'SegInvDirClr': 'Segment Shields without direction',
        'IconHead': 'Map Icons',
        'HighlightHead': 'Highlights',
        'HighlightColors': 'Highlight Colors',
        'ShowRamps': 'Include Ramps',
        'mHPlus': 'Only show on minor highways or greater',
        'titleCase': 'Segments/nodes with direction not in large-and-small-caps format',
        'TitleCaseClr': 'Segments/nodes with direction not in large-and-small-caps format',
        'TitleCaseSftClr': 'Direction in free text might not be in large-and-small-caps format',
        'checkTWD': 'Include Towards field',
        'checkTTS': 'Include TTS field',
        'checkVI': 'Include Visual Instruction field'
    },
    'es-419' : {
        'enableScript': 'Script habilitado',
        'HighSegShields': 'Segmentos con escudos',
        'HighSegShieldsClr': 'Segmentos con escudos',
        'ShowSegShields': 'Mostrar escudos de segmentos en el mapa',
        'SegShieldMissing': 'Segmentos a los que les pueden faltar escudos',
        'SegShieldMissingClr': 'Segmentos a los que les pueden faltar escudos',
        'SegShieldError': "Segmentos que tienen escudos y quizá no deberían",
        'SegShieldErrorClr': "Segmentos que tienen escudos y quizá no deberían",
        'HighNodeShields': 'Nodos con escudos (TG)',
        'HighNodeShieldsClr': 'Nodos con escudos (TG)',
        'ShowNodeShields': 'Mostrar Info de Escudo en Nodo',
        'ShowExitShields': 'Incluir iconos de giro (si existen)',
        'ShowTurnTTS': 'Incuir TTS',
        'AlertTurnTTS': 'Alertar si TTS fue modificado',
        'NodeShieldMissing': 'Nodos a los que les pueden faltar escudos',
        'NodeShieldMissingClr': 'Nodos a los que les pueden faltar escudos',
        'resetSettings': 'Reiniciar ajustes',
        'disabledFeat': '(Funcionalidad no configurada para ese país)',
        'ShowTowards': 'Incluir dirección (si existe)',
        'ShowVisualInst': 'Incluir instrucción visual',
        'SegHasDir': 'Escudos con dirección',
        'SegHasDirClr': 'Escudos con dirección',
        'SegInvDir': 'Escudos sin dirección',
        'SegInvDirClr': 'Escudos sin dirección',
        'IconHead': 'Iconos en mapa',
        'HighlightHead': 'Destacar',
        'HighlightColors': 'Reseña de Colores',
        'ShowRamps': 'Incluir Rampas',
        'mHPlus': 'Only show on minor highways or greater',
        'titleCase': 'Segments/nodes with direction not in large-and-small-caps format',
        'TitleCaseClr': 'Segments/nodes with direction not in large-and-small-caps format',
        'TitleCaseSftClr': 'Direction in free text might not be in large-and-small-caps format',
        'checkTWD': 'Include Towards field',
        'checkTTS': 'Include TTS field',
        'checkVI': 'Include Visual Instruction field'
    },
    'uk': {
        "enableScript":"Скріпт ввімкнено",
        "HighSegShields":"Сегменти з шильдами",
        "HighSegShieldsClr":"Сегменти з шильдами",
        "ShowSegShields":"Показувати шильди на мапі",
        "SegShieldMissing":"Сегменти, яким можливо потрібні шильди",
        "SegShieldMissingClr":"Сегменти, яким можливо потрібні шильди",
        "SegShieldError":"Сегменти, які мають шильди, але можливо вони непотрібні",
        "SegShieldErrorClr":"Сегменти, які мають шильди, але можливо вони непотрібні",
        "HighNodeShields":"Вузли з шильдами (TG)",
        "HighNodeShieldsClr":"Вузли з шильдами (TG)",
        "ShowNodeShields":"Показувати деталі шильда на вузлі ",
        "ShowExitShields":"Включити іконку повороту (якщо вони є)",
        "ShowTurnTTS":"Ввімкнути TTS",
        "AlertTurnTTS":"Сповіщати, якщо TTS відрізняється від типового",
        "NodeShieldMissing":"Вузли, на яких можуть бути відсутні щити",
        "NodeShieldMissingClr":"Вузли, на яких можуть бути відсутні щити",
        "resetSettings":"Скинути налаштування",
        "disabledFeat":"Відсутні налаштування для цієї страни",
        "ShowTowards":"Включаючи Towards (якщо існує)",
        "ShowVisualInst":"Включаючи візуальні інструкції",
        "SegHasDir":"Шильди з напрямками",
        "SegHasDirClr":"Шильди з напрямками",
        "SegInvDir":"Шильди без напрямків",
        "SegInvDirClr":"Шильди без напрямків",
        "IconHead":"Іконки на мапі",
        "HighlightHead":"Підсвічувати",
        "HighlightColors":"Кольори підсвічування",
        "ShowRamps":"Включаючи рампи",
        'mHPlus': 'Only show on minor highways or greater',
        'titleCase': 'Segments/nodes with direction not in large-and-small-caps format',
        'TitleCaseClr': 'Segments/nodes with direction not in large-and-small-caps format',
        'TitleCaseSftClr': 'Direction in free text might not be in large-and-small-caps format',
        'checkTWD': 'Include Towards field',
        'checkTTS': 'Include TTS field',
        'checkVI': 'Include Visual Instruction field'
    },
    'fr': {
        "enableScript":"Script activé",
        "HighSegShields":"Segments avec cartouche",
        "HighSegShieldsClr":"Segments avec cartouche",
        "ShowSegShields":"Afficher les cartouches sur la carte", 
        "SegShieldMissing":"Segments dont le cartouche pourrait manquer", 
        "SegShieldMissingClr":"Segments dont le cartouche pourrait manquer", 
        "SegShieldError":"Segments ayant un cartouche mais ne devraient peut-être pas", 
        "SegShieldErrorClr":"Segments ayant un cartouche mais ne devraient peut-être pas", 
        "HighNodeShields":"Noeuds avec cartouche (TG)", 
        "HighNodeShieldsClr":"Noeuds avec cartouche (TG)", 
        "ShowNodeShields":"Afficher les infos des cartouches de noeuds", 
        "ShowExitShields":"As des panneaux de sortie", 
        "ShowTurnTTS":"Has TIO", 
        "AlertTurnTTS":"Alert if TTS is different from default", 
        "NodeShieldMissing":"Noeud dont le cartouche pourrait manquer", 
        "NodeShieldMissingClr":"Noeud dont le cartouche pourrait manquer", 
        "resetSettings":"Réinitialiser les paramètres", 
        "disabledFeat":"Feature not configured for this country", 
        "ShowTowards":'As "En direction de"', 
        "ShowVisualInst":"As des instructions visuelles", 
        "SegHasDir":"Cartouche de segment avec direction", 
        "SegHasDirClr":"Cartouche de segment avec direction", 
        "SegInvDir":"Cartouche de segment sans direction", 
        "SegInvDirClr":"Cartouche de segment sans direction", 
        "IconHead":"Icônes de carte", 
        "HighlightHead":"Surlignages", 
        "HighlightColors":"Couleurs de surlignage", 
        "ShowRamps":"Inclure les bretelles", 
        "mHPlus":"Only show on minor highways or greater", 
        "titleCase":"Segments/nodes with direction not in large-and-small-caps format", 
        "TitleCaseClr":"Segments/nodes with direction not in large-and-small-caps format", 
        "TitleCaseSftClr":"Direction in free text might not be in large-and-small-caps format", 
        "checkTWD":'Inclure le champ "en direction de"', 
        "checkTTS":"Inclure le champ TTS", 
        "checkVI":"Inclure le champ d'instruction visuel"
    }
};
const CheckAltName = [
    // France
    73
];
let BadNames = [];
let rsaSettings;
let UpdateObj;
let SetTurn;
let rsaMapLayer;
let rsaIconLayer;
let LANG;

console.log('RSA: initializing...');

function rsaBootstrap(tries = 0) {
    if (W && W.map && W.model && W.loginManager.user && $ && WazeWrap.Ready) {
        initRSA();
    } else if (tries < 500) {
        setTimeout(() => {
            rsaBootstrap(tries + 1);
        }, 200);
    } else {
        console.error('RSA: Failed to load');
    }
}

function initRSA() {
    UpdateObj = require('Waze/Action/UpdateObject');
    SetTurn = require('Waze/Model/Graph/Actions/SetTurn');

    const rsaCss = [
        '.rsa-wrapper {position:relative;width:100%;font-size:12px;font-family:"Rubik", "Boing-light", sans-serif;user-select:none;}',
        '.rsa-section-wrapper {display:block;width:100%;padding:4px;}',
        '.rsa-section-wrapper.border {border-bottom:1px solid grey;margin-bottom:5px;}',
        '.rsa-header {font-weight:bold;}',
        '.rsa-option-container {padding:3px;}',
        '.rsa-option-container.no-display {display:none;}',
        '.rsa-option-container.sub {margin-left:20px;}',
        'input[type="checkbox"].rsa-checkbox {display:inline-block;position:relative;top:3px;vertical-align:top;margin:0;}',
        'input[type="color"].rsa-color-input {display:inline-block;position:relative;width:20px;padding:0px 1px;border:0px;vertical-align:top;cursor:pointer;}',
        'input[type="color"].rsa-color-input:focus {outline-width:0;}',
        'label.rsa-label {display:inline-block;position:relative;max-width:80%;vertical-align:top;font-weight:normal;padding-left:5px;word-wrap:break-word;}',
        '.group-title.toolbar-top-level-item-title.rsa:hover {cursor:pointer;}'
    ].join(' ');

    const $rsaTab = $('<div>');
    $rsaTab.html = ([
        `<div class='rsa-wrapper' id='rsa-tab-wrapper'>
            <div style='margin-bottom:5px;border-bottom:1px solid black;'>
                <span style='font-weight:bold;'>
                    <a href='https://www.waze.com/forum/viewtopic.php?f=1851&t=315748' target='_blank' style='text-decoration:none;'>Road Shield Assistant</a>
                </span> - v${GM_info.script.version}
            </div>
            <div class='rsa-option-container'>
                <input type=checkbox class='rsa-checkbox' id='rsa-enableScript' />
                <label class='rsa-label' for='rsa-enableScript'><span id='rsa-text-enableScript'></span></label>
            </div>
            <div class='rsa-option-container'>
                <input type=checkbox class='rsa-checkbox' id='rsa-ShowRamps' />
                <label class='rsa-label' for='rsa-ShowRamps'><span id='rsa-text-ShowRamps'></span></label>
            </div>
            <div class='rsa-option-container'>
                <input type=checkbox class='rsa-checkbox' id='rsa-mHPlus' />
                <label class='rsa-label' for='rsa-mHPlus'><span id='rsa-text-mHPlus'></span></label>
            </div>

            <span id='rsa-text-IconHead' class='rsa-header'></span>
            <div style='border-top:2px solid black;'>
                <div class='rsa-option-container'>
                    <input type=checkbox class='rsa-checkbox' id='rsa-ShowSegShields' />
                    <label class='rsa-label' for='rsa-ShowSegShields'><span id='rsa-text-ShowSegShields'></span></label>
                </div>
                <div class='rsa-option-container no-display'>
                    <input type=checkbox class='rsa-checkbox' id='rsa-NodeShieldMissing' />
                    <label class='rsa-label' for='rsa-NodeShieldMissing'><span id='rsa-text-NodeShieldMissing'></span></label>
                </div>
                <div class='rsa-option-container'>
                    <input type=checkbox class='rsa-checkbox' id='rsa-ShowNodeShields' />
                    <label class='rsa-label' for='rsa-ShowNodeShields'><span id='rsa-text-ShowNodeShields'></span></label>
                </div>
                <div class='rsa-option-container sub'>
                    <input type=checkbox class='rsa-checkbox' id='rsa-ShowExitShields' />
                    <label class='rsa-label' for='rsa-ShowExitShields'><span id='rsa-text-ShowExitShields'></span></label>
                </div>
                <div class='rsa-option-container sub'>
                    <input type=checkbox class='rsa-checkbox' id='rsa-ShowTurnTTS' />
                    <label class='rsa-label' for='rsa-ShowTurnTTS'><span id='rsa-text-ShowTurnTTS'></span></label>
                </div>
                <div class='rsa-option-container sub'>
                    <input type=checkbox class='rsa-checkbox' id='rsa-ShowTowards' />
                    <label class='rsa-label' for='rsa-ShowTowards'><span id='rsa-text-ShowTowards'></span></label>
                </div>
                <div class='rsa-option-container sub'>
                    <input type=checkbox class='rsa-checkbox' id='rsa-ShowVisualInst' />
                    <label class='rsa-label' for='rsa-ShowVisualInst'><span id='rsa-text-ShowVisualInst'></span></label>
                </div>
                <div class='rsa-option-container sub' style='display:none;'>
                    <input type=checkbox class='rsa-checkbox' id='rsa-AlertTurnTTS' />
                    <label class='rsa-label' for='rsa-AlertTurnTTS'><span id='rsa-text-AlertTurnTTS'></span></label>
                </div>
            </div>

            <span id='rsa-text-HighlightHead' class='rsa-header'></span>
            <div style='border-top:2px solid black;'>
                <div class='rsa-option-container' style='display:none;'>
                    <input type=checkbox class='rsa-checkbox' id='rsa-HighNodeShields' />
                    <label class='rsa-label' for='rsa-HighNodeShields'><span id='rsa-text-HighNodeShields'></span></label>
                </div>
                <div class='rsa-option-container'>
                    <input type=checkbox class='rsa-checkbox' id='rsa-HighSegShields' />
                    <label class='rsa-label' for='rsa-HighSegShields'><span id='rsa-text-HighSegShields'></span></label>
                </div>
                <div class='rsa-option-container'>
                    <input type=checkbox class='rsa-checkbox' id='rsa-SegHasDir' />
                    <label class='rsa-label' for='rsa-SegHasDir'><span id='rsa-text-SegHasDir'></span></label>
                </div>
                <div class='rsa-option-container'>
                    <input type=checkbox class='rsa-checkbox' id='rsa-SegInvDir' />
                    <label class='rsa-label' for='rsa-SegInvDir'><span id='rsa-text-SegInvDir'></span></label>
                </div>
                <div class='rsa-option-container' id='rsa-container-titleCase'>
                    <input type=checkbox class='rsa-checkbox' id='rsa-titleCase' />
                    <label class='rsa-label' for='rsa-titleCase'><span id='rsa-text-titleCase'></span></label>
                </div>
                <div class='rsa-option-container sub' id='rsa-container-checkTWD'>
                    <input type=checkbox class='rsa-checkbox' id='rsa-checkTWD' />
                    <label class='rsa-label' for='rsa-checkTWD'><span id='rsa-text-checkTWD'></span></label>
                </div>
                <div class='rsa-option-container sub' id='rsa-container-checkTTS'>
                    <input type=checkbox class='rsa-checkbox' id='rsa-checkTTS' />
                    <label class='rsa-label' for='rsa-checkTTS'><span id='rsa-text-checkTTS'></span></label>
                </div>
                <div class='rsa-option-container sub' id='rsa-container-checkVI'>
                    <input type=checkbox class='rsa-checkbox' id='rsa-checkVI' />
                    <label class='rsa-label' for='rsa-checkVI'><span id='rsa-text-checkVI'></span></label>
                </div>
                <div class='rsa-option-container'>
                    <input type=checkbox class='rsa-checkbox' id='rsa-SegShieldMissing' />
                    <label class='rsa-label' for='rsa-SegShieldMissing'><span id='rsa-text-SegShieldMissing'></span></label>
                </div>
                <div class='rsa-option-container'>
                    <input type=checkbox class='rsa-checkbox' id='rsa-SegShieldError' />
                    <label class='rsa-label' for='rsa-SegShieldError'><span id='rsa-text-SegShieldError'></span></label>
                </div>
            </div>

            <span id='rsa-text-HighlightColors' class='rsa-header'></span>
            <div style='border-top:2px solid black;'>
                <div class='rsa-option-container'>
                    <input type=color class='rsa-color-input' id='rsa-HighSegClr' />
                    <label class='rsa-label' for='rsa-HighSegClr'><span id='rsa-text-HighSegShieldsClr'></span></label>
                </div>
                <div class='rsa-option-container'>
                    <input type=color class='rsa-color-input' id='rsa-SegHasDirClr' />
                    <label class='rsa-label' for='rsa-SegHasDirClr'><span id='rsa-text-SegHasDirClr'></span></label>
                </div>
                <div class='rsa-option-container'>
                    <input type=color class='rsa-color-input' id='rsa-SegInvDirClr' />
                    <label class='rsa-label' for='rsa-SegInvDirClr'><span id='rsa-text-SegInvDirClr'></span></label>
                </div>
                <div class='rsa-option-container'>
                    <input type=color class='rsa-color-input' id='rsa-MissSegClr' />
                    <label class='rsa-label' for='rsa-MissSegClr'><span id='rsa-text-SegShieldMissingClr'></span></label>
                </div>
                <div class='rsa-option-container'>
                    <input type=color class='rsa-color-input' id='rsa-ErrSegClr' />
                    <label class='rsa-label' for='rsa-ErrSegClr'><span id='rsa-text-SegShieldErrorClr'></span></label>
                </div>
                <div class='rsa-option-container'>
                    <input type=color class='rsa-color-input' id='rsa-HighNodeClr' />
                    <label class='rsa-label' for='rsa-HighNodeClr'><span id='rsa-text-HighNodeShieldsClr'></span></label>
                </div>
                <div class='rsa-option-container no-display'>
                    <input type=color class='rsa-color-input' id='rsa-MissNodeClr' />
                    <label class='rsa-label' for='rsa-MissNodeClr'><span id='rsa-text-NodeShieldMissingClr'></span></label>
                </div>
                <div class='rsa-option-container' id='rsa-container-TitleCaseClr'>
                    <input type=color class='rsa-color-input' id='rsa-TitleCaseClr' />
                    <label class='rsa-label' for='rsa-TitleCaseClr'><span id='rsa-text-TitleCaseClr'></span></label>
                </div>
                <div class='rsa-option-container' id='rsa-container-TitleCaseSftClr'>
                    <input type=color class='rsa-color-input' id='rsa-TitleCaseSftClr' />
                    <label class='rsa-label' for='rsa-TitleCaseSftClr'><span id='rsa-text-TitleCaseSftClr'></span></label>
                </div>
            </div>

            <div style='border-top:2px solid black;'>
                <div class='rsa-option-container'>
                    <input type=button id='rsa-resetSettings' />
                </div>
            </div>
        </div>`
    ].join(' '));
    
    const $rsaFixWrapper = $('<div id="rsa-autoWrapper" class="toolbar-button ItemInactive" style="display:none;margin-right:5px;">');
    const $rsaFixInner = $('<div class="group-title toolbar-top-level-item-title rsa" style="margin:5px 0 0 15px;font-size:12px;">RSA Fix</div>');

    WazeWrap.Interface.Tab('RSA', $rsaTab.html, setupOptions, 'RSA');
    $(`<style type="text/css">${rsaCss}</style>`).appendTo('head');
    // $($rsaFixInner).appendTo($rsaFixWrapper);
    // $($rsaFixWrapper).appendTo($('#primary-toolbar > div'));
    WazeWrap.Interface.ShowScriptUpdate(GM_info.script.name, GM_info.script.version, RSA_UPDATE_NOTES, GF_LINK, FORUM_LINK);
    console.log('RSA: loaded');
}

async function setupOptions() {
    await loadSettings();

    // Create OL layer for display
    rsaMapLayer = new OpenLayers.Layer.Vector('rsaMapLayer', { uniqueName: 'rsaMapLayer' });
    W.map.addLayer(rsaMapLayer);
    rsaMapLayer.setVisibility(true);

    rsaIconLayer = new OpenLayers.Layer.Vector('rsaIconLayer', { uniqueName: 'rsaIconLayer' });
    W.map.addLayer(rsaIconLayer);
    rsaIconLayer.setVisibility(true);

    // Set user options
    function setEleStatus() {
        setChecked('rsa-enableScript', rsaSettings.enableScript);
        setChecked('rsa-HighSegShields', rsaSettings.HighSegShields);
        setChecked('rsa-ShowSegShields', rsaSettings.ShowSegShields);
        setChecked('rsa-SegShieldMissing', rsaSettings.SegShieldMissing);
        setChecked('rsa-SegShieldError', rsaSettings.SegShieldError);
        setChecked('rsa-HighNodeShields', rsaSettings.HighNodeShields);
        setChecked('rsa-ShowNodeShields', rsaSettings.ShowNodeShields);
        setChecked('rsa-ShowExitShields', rsaSettings.ShowExitShields);
        setChecked('rsa-ShowTurnTTS', rsaSettings.ShowTurnTTS);
        setChecked('rsa-AlertTurnTTS', rsaSettings.AlertTurnTTS);
        setChecked('rsa-ShowTowards', rsaSettings.ShowTowards);
        setChecked('rsa-ShowVisualInst', rsaSettings.ShowVisualInst);
        setChecked('rsa-NodeShieldMissing', rsaSettings.NodeShieldMissing);
        setChecked('rsa-SegHasDir', rsaSettings.SegHasDir);
        setChecked('rsa-SegInvDir', rsaSettings.SegInvDir);
        setChecked('rsa-ShowRamps', rsaSettings.ShowRamps);
        setChecked('rsa-mHPlus', rsaSettings.mHPlus);
        setChecked('rsa-titleCase', rsaSettings.titleCase);
        setChecked('rsa-checkTWD', rsaSettings.checkTWD);
        setChecked('rsa-checkTTS', rsaSettings.checkTTS);
        setChecked('rsa-checkVI', rsaSettings.checkVI);
        setValue('rsa-HighSegClr', rsaSettings.HighSegClr);
        setValue('rsa-MissSegClr', rsaSettings.MissSegClr);
        setValue('rsa-ErrSegClr', rsaSettings.ErrSegClr);
        setValue('rsa-HighNodeClr', rsaSettings.HighNodeClr);
        setValue('rsa-MissNodeClr', rsaSettings.MissNodeClr);
        setValue('rsa-SegHasDirClr', rsaSettings.SegHasDirClr);
        setValue('rsa-SegInvDirClr', rsaSettings.SegInvDirClr);
        setValue('rsa-TitleCaseClr', rsaSettings.TitleCaseClr);
        setValue('rsa-TitleCaseSftClr', rsaSettings.TitleCaseSftClr);

        if (rsaSettings.titleCase === true && W.model.getTopCountry().attributes.id === 235) {
            $('#rsa-container-checkTWD').css('display', 'block');
            $('#rsa-container-checkTTS').css('display', 'block');
            $('#rsa-container-checkVI').css('display', 'block');
        } else {
            $('#rsa-container-checkTWD').css('display', 'none');
            $('#rsa-container-checkTTS').css('display', 'none');
            $('#rsa-container-checkVI').css('display', 'none');
        }

        function setChecked(ele, status) {
            $(`#${ele}`).prop('checked', status);
        }

        function setValue(ele, value) {
            const inputElem = $(`#${ele}`);
            inputElem.attr('value', value);
            // inputElem.css('border', `1px solid ${value}`);
        }
    }

    // Register event listeners
    WazeWrap.Events.register('selectionchanged', null, removeAutoFixButton);
    WazeWrap.Events.register('selectionchanged', null, tryScan);
    WazeWrap.Events.register('moveend', null, removeAutoFixButton);
    WazeWrap.Events.register('moveend', null, tryScan);
    WazeWrap.Events.register('moveend', null, checkOptions);
    WazeWrap.Events.register('afteraction', null, tryScan);

    new WazeWrap.Interface.Shortcut('addShield', 'Activates the Add Shield Button', 'wmersa', 'Road Shield Assistant', rsaSettings.addShield, addShieldClick, null).add();

    setEleStatus();

    $('.rsa-checkbox').change(function () {
        let settingName = $(this)[0].id.substr(4);
        rsaSettings[settingName] = this.checked;

        // Check to ensure highlight nodes and show node shields don't onverlap each other
        // if (settingName = 'ShowNodeShields') {
        //     if (this.checked) {
        //         $('rsa-HighNodeShields').prop('checked', false);
        //         rsaSettings.HighNodeShields = false;
        //     }
        // } else if (settingName = 'HighNodeShields') {
        //     if (this.checked) {
        //         $('rsa-ShowNodeShields').prop('checked', false);
        //         rsaSettings.ShowNodeShields = false;
        //     }
        // }

        saveSettings();

        removeHighlights();
        tryScan();
    });
    $('.rsa-color-input').change(function () {
        let settingName = $(this)[0].id.substr(4);
        rsaSettings[settingName] = this.value;
        saveSettings();
        setEleStatus();
        removeHighlights();
        tryScan();
    });
    $('#rsa-titleCase').click(function () {
        if (getId('rsa-titleCase').checked) {
            $('#rsa-container-checkTWD').css('display', 'block');
            $('#rsa-container-checkTTS').css('display', 'block');
            $('#rsa-container-checkVI').css('display', 'block');
        } else {
            $('#rsa-container-checkTWD').css('display', 'none');
            $('#rsa-container-checkTTS').css('display', 'none');
            $('#rsa-container-checkVI').css('display', 'none');
        }
    });
    // $('#rsa-ShowNodeShields').click(function() {
    //     if (!getId('rsa-ShowNodeShields').checked) $('.rsa-option-container.sub').hide();
    //     else $('.rsa-option-container.sub').show();
    // });
    $('#rsa-resetSettings').click(function() {
        const defaultSettings = {
            lastSaveAction: 0,
            enableScript: true,
            HighSegShields: false,
            ShowSegShields: true,
            SegShieldMissing: false,
            SegShieldError: false,
            SegHasDir: false,
            SegInvDir: false,
            HighNodeShields: true,
            ShowNodeShields: false,
            ShowExitShields: false,
            ShowTurnTTS: false,
            AlertTurnTTS: false,
            ShowTowards: false,
            ShowVisualInst: false,
            NodeShieldMissing: false,
            HighSegClr: '#0066ff',
            MissSegClr: '#00ff00',
            ErrSegClr: '#cc00ff',
            HighNodeClr: '#ff00bf',
            MissNodeClr: '#ff0000',
            SegHasDirClr: '#ffff00',
            SegInvDirClr: '#66ffff'
        }

        rsaSettings = defaultSettings;
        saveSettings();
        setEleStatus();
    });
    // Add translated UI text
    LANG = I18n.currentLocale().toLowerCase();
    if (!Strings[LANG]) LANG = 'en';
    for (let i=0; i < Object.keys(Strings[LANG]).length; i++) {
        let key = Object.keys(Strings[LANG])[i]
        $(`#rsa-text-${key}`).text(Strings[LANG][key]);
    }
    $('#rsa-resetSettings').attr('value', Strings[LANG]['resetSettings']);

    checkOptions();
}

async function loadSettings() {
    const localSettings = $.parseJSON(localStorage.getItem('RSA_Settings'));
    const serverSettings = await WazeWrap.Remote.RetrieveSettings('RSA_Settings');
    if (!serverSettings) {
        console.error('RSA: Error communicating with WW settings server');
    }

    const defaultSettings = {
        lastSaveAction: 0,
        enableScript: true,
        HighSegShields: false,
        ShowSegShields: true,
        SegShieldMissing: false,
        SegShieldError: false,
        SegHasDir: false,
        SegInvDir: false,
        HighNodeShields: true,
        ShowNodeShields: false,
        ShowExitShields: false,
        ShowTurnTTS: false,
        AlertTurnTTS: false,
        ShowTowards: false,
        ShowVisualInst: false,
        NodeShieldMissing: false,
        HighSegClr: '#0066ff',
        MissSegClr: '#00ff00',
        ErrSegClr: '#cc00ff',
        HighNodeClr: '#ff00bf',
        MissNodeClr: '#ff0000',
        SegHasDirClr: '#ffff00',
        SegInvDirClr: '#66ffff',
        TitleCaseClr: '#ff9933',
        TitleCaseSftClr: '#ffff66',
        ShowRamps: true,
        mHPlus: false,
        titleCase: false,
        checkTWD: false,
        checkTTS: false,
        checkVI: false,
        addShield: ''
    };

    rsaSettings = $.extend({}, defaultSettings, localSettings);
    if (serverSettings && serverSettings.lastSaveAction > rsaSettings.lastSaveAction) {
        $.extend(rsaSettings, serverSettings);
        // console.log('RSA: server settings used');
    } else {
        // console.log('RSA: local settings used');
    }

    // If there is no value set in any of the stored settings then use the default
    Object.keys(defaultSettings).forEach((funcProp) => {
        if (!rsaSettings.hasOwnProperty(funcProp)) {
            rsaSettings[funcProp] = defaultSettings[funcProp];
        }
    });
}

async function saveSettings() {
    const {
        enableScript,
        HighSegShields,
        ShowSegShields,
        SegShieldMissing,
        SegShieldError,
        HighNodeShields,
        ShowNodeShields,
        ShowExitShields,
        SegHasDir,
        SegInvDir,
        ShowTurnTTS,
        AlertTurnTTS,
        ShowTowards,
        ShowVisualInst,
        NodeShieldMissing,
        HighSegClr,
        MissSegClr,
        ErrSegClr,
        HighNodeClr,
        MissNodeClr,
        SegHasDirClr,
        SegInvDirClr,
        TitleCaseClr,
        TitleCaseSftClr,
        ShowRamps,
        mHPlus,
        titleCase,
        checkTWD,
        checkTTS,
        checkVI,
        addShield
    } = rsaSettings;

    const localSettings = {
        lastSaveAction: Date.now(),
        enableScript,
        HighSegShields,
        ShowSegShields,
        SegShieldMissing,
        SegShieldError,
        HighNodeShields,
        ShowNodeShields,
        ShowExitShields,
        SegHasDir,
        SegInvDir,
        ShowTurnTTS,
        AlertTurnTTS,
        ShowTowards,
        ShowVisualInst,
        NodeShieldMissing,
        HighSegClr,
        MissSegClr,
        ErrSegClr,
        HighNodeClr,
        MissNodeClr,
        SegHasDirClr,
        SegInvDirClr,
        TitleCaseClr,
        TitleCaseSftClr,
        ShowRamps,
        mHPlus,
        titleCase,
        checkTWD,
        checkTTS,
        checkVI,
        addShield
    };

    // Grab keyboard shortcuts and store them for saving
    for (const name in W.accelerators.Actions) {
        const {shortcut, group} = W.accelerators.Actions[name];
        if (group === 'wmersa') {
            let TempKeys = '';
            if (shortcut) {
                if (shortcut.altKey === true) {
                    TempKeys += 'A';
                }
                if (shortcut.shiftKey === true) {
                    TempKeys += 'S';
                }
                if (shortcut.ctrlKey === true) {
                    TempKeys += 'C';
                }
                if (TempKeys !== '') {
                    TempKeys += '+';
                }
                if (shortcut.keyCode) {
                    TempKeys += shortcut.keyCode;
                }
            } else {
                TempKeys = '-1';
            }
            localSettings[name] = TempKeys;
        }
    }

    // Required for the instant update of changes to the keyboard shortcuts on the UI
    rsaSettings = localSettings;

    if (localStorage) {
        localStorage.setItem('RSA_Settings', JSON.stringify(localSettings));
    }
    const serverSave = await WazeWrap.Remote.SaveSettings('RSA_Settings', localSettings);

    if (serverSave === null) {
        console.warn('RSA: User PIN not set in WazeWrap tab');
    } else {
        if (serverSave === false) {
            console.error('RSA: Unable to save settings to server');
        }
    }
}

function getId(ele) {
    return document.getElementById(ele);
}

function checkOptions() {
    const countries = W.model.countries.getObjectArray();

    if (countries.length < 1) {
        setTimeout(function() { checkOptions(); }, 500);
        return;
    } else {
        let allowFeat = false;

        for (let i=0; i < countries.length; i++) {
            if (RoadAbbr[countries[i].id]) allowFeat = true;
        }

        if (!allowFeat) {
            $(`#rsa-text-SegShieldMissing`).prop('checked', false);
            $(`#rsa-text-SegShieldError`).prop('checked', false);
            $(`#rsa-text-NodeShieldMissing`).prop('checked', false);

            $(`#rsa-text-SegShieldMissing`).text(Strings[LANG]['SegShieldMissing'] + ' ' + Strings[LANG]['disabledFeat']);
            $(`#rsa-text-SegShieldError`).text(Strings[LANG]['SegShieldError'] + ' ' + Strings[LANG]['disabledFeat']);
            $(`#rsa-text-NodeShieldMissing`).text(Strings[LANG]['NodeShieldMissing'] + ' ' + Strings[LANG]['disabledFeat']);

            $(`#rsa-SegShieldMissing`).prop('disabled', true);
            $(`#rsa-SegShieldError`).prop('disabled', true);
            $(`#rsa-NodeShieldMissing`).prop('disabled', true);

            rsaSettings.SegShieldMissing = false;
            rsaSettings.SegShieldError = false;
            rsaSettings.NodeShieldMissing = false;
            saveSettings();
        } else {
            $(`#rsa-text-SegShieldMissing`).prop('checked', rsaSettings.SegShieldMissing);
            $(`#rsa-text-SegShieldError`).prop('checked', rsaSettings.SegShieldError);
            $(`#rsa-text-NodeShieldMissing`).prop('checked', rsaSettings.NodeShieldMissing);

            $(`#rsa-text-SegShieldMissing`).text(Strings[LANG]['SegShieldMissing']);
            $(`#rsa-text-SegShieldError`).text(Strings[LANG]['SegShieldError']);
            $(`#rsa-text-NodeShieldMissing`).text(Strings[LANG]['NodeShieldMissing']);

            $(`#rsa-SegShieldMissing`).prop('disabled', false);
            $(`#rsa-SegShieldError`).prop('disabled', false);
            $(`#rsa-NodeShieldMissing`).prop('disabled', false);
        }
    }

    if (W.model.getTopCountry().attributes.id !== 235) {
        $('#rsa-container-titleCase').css('display', 'none');
        $('#rsa-container-TitleCaseClr').css('display', 'none');
        $('#rsa-container-TitleCaseSftClr').css('display', 'none');
    } else {
        $('#rsa-container-titleCase').css('display', 'block');
        $('#rsa-container-TitleCaseClr').css('display', 'block');
        $('#rsa-container-TitleCaseSftClr').css('display', 'block');
    }
}

function autoFixButton() {
    $('#rsa-autoWrapper').css('display', 'inline-block');
    $('#rsa-autoWrapper > div').off();

    // console.log(BadNames);
    // Create function to fix case types when button clicked
    $('#rsa-autoWrapper > div').click(function() {
        const turnGraph = W.model.getTurnGraph();

        for (let i=0; i < BadNames.length; i++) {
            // Check if street or turn
            if (BadNames[i].type) {
                let strt = BadNames[i];
                let dir = strt.direction;

                if (dir.match(/\b(north)\b/i) != null)  dir = 'Nᴏʀᴛʜ';
                if (dir.match(/\b(south)\b/i) != null)  dir = 'Sᴏᴜᴛʜ';
                if (dir.match(/\b(east)\b/i) != null)  dir = 'Eᴀꜱᴛ';
                if (dir.match(/\b(west)\b/i) != null)  dir = 'Wᴇꜱᴛ';

                W.model.actionManager.add(new UpdateObj(strt, { 'direction': dir }));
            } else {
                function fixName(name) {
                    let temp = name;
                    temp = temp.replace(/\b(north)\b/ig, 'Nᴏʀᴛʜ');
                    temp = temp.replace(/\b(south)\b/ig, 'Sᴏᴜᴛʜ');
                    temp = temp.replace(/\b(east)\b/ig, 'Eᴀꜱᴛ');
                    temp = temp.replace(/\b(west)\b/ig, 'Wᴇꜱᴛ');

                    temp = temp.replace(/\b(TO)\b/ig, 'ᴛᴏ');
                    temp = temp.replace(/\b(VIA)\b/ig, 'ᴠɪᴀ');
                    temp = temp.replace(/\b(JCT)\b/ig, 'ᴊᴄᴛ');
                    return temp;
                }

                let turn = BadNames[i];
                let turnDat = turn.getTurnData();
                let turnGuid = turnDat.getTurnGuidance();
                let newGuid = turnGuid;
                console.log(turn);
                for (s in turnGuid.roadShields) {
                    turnGuid.roadShields[s].direction = fixName(turnGuid.roadShields[s].direction);
                };
                if (rsaSettings.checkTWD && turnGuid.towards) turnGuid.towards = fixName(turnGuid.towards);
                if (rsaSettings.checkTTS && turnGuid.tts) turnGuid.tts = fixName(turnGuid.tts);
                if (rsaSettings.checkVI && turnGuid.visualInstruction) turnGuid.visualInstruction = fixName(turnGuid.visualInstruction);

                console.log(turnGuid);
                turnDat = turnDat.withTurnGuidance(turnGuid);
                W.model.actionManager.add(new SetTurn(turnGraph, turn.withTurnData(turnDat)));
            }
        }
    });
}

function removeAutoFixButton() {
    $('#rsa-autoWrapper > div').off();
    $('#rsa-autoWrapper').css('display', 'none');
}

function addShieldClick() {
    const selFea = W.selectionManager.getSelectedFeatures();
    if (selFea && selFea.length === 1 && selFea[0].WW.getType() === 'segment') {
        $('.add-new-road-shield').click();
    } else {
        WazeWrap.Alerts.error(GM_info.script.name, 'You must have only 1 segment selected to use the shield editing menu');
    }

    
}

function tryScan() {
    if (!rsaSettings.enableScript) return;

    // Reset the array of objects that need names fixed
    BadNames = [];

    function scanNode(node) {
        let conSegs = node.attributes.segIDs;

        for (let i=0; i < conSegs.length; i++) {
            let seg1 = W.model.segments.getObjectById(conSegs[i]);
            for (let j=0; j < conSegs.length; j++) {
                let seg2 = W.model.segments.getObjectById(conSegs[j]);
                processNode(node, seg1, seg2);
            }
        }
    }

    function scanSeg(seg, showInfo = false) {
        processSeg(seg, showInfo);
    }

    removeHighlights();
    let selFea = W.selectionManager.getSelectedFeatures();
    if (selFea && selFea.length > 0) {
        // if (selFea.model.type === 'segment') scanSeg(selFea.model, true);
    } else {
        // Scan all segments on screen
        if (rsaSettings.ShowSegShields || rsaSettings.SegShieldMissing || rsaSettings.SegShieldError || rsaSettings.HighSegShields || rsaSettings.titleCase) {
            _.each(W.model.segments.getObjectArray(), s => {
                scanSeg(s);
            });
        }
        // Scan all nodes on screen
        if (rsaSettings.HighNodeShields || rsaSettings.ShowNodeShields || rsaSettings.titleCase) {
            _.each(W.model.nodes.getObjectArray(), n => {
                scanNode(n);
            });
        }
       
    }
}

function processSeg(seg, showNode = false) {
    let segAtt = seg.attributes;
    let street = W.model.streets.getObjectById(segAtt.primaryStreetID).attributes;
    let cityID = W.model.cities.getObjectById(street.cityID).attributes;
    let stateName = W.model.states.getObjectById(cityID.stateID).attributes.name;
    let countryID = cityID.countryID;
    let candidate = isSegmentCandidate(segAtt, stateName, countryID);
    let hasShield = street.signType !== null;

    // Exlude ramps
    if (!rsaSettings.ShowRamps && segAtt.roadType === 4) return;

    // Only show mH and above
    if (rsaSettings.mHPlus && segAtt.roadType != 3 && segAtt.roadType != 4 && segAtt.roadType != 6 && segAtt.roadType != 7) return;

    // Display shield on map
    if (hasShield && rsaSettings.ShowSegShields) displaySegShields(seg, street.signType, street.signText, street.direction);

    // If candidate and has shield
    if (candidate.isCandidate && hasShield && rsaSettings.HighSegShields) {
        if (isValidShield(segAtt)) {
            createHighlight(seg, rsaSettings.HighSegClr);
        } else {
            createHighlight(seg, rsaSettings.ErrSegClr);
        }
    }

    // If candidate and missing shield
    if (candidate.isCandidate && !hasShield && rsaSettings.SegShieldMissing) createHighlight(seg, rsaSettings.MissSegClr);

    // If not candidate and has shield
    if (!candidate.isCandidate && hasShield && rsaSettings.SegShieldError) createHighlight(seg, rsaSettings.ErrSegClr);

    // Highlight seg shields with direction
    if (hasShield && street.direction && rsaSettings.SegHasDir) createHighlight(seg, rsaSettings.SegHasDirClr);
    if (hasShield && !street.direction && rsaSettings.SegInvDir) createHighlight(seg, rsaSettings.SegInvDirClr);

    // Streets without capitalized letters
    if (rsaSettings.titleCase) {
        const badName = matchTitleCase(street);
        if (badName === true) {
            createHighlight(seg, rsaSettings.TitleCaseClr, true);
            // autoFixButton();
        }
    }
}

function processNode(node, seg1, seg2) {
    let turn = W.model.getTurnGraph().getTurnThroughNode(node,seg1,seg2);
    let turnData = turn.getTurnData();
    let hasGuidence = turnData.hasTurnGuidance();

    if (hasGuidence) {
        if (rsaSettings.ShowNodeShields && W.map.getZoom() > 14) displayNodeIcons(node, turnData);

        if (rsaSettings.titleCase) {
            let badName = matchTitleCaseThroughNode(turn);
            if (badName.isBad === true) {
                let color = badName.softIssue ? rsaSettings.TitleCaseSftClr: rsaSettings.TitleCaseClr;
                createHighlight(node, color, true);
                // autoFixButton();
            }
        }
    }
    
}

// Function written by kpouer to accommodate French conventions of shields being based on alt names
function isSegmentCandidate(segAtt, state, country) {
    let street = W.model.streets.getObjectById(segAtt.primaryStreetID);
    let candidate = isStreetCandidate(street, state, country);
    if (candidate.isCandidate) {
        return candidate;
    }

    if (CheckAltName.includes(country)) {
        for (let i = 0; i < segAtt.streetIDs.length; i++) {
            street = W.model.streets.getObjectById(segAtt.streetIDs[i]);
            candidate = isStreetCandidate(street, state, country);
            if (candidate.isCandidate) {
                return candidate;
            }
        }
    }
    return candidate;
}

function isStreetCandidate(street, state, country) {
    const info = {
        isCandidate: false,
        iconID: null
    }

    if (!RoadAbbr[country]) {
        return info;
    }

    //Check to see if the country has states configured in RSA by looking for a key with nothing in it
    const noStates = '' in RoadAbbr[country];
    const name = street.name;
    const abbrvs = noStates ? RoadAbbr[country][''] : RoadAbbr[country][state];

    for (let i=0; i < Object.keys(abbrvs).length; i++) {
        if (name) {
            if (noStates) {
                const abrKey = Object.keys(abbrvs)[i];
                const abbr = new RegExp(abrKey, 'g');
                const isMatch = name.match(abbr);

                if (isMatch && name === isMatch[0]) {
                    info.isCandidate = true;
                    info.iconID = abbrvs[abrKey];
                }
            } else {
                const abbr = Object.keys(abbrvs)[i];
                const isMatch = name.includes(abbr);

                if (isMatch) {
                    // console.log(abbrvs[abbr]);
                    info.isCandidate = true;
                    info.iconID = abbrvs[abbr];
                }
            } 
        }
    }
    return info;
}

function isValidShield(segAtt) {
    let primaryStreet = W.model.streets.getObjectById(segAtt.primaryStreetID);
    if (primaryStreet.name === primaryStreet.signText) {
        return true;
    }
    for (var i = 0;i<segAtt.streetIDs.length;i++) {
        let street = W.model.streets.getObjectById(segAtt.streetIDs[i]);
        if (street.name === primaryStreet.signText) {
            return true;
        }
    }
    return false;
}

function matchTitleCase(street) {
    const dir = street.direction;
    let isBad = false;
    if (dir !== '' && dir !== null) {
        // console.log(dir);
        if (dir.match(/\b(north|south|east|west)\b/i) != null) isBad = true;
        if (dir.match(/([ᴀʙᴄᴅᴇꜰɢʜɪᴊᴋʟᴍɴᴏᴘʀꜱᴛᴜᴠᴡʏᴢ][a-z]|[a-z][ᴀʙᴄᴅᴇꜰɢʜɪᴊᴋʟᴍɴᴏᴘʀꜱᴛᴜᴠᴡʏᴢ])/)  != null) isBad = true;

        if (isBad === true) {
            if (BadNames.length === 0) {
                BadNames.push(street);
            } else {
                let isDuplicate = false;
                for (let i=0; i < BadNames.length; i++) {
                    // if (BadNames[i].type) console.log(BadNames[i].id === street.id);
                    if (BadNames[i].type && BadNames[i].id === street.id) isDuplicate = true;
                }
                if (!isDuplicate) BadNames.push(street);
            }
        }
    }
    return isBad;
}

function matchTitleCaseThroughNode(turn) {
    const turnData = turn.getTurnData();
    const turnGuid = turnData.getTurnGuidance();
    const shields = turnGuid.getRoadShields();
    const twd = turnGuid.getTowards();
    const tts = turnGuid.getTTS();
    const VI = turnGuid.getVisualInstruction();
    let info = {
        isBad: false,
        softIssue: false
    };

    function checkText(txt, isSoft = false) {
        if (txt !== '' && txt !== null) {
            if (txt.match(/\b(north|south|east|west)\b/i) != null) { info.isBad = true; if (isSoft) info.softIssue = true; }
            if (txt.match(/\b(TO|VIA|JCT)\b/i) != null) { info.isBad = true; if (isSoft) info.softIssue = true; }
            if (txt.match(/([ᴀʙᴄᴅᴇꜰɢʜɪᴊᴋʟᴍɴᴏᴘʀꜱᴛᴜᴠᴡʏᴢ][a-z]|[a-z][ᴀʙᴄᴅᴇꜰɢʜɪᴊᴋʟᴍɴᴏᴘʀꜱᴛᴜᴠᴡʏᴢ])/) != null) { info.isBad = true; if (isSoft) info.softIssue = true; }
        }
    }

    function checkTTStext(txt, isSoft = false) {
        if (txt !== '' && txt !== null) {
            if (txt.match(/(Nᴏʀᴛʜ|Sᴏᴜᴛʜ|Eᴀꜱᴛ|Wᴇꜱᴛ)/) != null) { info.isBad = true; if (isSoft) info.softIssue = true; }
            if (txt.match(/(ᴛᴏ|ᴠɪᴀ|ᴊᴄᴛ)/) != null) { info.isBad = true; if (isSoft) info.softIssue = true; }
            if (txt.match(/([ᴀʙᴄᴅᴇꜰɢʜɪᴊᴋʟᴍɴᴏᴘʀꜱᴛᴜᴠᴡʏᴢ][a-z]|[a-z][ᴀʙᴄᴅᴇꜰɢʜɪᴊᴋʟᴍɴᴏᴘʀꜱᴛᴜᴠᴡʏᴢ])/) != null) { info.isBad = true; if (isSoft) info.softIssue = true; }
        }
    }

    if (shields) {
        _.each(shields, (s) => {
            checkText(s.direction);
        });
    }
    if (twd && twd !== "" && rsaSettings.checkTWD) checkText(twd, true);
    if (tts && tts !== "" && rsaSettings.checkTTS) checkTTStext(tts, true);
    if (VI && VI !== "" && rsaSettings.checkVI) checkText(VI, true);

    if (info.isBad === true) BadNames.push(turn);

    return info;
}

function displayNodeIcons(node, turnDat) {
    const geo = node.geometry.clone();
    const trnGuid = turnDat.getTurnGuidance();
    const GUIDANCE = {
        shields: {
            exists: false,
            color: '',
            width: 30,
            height: 30,
            sign: '6',
            txt: 'TG'
        },
        exitsign: {
            exists: false,
            color: '',
            width: 30,
            height: 20,
            sign: '2159',
            txt: 'EX'
        },
        tts: {
            exists: false,
            color: '',
            width: 30,
            height: 30,
            sign: '7',
            txt: 'TIO'
        },
        towards: {
            exists: false,
            color: '',
            width: 30,
            height: 30,
            sign: '7',
            txt: 'TW'
        },
        visualIn: {
            exists: false,
            color: '',
            width: 30,
            height: 30,
            sign: '7',
            txt: 'VI'
        }
    };
    let count = 0;

    GUIDANCE.shields.exists = trnGuid.getRoadShields() !== null;
    if (rsaSettings.ShowExitShields) { GUIDANCE.exitsign.exists = (trnGuid.getExitSigns() !== null && trnGuid.getExitSigns().length > 0); }
    if (rsaSettings.ShowTurnTTS) { GUIDANCE.tts.exists = (trnGuid.getTTS() !== null && trnGuid.getTTS().length > 0); }
    if (rsaSettings.ShowTowards) { GUIDANCE.towards.exists = (trnGuid.getTowards() !== null && trnGuid.getTowards().length > 0); }
    if (rsaSettings.ShowVisualInst) { GUIDANCE.visualIn.exists = (trnGuid.getVisualInstruction() !== null && trnGuid.getVisualInstruction().length > 0); }

    const styleNode = {
        strokeColor: rsaSettings.HighNodeClr,
        strokeOpacity: 0.75,
        strokeWidth: 4,
        fillColor: rsaSettings.HighNodeClr,
        fillOpacity: 0.75,
        pointRadius: 3
    };

    let startPoint = {
        x: geo.getVertices()[0].x,
        y: geo.getVertices()[0].y
    }
    let lblStart = {
        x: startPoint.x + LabelDistance().label,
        y: startPoint.y + LabelDistance().label
    }

    // Array of points for line connecting node to icons
    let points = [];
    // Point coords
    let pointNode = new OpenLayers.Geometry.Point(startPoint.x, startPoint.y);
    points.push(pointNode);
    // Label coords
    var pointLabel = new OpenLayers.Geometry.Point(lblStart.x, lblStart.y);
    points.push(pointLabel);


    // Point on node
    let pointFeature = new OpenLayers.Feature.Vector(pointNode, null, styleNode);
    rsaIconLayer.addFeatures([pointFeature]);
    // Line between node and label
    var newline = new OpenLayers.Geometry.LineString(points);
    var lineFeature = new OpenLayers.Feature.Vector(newline, null, styleNode);
    rsaIconLayer.addFeatures([lineFeature]);


    _.each(GUIDANCE, (q) => {
        if (q.exists) {
            // console.log(q);
            const styleLabel = {
                externalGraphic: `https://renderer-am.waze.com/renderer/v1/signs/${q.sign}?text=${q.txt}`,
                graphicHeight: q.height,
                graphicWidth: q.width,
                fontSize: 12,
                graphicZIndex: 700
            };
            let xpoint;
            let ypoint;

            switch(count) {
                case 0:
                    xpoint = lblStart.x;
                    ypoint = lblStart.y;
                    break;
                case 1:
                    xpoint = lblStart.x + LabelDistance().icon;
                    ypoint = lblStart.y;
                    break;
                case 2:
                    xpoint = lblStart.x;
                    ypoint = lblStart.y - LabelDistance().icon;
                    break;
                case 3: 
                    xpoint = lblStart.x + LabelDistance().icon;
                    ypoint = lblStart.y - LabelDistance().icon;
                    break;
                case 4:
                    xpoint = lblStart.x + (LabelDistance().icon * 2);
                    ypoint = lblStart.y;
                default:
                    break;
            }

            // Label coords
            let pointLabel = new OpenLayers.Geometry.Point(xpoint, ypoint);
            // Label
            let labelFeat = new OpenLayers.Feature.Vector(pointLabel, null, styleLabel);
            rsaIconLayer.addFeatures([labelFeat]);

            count++;
        }
    });
}

function displaySegShields(segment, shieldID, shieldText, shieldDir) {
    if (W.map.getZoom() < 14) return;

    const iconURL = `https://renderer-am.waze.com/renderer/v1/signs/${shieldID}?text=${shieldText}`;
    let SegmentPoints = [];
    let oldparam = {};
    let labelDis = LabelDistance();
    let width = 37;
    let height = 37;

    if (shieldText.length > 4 && shieldText.length < 7) {
        width = 50;
        height = 40;
    } else if (shieldText.length > 6 && shieldText.length < 9) {
        width = 80;
        height = 45;
    }
    else if (shieldText.length > 8 && shieldText.length < 13) {
        width = 100;
        height = 50;
    }
    oldparam.x = null;
    oldparam.y = null;
    let AtLeastOne = false;
    $.each(segment.geometry.getVertices(), function(idx, param) {
        // Build a new segment with same geometry
        SegmentPoints.push(new OpenLayers.Geometry.Point(param.x, param.y));

        // Shield icon style
        const style = {
            externalGraphic: iconURL,
            graphicWidth: width,
            graphicHeight: height,
            graphicYOffset: -20,
            graphicZIndex: 650
        };
        // Direction label styel
        const style2 = {
            label: shieldDir !== null ? shieldDir : '',
            fontColor: 'green',
            labelOutlineColor: 'white',
            labelOutlineWidth: 1,
            fontSize: 12
        };

        if (oldparam.x !== null && oldparam.y !== null) {
            if ( Math.abs(oldparam.x - param.x) > labelDis.space || Math.abs(oldparam.y - param.y) > labelDis.space  || AtLeastOne === false) {
                let centerparam = {};
                centerparam.x = ((oldparam.x + param.x) / 2);
                centerparam.y = ((oldparam.y + param.y) / 2);
                if ( Math.abs(centerparam.x - param.x) > labelDis.space || Math.abs(centerparam.y - param.y) > labelDis.space || AtLeastOne === false) {
                    LabelPoint = new OpenLayers.Geometry.Point(centerparam.x, centerparam.y);
                    const pointFeature = new OpenLayers.Feature.Vector(LabelPoint, null, style);
                    // Create point for direction label below shield icon
                    const labelPoint2 = new OpenLayers.Geometry.Point(centerparam.x, centerparam.y - labelDis.label);
                    const imageFeature2 = new OpenLayers.Feature.Vector(labelPoint2, null, style2);
                    rsaIconLayer.addFeatures([pointFeature, imageFeature2]);
                    AtLeastOne = true;
                }
            }
        }
        oldparam.x = param.x;
        oldparam.y = param.y;
    });
}

function createHighlight(obj, color, overSized = false) {
    const geo = obj.geometry.clone();
    let isNode = obj.type == 'node';

    if (isNode) {
        const styleNode = {
            strokeColor: color,
            strokeOpacity: overSized == true ? 1 : 0.75,
            strokeWidth: 4,
            fillColor: color,
            fillOpacity: 0.75,
            pointRadius: overSized == true ? 7 : 3
        }

        // Point coords
        let pointNode = new OpenLayers.Geometry.Point(geo.x, geo.y);

        // Point on node
        var pointFeature = new OpenLayers.Feature.Vector(pointNode, null, styleNode);
        rsaIconLayer.addFeatures([pointFeature]);
    } else {
        // console.log('seg highlight')
        const style = {
            strokeColor: color,
            strokeOpacity: overSized == true ? 1 : 0.75,
            strokeWidth: overSized == true ? 7 : 4,
            fillColor: color,
            fillOpacity: 0.75
        }
        const newFeat =  new OpenLayers.Geometry.LineString(geo.components, {});
        const newVector = new OpenLayers.Feature.Vector(newFeat, null, style);
        rsaMapLayer.addFeatures([newVector]);
    }
}

function removeHighlights() {
    rsaMapLayer.removeAllFeatures();
    rsaIconLayer.removeAllFeatures();
}

function LabelDistance() {
    // Return object with two variables - label is the distance used to place the direction below the icon,
    // space is the space between geo points needed to render another icon
    let label_distance = {};
    switch (W.map.getOLMap().getZoom()) {
        case zm10:
            label_distance.label = 2;
            label_distance.space = 20;
            label_distance.icon = 1.1;
            break;
        case zm9:
            label_distance.label = 2;
            label_distance.space = 20;
            label_distance.icon = 2.2;
            break;
        case zm8:
            label_distance.label = 4;
            label_distance.space = 20;
            label_distance.icon = 4.5;
            break;
        case zm7:
            label_distance.label = 7;
            label_distance.space = 20;
            label_distance.icon = 8.3;
            break;
        case zm6:
            label_distance.label = 12;
            label_distance.space = 30;
            label_distance.icon = 17;
            break;
        case zm5:
            label_distance.label = 30;
            label_distance.space = 30;
            label_distance.icon = 34;
            break;
        case zm4:
            label_distance.label = 40;
            label_distance.space = 40;
            label_distance.icon = 68;
            break;
        case zm3:
            label_distance.label = 70;
            label_distance.space = 70;
            label_distance.icon = 140;
            break;
        case zm2:
            label_distance.label = 150;
            label_distance.space = 200;
            label_distance.icon = null;
            break;
        case zm1:
            label_distance.label = 200;
            label_distance.space = 250;
            label_distance.icon = null;
            break;
    }
    return label_distance;
}

rsaBootstrap();