WME FC Layer

Adds a Functional Class layer for states that publish ArcGIS FC data.

当前为 2025-06-23 提交的版本,查看 最新版本

您需要先安装一个扩展,例如 篡改猴Greasemonkey暴力猴,之后才能安装此脚本。

You will need to install an extension such as Tampermonkey to install this script.

您需要先安装一个扩展,例如 篡改猴暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴Userscripts ,之后才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。

您需要先安装用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         WME FC Layer
// @namespace    https://greasyfork.org/users/45389
// @version      2025.06.23.000
// @description  Adds a Functional Class layer for states that publish ArcGIS FC data.
// @author       MapOMatic
// @match        *://*.waze.com/*editor*
// @exclude      *://*.waze.com/user/editor*
// @exclude      *://*.waze.com/editor/sdk/*
// @license      GNU GPLv3
// @contributionURL https://github.com/WazeDev/Thank-The-Authors
// @require      https://greasyfork.org/scripts/39002-bluebird/code/Bluebird.js?version=255146
// @require      https://greasyfork.org/scripts/24851-wazewrap/code/WazeWrap.js
// @require      https://cdn.jsdelivr.net/npm/@turf/turf@7/turf.min.js
// @require      https://update.greasyfork.org/scripts/509664/WME%20Utils%20-%20Bootstrap.js
// @connect      greasyfork.org
// @grant        GM_xmlhttpRequest
// @connect      arcgis.com
// @connect      gis.ardot.gov
// @connect      azdot.gov
// @connect      ca.gov
// @connect      coloradodot.info
// @connect      delaware.gov
// @connect      dc.gov
// @connect      ga.gov
// @connect      uga.edu
// @connect      hawaii.gov
// @connect      idaho.gov
// @connect      in.gov
// @connect      iowadot.gov
// @connect      illinois.gov
// @connect      ksdot.org
// @connect      ky.gov
// @connect      la.gov
// @connect      maine.gov
// @connect      md.gov
// @connect      ma.us
// @connect      mn.us
// @connect      nv.gov
// @connect      memphistn.gov
// @connect      state.mi.us
// @connect      modot.org
// @connect      mt.gov
// @connect      unh.edu
// @connect      nh.gov
// @connect      ny.gov
// @connect      ncdot.gov
// @connect      nd.gov
// @connect      oh.us
// @connect      or.us
// @connect      penndot.gov
// @connect      sd.gov
// @connect      shelbycountytn.gov
// @connect      utah.gov
// @connect      vermont.gov
// @connect      wa.gov
// @connect      wv.gov
// @connect      wyoroad.info
// ==/UserScript==

/* global turf */
/* global bootstrap */

(async function main() {
    'use strict';

    const settingsStoreName = 'wme_fc_layer';
    const debug = false;
    const scriptVersion = GM_info.script.version;
    const downloadUrl = 'https://greasyfork.org/scripts/369633-wme-fc-layer/code/WME%20FC%20Layer.user.js';
    const sdk = await bootstrap({ scriptUpdateMonitor: { downloadUrl } });
    const layerName = 'FC Layer';
    let isAM = false;
    let userNameLC;
    let settings = {};
    let rank;
    let MAP_LAYER_Z_INDEX;
    const MIN_ZOOM_LEVEL = 11;
    const STATES_HASH = {
        Alabama: 'AL',
        Alaska: 'AK',
        'American Samoa': 'AS',
        Arizona: 'AZ',
        Arkansas: 'AR',
        California: 'CA',
        Colorado: 'CO',
        Connecticut: 'CT',
        Delaware: 'DE',
        'District of Columbia': 'DC',
        'Federated States Of Micronesia': 'FM',
        Florida: 'FL',
        Georgia: 'GA',
        Guam: 'GU',
        Hawaii: 'HI',
        Idaho: 'ID',
        Illinois: 'IL',
        Indiana: 'IN',
        Iowa: 'IA',
        Kansas: 'KS',
        Kentucky: 'KY',
        Louisiana: 'LA',
        Maine: 'ME',
        'Marshall Islands': 'MH',
        Maryland: 'MD',
        Massachusetts: 'MA',
        Michigan: 'MI',
        Minnesota: 'MN',
        Mississippi: 'MS',
        Missouri: 'MO',
        Montana: 'MT',
        Nebraska: 'NE',
        Nevada: 'NV',
        'New Hampshire': 'NH',
        'New Jersey': 'NJ',
        'New Mexico': 'NM',
        'New York': 'NY',
        'North Carolina': 'NC',
        'North Dakota': 'ND',
        'Northern Mariana Islands': 'MP',
        Ohio: 'OH',
        Oklahoma: 'OK',
        Oregon: 'OR',
        Palau: 'PW',
        Pennsylvania: 'PA',
        'Puerto Rico': 'PR',
        'Rhode Island': 'RI',
        'South Carolina': 'SC',
        'South Dakota': 'SD',
        Tennessee: 'TN',
        Texas: 'TX',
        Utah: 'UT',
        Vermont: 'VT',
        'Virgin Islands': 'VI',
        Virginia: 'VA',
        Washington: 'WA',
        'West Virginia': 'WV',
        Wisconsin: 'WI',
        Wyoming: 'WY'
    };

    function reverseStatesHash(stateAbbr) {
    // eslint-disable-next-line no-restricted-syntax
        for (const stateName in STATES_HASH) {
            if (STATES_HASH[stateName] === stateAbbr) return stateName;
        }
        throw new Error(`FC Layer: reverseStatesHash function did not return a value for ${stateAbbr}.`);
    }

    const STATE_SETTINGS = {
        global: {
            roadTypes: ['St', 'PS', 'PS2', 'mH', 'MH', 'Ew', 'Rmp', 'Fw'], // Ew = Expressway.  For FC's that make it uncertain if they should be MH or FW.
            getFeatureRoadType(feature, layer) {
                const fc = feature.attributes[layer.fcPropName];
                return this.getRoadTypeFromFC(fc, layer);
            },
            getRoadTypeFromFC(fc, layer) {
                return Object.keys(layer.roadTypeMap).find(rt => layer.roadTypeMap[rt].indexOf(fc) !== -1);
            },
            isPermitted(stateAbbr) {
                const state = STATE_SETTINGS[stateAbbr];
                if (state.isPermitted) return state.isPermitted();
                return (rank >= 3 && isAM) || rank >= 4;
            },
            getMapLayer(stateAbbr, layerID) {
                let returnValue;
                STATE_SETTINGS[stateAbbr].fcMapLayers.forEach(layer => {
                    if (layer.layerID === layerID) {
                        returnValue = layer;
                    }
                });
                return returnValue;
            }
        },
        AL: {
            baseUrl: 'https://services.arcgis.com/LZzQi3xDiclG6XvQ/arcgis/rest/services/HPMS_Year2017_F_System_Data/FeatureServer/',
            defaultColors: {
                Fw: '#ff00c5',
                Ew: '#4f33df',
                MH: '#149ece',
                mH: '#4ce600',
                PS: '#cfae0e',
                St: '#eeeeee'
            },
            zoomSettings: { maxOffset: [30, 15, 8, 4, 2, 1, 1, 1, 1, 1], excludeRoadTypes: [['St'], ['St'], ['St'], ['St'], [], [], [], [], [], [], []] },
            fcMapLayers: [
                {
                    layerID: 0,
                    fcPropName: 'F_SYSTEM_V',
                    idPropName: 'OBJECTID',
                    outFields: ['FID', 'F_SYSTEM_V', 'State_Sys'],
                    roadTypeMap: {
                        Fw: [1],
                        Ew: [2],
                        MH: [3],
                        mH: [4],
                        PS: [5, 6],
                        St: [7]
                    },
                    maxRecordCount: 1000,
                    supportsPagination: false
                }
            ],
            isPermitted() {
                return rank >= 3;
            },
            information: { Source: 'ALDOT', Permission: 'Visible to R3+', Description: 'Federal and State highways set to a minimum of mH.' },
            getWhereClause(context) {
                if (context.mapContext.zoom < 16) {
                    return `${context.layer.fcPropName} <> 7`;
                }
                return null;
            },
            getFeatureRoadType(feature, layer) {
                let fc = parseInt(feature.attributes[layer.fcPropName], 10);
                if (fc > 4 && feature.attributes.State_Sys === 'YES') {
                    fc = 4;
                }
                return STATE_SETTINGS.global.getRoadTypeFromFC(fc, layer);
            }
        },
        AK: {
            baseUrl: 'https://services.arcgis.com/r4A0V7UzH9fcLVvv/ArcGIS/rest/services/AKDOTPF_Route_Data/FeatureServer/',
            defaultColors: {
                Ew: '#4f33df',
                MH: '#149ece',
                mH: '#4ce600',
                PS: '#cfae0e',
                St: '#eeeeee'
            },
            zoomSettings: { maxOffset: [30, 15, 8, 4, 2, 1, 1, 1, 1, 1], excludeRoadTypes: [[], [], [], [], [], [], [], [], [], [], []] },
            fcMapLayers: [
                {
                    layerID: 13,
                    fcPropName: 'Functional_Class',
                    idPropName: 'OBJECTID',
                    outFields: ['OBJECTID', 'Functional_Class'],
                    roadTypeMap: {
                        Ew: [1, 2],
                        MH: [3],
                        mH: [4],
                        PS: [5, 6],
                        St: [7]
                    },
                    maxRecordCount: 1000,
                    supportsPagination: false
                }
            ],
            information: { Source: 'Alaska DOT&PF', Permission: 'Visible to R4+ or R3-AM', Description: 'Raw unmodified FC data.' },
            getWhereClause(context) {
                if (context.mapContext.zoom < 16) {
                    return `${context.layer.fcPropName} <> 7`;
                }
                return null;
            },
            getFeatureRoadType(feature, layer) {
                if (layer.getFeatureRoadType) {
                    return layer.getFeatureRoadType(feature);
                }
                return STATE_SETTINGS.global.getFeatureRoadType(feature, layer);
            }
        },
        AZ: {
            baseUrl: 'https://services1.arcgis.com/XAiBIVuto7zeZj1B/arcgis/rest/services/ATIS_prod_gdb_1/FeatureServer/',
            defaultColors: {
                Fw: '#ff00c5',
                Ew: '#ff00c5',
                MH: '#149ece',
                mH: '#4ce600',
                PS: '#cfae0e',
                St: '#eeeeee'
            },
            zoomSettings: { maxOffset: [30, 15, 8, 4, 2, 1, 1, 1, 1, 1] },
            fcMapLayers: [
                {
                    layerID: 38,
                    fcPropName: 'FunctionalClass',
                    idPropName: 'OBJECTID',
                    outFields: ['OBJECTID', 'FunctionalClass', 'RouteId'],
                    roadTypeMap: {
                        Fw: [1],
                        Ew: [2],
                        MH: [3],
                        mH: [4],
                        PS: [5, 6],
                        St: [7]
                    },
                    maxRecordCount: 1000,
                    supportsPagination: false
                }
            ],
            information: { Source: 'ADOT', Permission: 'Visible to R4+ or R3-AM' },
            getWhereClause() {
                return null;
            },
            getFeatureRoadType(feature, layer) {
                const attr = feature.attributes;
                const roadID = attr.RouteId.trim().replace(/  +/g, ' ');
                const roadNum = parseInt(roadID.substring(2, 5), 10);
                let fc = attr[layer.fcPropName];
                switch (fc) {
                    case 'Rural Principal Arterial - Interstate':
                    case 'Urban Principal Arterial - Interstate':
                        fc = 1;
                        break;
                    case 'Rural Principal Arterial - Other Fwys & Expwys':
                    case 'Urban Principal Arterial - Other Fwys & Expwys':
                        fc = 2;
                        break;
                    case 'Rural Principal Arterial - Other':
                    case 'Urban Principal Arterial - Other':
                        fc = 3;
                        break;
                    case 'Rural Minor Arterial':
                    case 'Urban Minor Arterial':
                        fc = 4;
                        break;
                    case 'Rural Major Collector':
                    case 'Urban Major Collector':
                        fc = 5;
                        break;
                    case 'Rural Minor Collector':
                    case 'Urban Minor Collector':
                        fc = 6;
                        break;
                    default:
                        fc = 7;
                }
                const azIH = [8, 10, 11, 17, 19, 40]; // Interstate hwys in AZ
                const isUS = /^U\D\d{3}\b/.test(roadID);
                const isState = /^S\D\d{3}\b/.test(roadID);
                const isBiz = /^SB\d{3}\b/.test(roadID);
                if (fc > 4 && isState && azIH.includes(roadNum) && isBiz) fc = 4;
                else if (fc > 4 && isUS) fc = isBiz ? 6 : 4;
                else if (fc > 6 && isState) fc = isBiz ? 7 : 6;
                return STATE_SETTINGS.global.getRoadTypeFromFC(fc, layer);
            }
        },
        AR: {
            baseUrl: 'https://gis.ardot.gov/hosting/rest/services/SIR_TIS/RoadInvDissolves/FeatureServer/',
            defaultColors: {
                Fw: '#ff00c5',
                Ew: '#4f33df',
                MH: '#149ece',
                mH: '#4ce600',
                PS: '#cfae0e',
                St: '#eeeeee'
            },
            zoomSettings: { maxOffset: [30, 15, 8, 4, 2, 1, 1, 1, 1, 1], excludeRoadTypes: [[], [], [], [], [], [], [], [], [], [], []] },
            fcMapLayers: [
                {
                    layerID: 0,
                    fcPropName: 'FunctionalClass',
                    idPropName: 'OBJECTID',
                    outFields: ['OBJECTID', 'FunctionalClass', 'AH_Route', 'AH_Section'],
                    roadTypeMap: {
                        Fw: [1, 2],
                        Ew: [],
                        MH: [3],
                        mH: [4],
                        PS: [5, 6],
                        St: [7]
                    },
                    maxRecordCount: 1000,
                    supportsPagination: false
                }
            ],
            information: { Source: 'ARDOT', Permission: 'Visible to R4+ or R3-AM' },
            getWhereClause() {
                return null;
            },
            getFeatureRoadType(feature, layer) {
                const attr = feature.attributes;
                let fc = parseInt(attr[layer.fcPropName], 10);
                const roadID = parseInt(attr.AH_Route, 10);
                const usHwys = [49, 59, 61, 62, 63, 64, 65, 67, 70, 71, 79, 82, 165, 167, 270, 271, 278, 371, 412, 425];
                const isUS = usHwys.includes(roadID);
                const isState = roadID < 613;
                const isBiz = attr.AH_Section[attr.AH_Section.length - 1] === 'B';
                if (fc > 3 && isUS) fc = isBiz ? 4 : 3;
                else if (fc > 4 && isState) fc = isBiz ? 5 : 4;
                return STATE_SETTINGS.global.getRoadTypeFromFC(fc, layer);
            }
        },
        CA: {
            baseUrl: 'https://caltrans-gis.dot.ca.gov/arcgis/rest/services/CHhighway/CRS_Functional_Classification/FeatureServer/',
            defaultColors: {
                Fw: '#ff00c5',
                Ew: '#4f33df',
                MH: '#149ece',
                mH: '#4ce600',
                PS: '#cfae0e',
                St: '#eeeeee'
            },
            zoomSettings: { maxOffset: [30, 15, 8, 4, 2, 1, 1, 1, 1, 1], excludeRoadTypes: [['St'], ['St'], ['St'], ['St'], [], [], [], [], [], [], []] },
            fcMapLayers: [
                {
                    layerID: 0,
                    fcPropName: 'F_System',
                    idPropName: 'OBJECTID',
                    outFields: ['OBJECTID', 'F_System'],
                    roadTypeMap: {
                        Fw: [1],
                        Ew: [2],
                        MH: [3],
                        mH: [4],
                        PS: [5, 6],
                        St: [7]
                    },
                    maxRecordCount: 1000,
                    supportsPagination: false
                }
            ],
            isPermitted() {
                return ['mapomatic', 'turbomkt', 'tonestertm', 'ottonomy', 'jemay', 'ojlaw', 'js55ct'].includes(userNameLC);
            },
            information: { Source: 'Caltrans', Permission: 'Visible to ?', Description: '' },
            getWhereClause(context) {
                if (context.mapContext.zoom < 16) {
                    return `${context.layer.fcPropName} <> 7`;
                }
                return null;
            },
            getFeatureRoadType(feature, layer) {
                const fc = parseInt(feature.attributes[layer.fcPropName], 10);
                return STATE_SETTINGS.global.getRoadTypeFromFC(fc, layer);
            }
        },
        CO: {
            baseUrl: 'https://dtdapps.coloradodot.info/arcgis/rest/services/CPLAN/open_data_sde/FeatureServer/',
            defaultColors: {
                Fw: '#ff00c5',
                Ew: '#4f33df',
                MH: '#149ece',
                mH: '#4ce600',
                PS: '#cfae0e',
                St: '#eeeeee'
            },
            zoomSettings: { maxOffset: [30, 15, 8, 4, 2, 1, 1, 1, 1, 1], excludeRoadTypes: [[], [], [], [], [], [], [], [], [], [], []] },
            fcMapLayers: [
                {
                    layerID: 11,
                    fcPropName: 'FUNCCLASS',
                    idPropName: 'OBJECTID',
                    outFields: ['OBJECTID', 'FUNCCLASS', 'ROUTE', 'REFPT'],
                    roadTypeMap: {
                        Fw: [1],
                        Ew: [2],
                        MH: [3],
                        mH: [4],
                        PS: [5, 6],
                        St: [7]
                    },
                    maxRecordCount: 1000,
                    supportsPagination: false
                },
                {
                    layerID: 14,
                    fcPropName: 'FUNCCLASSID',
                    idPropName: 'OBJECTID',
                    outFields: ['OBJECTID', 'FUNCCLASSID', 'ROUTE', 'FIPSCOUNTY'],
                    roadTypeMap: {
                        Fw: [1],
                        Ew: [2],
                        MH: [3],
                        mH: [4],
                        PS: [5, 6],
                        St: [7]
                    },
                    maxRecordCount: 1000,
                    supportsPagination: false
                },
                {
                    layerID: 17,
                    fcPropName: 'FUNCCLASSID',
                    idPropName: 'OBJECTID',
                    outFields: ['OBJECTID', 'FUNCCLASSID', 'ROUTE', 'FIPSCOUNTY'],
                    roadTypeMap: {
                        Fw: [1],
                        Ew: [2],
                        MH: [3],
                        mH: [4],
                        PS: [5, 6],
                        St: [7]
                    },
                    maxRecordCount: 1000,
                    supportsPagination: false
                }
            ],
            isPermitted() {
                return rank >= 3;
            },
            information: {
                Source: 'CDOT',
                Permission: 'Visible to R3+',
                Description: 'Please consult with a state manager before making any changes to road types based on the data presented.'
            },
            getWhereClause(context) {
                if (context.mapContext.zoom < 16) {
                    return `${context.layer.fcPropName} <> '7'`;
                }
                return null;
            },
            getFeatureRoadType(feature, layer) {
                const attr = feature.attributes;
                let fc = parseInt(attr[layer.fcPropName], 10);
                const route = attr.ROUTE.replace(/  +/g, ' ');
                if (layer.layerID === 7) {
                    const rtnum = parseInt(route.slice(0, 3), 10);
                    const refpt = attr.REFPT;
                    const hwys = [6, 24, 25, 34, 36, 40, 50, 70, 84, 85, 87, 138, 160, 285, 287, 350, 385, 400, 491, 550];
                    // Exceptions first, then normal classification
                    const doNothing = ['024D', '040G'];
                    const notNothing = ['070K', '070L', '070O', '070Q', '070R'];
                    const doMin = ['024E', '050D', '070O', '085F', '160D'];
                    if (doNothing.includes(route) || (rtnum === 70 && route !== '070K' && !notNothing.includes(route))) {
                        // do nothing
                    } else if (doMin.includes(route) || (rtnum === 40 && refpt > 320 && refpt < 385) || (rtnum === 36 && refpt > 79 && refpt < 100.99) || (route === '034D' && refpt > 11)) {
                        fc = 4;
                    } else if (hwys.includes(rtnum)) {
                        fc = Math.min(fc, 3);
                    } else {
                        fc = Math.min(fc, 4);
                    }
                } else {
                    // All exceptions
                    const fips = parseInt(attr.FIPSCOUNTY, 10);
                    if ((fips === 19 && route === 'COLORADO BD') || (fips === 37 && (route === 'GRAND AV' || route === 'S H6'))) {
                        fc = 3;
                    } else if (fips === 67 && route === 'BAYFIELDPAY') {
                        fc = 4;
                    }
                }
                return STATE_SETTINGS.global.getRoadTypeFromFC(fc, layer);
            }
        },
        CT: {
            baseUrl: 'https://services1.arcgis.com/FCaUeJ5SOVtImake/ArcGIS/rest/services/',
            defaultColors: {
                Fw: '#ff00c5',
                Ew: '#4f33df',
                MH: '#149ece',
                mH: '#4ce600',
                PS: '#cfae0e',
                St: '#eeeeee'
            },
            zoomSettings: { maxOffset: [30, 15, 8, 4, 2, 1, 1, 1, 1, 1], excludeRoadTypes: [['St'], ['St'], ['St'], ['St'], [], [], [], [], [], [], []] },
            fcMapLayers: [
                {
                    layerID: 3,
                    layerPath: 'CTDOT_Roadway_Classification_and_Characteristic_Data/FeatureServer/',
                    fcPropName: 'FC_FC_CODE',
                    idPropName: 'OBJECTID',
                    outFields: ['OBJECTID', 'FC_FC_CODE'],
                    roadTypeMap: {
                        Fw: [1],
                        Ew: [2],
                        MH: [3],
                        mH: [4],
                        PS: [5, 6],
                        St: [7]
                    },
                    maxRecordCount: 1000,
                    supportsPagination: false
                },
                {
                    layerID: 0,
                    layerPath: 'CTDOT_State_Routes_and_Local_Roads/FeatureServer/',
                    fcPropName: 'ROUTE_PREFIX',
                    idPropName: 'OBJECTID',
                    outFields: ['OBJECTID', 'ROUTE_PREFIX'],
                    roadTypeMap: {
                        Fw: [1],
                        Ew: [2],
                        MH: [3],
                        mH: [4],
                        PS: [5, 6],
                        St: [7]
                    },
                    maxRecordCount: 1000,
                    supportsPagination: false
                }
            ],
            isPermitted() {
                return rank >= 3;
            },
            information: { Source: 'CTDOT', Permission: 'Visible to R3+', Description: 'Federal and State highways set to a minimum of mH.' },
            getWhereClause(context) {
                if (context.mapContext.zoom < 16) {
                    if (context.layer.layerID === 3) {
                        return `${context.layer.fcPropName} <> 7`;
                    }
                    if (context.layer.layerID === 'CTDOT_State_Routes_and_Local_Roads/FeatureServer/0') {
                        return `${context.layer.fcPropName} IN ('I', 'CT', 'SR', 'US')`;
                    }
                    return null;
                }
                return null;
            },
            getFeatureRoadType(feature, layer) {
                let fc;
                let primaryFc;
                let secondaryFc;

                if (layer.layerID === 3) {
                    // Extract primary FC based on 'FC_FC_CODE'
                    primaryFc = parseInt(feature.attributes[layer.fcPropName], 10);
                } else if (layer.layerID === 0) {
                    // Determine secondary FC using 'ROUTE_PREFIX'
                    const prefix = feature.attributes[layer.fcPropName];

                    if (prefix === 'I') {
                        secondaryFc = 1;
                    } else if (prefix === 'US') {
                        secondaryFc = 3;
                    } else if (prefix === 'CT' || prefix === 'SR') {
                        secondaryFc = 4;
                    }
                }

                // Determine fc based on available values
                if (typeof primaryFc !== 'undefined' && typeof secondaryFc !== 'undefined') {
                    fc = Math.min(primaryFc, secondaryFc);
                } else if (typeof primaryFc !== 'undefined') {
                    fc = primaryFc;
                } else if (typeof secondaryFc !== 'undefined') {
                    fc = secondaryFc;
                } else {
                    fc = null; // Default if both are undefined, decide handling of null based on safeguards or other logic
                }

                return STATE_SETTINGS.global.getRoadTypeFromFC(fc, layer);
            }
        },
        DE: {
            baseUrl: 'https://enterprise.firstmap.delaware.gov/arcgis/rest/services/Transportation/DE_Roadways_Main/FeatureServer/',
            defaultColors: {
                Fw: '#ff00c5',
                Ew: '#4f33df',
                MH: '#149ece',
                mH: '#4ce600',
                PS: '#cfae0e',
                St: '#eeeeee'
            },
            zoomSettings: { maxOffset: [30, 15, 8, 4, 2, 1, 1, 1, 1, 1], excludeRoadTypes: [['St'], ['St'], ['St'], ['St'], [], [], [], [], [], [], []] },
            fcMapLayers: [
                {
                    layerID: 16,
                    fcPropName: 'VALUE_TEXT',
                    idPropName: 'OBJECTID',
                    outFields: ['OBJECTID', 'VALUE_TEXT'],
                    maxRecordCount: 1000,
                    supportsPagination: false,
                    roadTypeMap: {
                        Fw: ['Interstate'],
                        Ew: ['Other Expressways & Freeway'],
                        MH: ['Other Principal Arterials'],
                        mH: ['Minor Arterial'],
                        PS: ['Major Collector', 'Minor Collector'],
                        St: ['Local']
                    }
                }
            ],
            information: { Source: 'Delaware FirstMap', Permission: 'Visible to R4+ or R3-AM', Description: 'Raw unmodified FC data.' },
            getWhereClause(context) {
                if (context.mapContext.zoom < 16) {
                    return `${context.layer.fcPropName} <> 'Local'`;
                }
                return null;
            },
            getFeatureRoadType(feature, layer) {
                if (layer.getFeatureRoadType) {
                    return layer.getFeatureRoadType(feature);
                }
                return STATE_SETTINGS.global.getFeatureRoadType(feature, layer);
            }
        },
        DC: {
            baseUrl: 'https://maps2.dcgis.dc.gov/dcgis/rest/services/DCGIS_DATA/Transportation_WebMercator/MapServer/',
            supportsPagination: false,
            defaultColors: {
                Fw: '#ff00c5',
                Ew: '#149ece',
                MH: '#149ece',
                mH: '#4ce600',
                PS: '#cfae0e',
                St: '#eeeeee'
            },
            zoomSettings: { maxOffset: [30, 15, 8, 4, 2, 1, 1, 1, 1, 1], excludeRoadTypes: [[], [], [], [], [], [], [], [], [], [], []] },
            fetchAllFC: false,
            fcMapLayers: [
                {
                    layerID: 48,
                    fcPropName: 'FHWAFUNCTIONALCLASS',
                    idPropName: 'OBJECTID',
                    outFields: ['OBJECTID', 'FHWAFUNCTIONALCLASS'],
                    maxRecordCount: 1000,
                    supportsPagination: false,
                    roadTypeMap: {
                        Fw: [1],
                        Ew: [2],
                        MH: [3],
                        mH: [4],
                        PS: [5, 6],
                        St: [7]
                    }
                }
            ],
            information: { Source: 'DDOT', Permission: 'Visible to R4+ or R3-AM' },
            getWhereClause() {
                return null;
            },
            getFeatureRoadType(feature, layer) {
                if (layer.getFeatureRoadType) {
                    return layer.getFeatureRoadType(feature);
                }
                return STATE_SETTINGS.global.getFeatureRoadType(feature, layer);
            }
        },
        FL: {
            baseUrl: 'https://services1.arcgis.com/O1JpcwDW8sjYuddV/ArcGIS/rest/services/Functional_Classification_TDA/FeatureServer/',
            supportsPagination: false,
            defaultColors: {
                Fw: '#ff00c5',
                Ew: '#149ece',
                MH: '#149ece',
                mH: '#4ce600',
                PS: '#cfae0e',
                St: '#eeeeee'
            },
            zoomSettings: { maxOffset: [30, 15, 8, 4, 2, 1, 1, 1, 1, 1], excludeRoadTypes: [[], [], [], [], [], [], [], [], [], [], []] },
            fetchAllFC: false,
            fcMapLayers: [
                {
                    layerID: 0,
                    fcPropName: 'FUNCLASS',
                    idPropName: 'FID',
                    outFields: ['FID', 'FUNCLASS'],
                    maxRecordCount: 1000,
                    supportsPagination: false,
                    roadTypeMap: {
                        Fw: ['01', '11'],
                        Ew: ['02', '12'],
                        MH: ['04', '14'],
                        mH: ['06', '16'],
                        PS: ['07', '08', '17', '18']
                    }
                }
            ],
            information: { Source: 'FDOT', Permission: 'Visible to R4+ or R3-AM', Description: 'Raw unmodified FC data.' },
            getWhereClause() {
                return null;
            },
            getFeatureRoadType(feature, layer) {
                if (layer.getFeatureRoadType) {
                    return layer.getFeatureRoadType(feature);
                }
                return STATE_SETTINGS.global.getFeatureRoadType(feature, layer);
            }
        },
        GA: {
            baseUrl: 'https://maps.itos.uga.edu/arcgis/rest/services/GDOT/GDOT_FunctionalClass/mapserver/',
            supportsPagination: true,
            defaultColors: {
                Fw: '#ff00c5',
                Ew: '#149ece',
                MH: '#149ece',
                mH: '#4ce600',
                PS: '#cfae0e',
                St: '#eeeeee'
            },
            zoomSettings: { maxOffset: [30, 15, 8, 4, 2, 1, 1, 1, 1, 1], excludeRoadTypes: [[], [], [], [], [], [], [], [], [], [], []] },
            fetchAllFC: false,
            /* eslint-disable object-curly-newline */
            fcMapLayers: [
                {
                    layerID: 0,
                    fcPropName: 'FUNCTIONAL_CLASS',
                    idPropName: 'OBJECTID',
                    outFields: ['OBJECTID', 'FUNCTIONAL_CLASS', 'SYSTEM_CODE'],
                    maxRecordCount: 1000,
                    supportsPagination: true,
                    roadTypeMap: { Fw: [1], Ew: [2], MH: [3], mH: [4], PS: [5, 6] }
                },
                {
                    layerID: 1,
                    fcPropName: 'FUNCTIONAL_CLASS',
                    idPropName: 'OBJECTID',
                    outFields: ['OBJECTID', 'FUNCTIONAL_CLASS', 'SYSTEM_CODE'],
                    maxRecordCount: 1000,
                    supportsPagination: true,
                    roadTypeMap: { Fw: [1], Ew: [2], MH: [3], mH: [4], PS: [5, 6] }
                },
                {
                    layerID: 2,
                    fcPropName: 'FUNCTIONAL_CLASS',
                    idPropName: 'OBJECTID',
                    outFields: ['OBJECTID', 'FUNCTIONAL_CLASS', 'SYSTEM_CODE'],
                    maxRecordCount: 1000,
                    supportsPagination: true,
                    roadTypeMap: { Fw: [1], Ew: [2], MH: [3], mH: [4], PS: [5, 6] }
                },
                {
                    layerID: 3,
                    fcPropName: 'FUNCTIONAL_CLASS',
                    idPropName: 'OBJECTID',
                    outFields: ['OBJECTID', 'FUNCTIONAL_CLASS', 'SYSTEM_CODE'],
                    maxRecordCount: 1000,
                    supportsPagination: true,
                    roadTypeMap: { Fw: [1], Ew: [2], MH: [3], mH: [4], PS: [5, 6] }
                },
                {
                    layerID: 4,
                    fcPropName: 'FUNCTIONAL_CLASS',
                    idPropName: 'OBJECTID',
                    outFields: ['OBJECTID', 'FUNCTIONAL_CLASS', 'SYSTEM_CODE'],
                    maxRecordCount: 1000,
                    supportsPagination: true,
                    roadTypeMap: { Fw: [1], Ew: [2], MH: [3], mH: [4], PS: [5, 6] }
                },
                {
                    layerID: 5,
                    fcPropName: 'FUNCTIONAL_CLASS',
                    idPropName: 'OBJECTID',
                    outFields: ['OBJECTID', 'FUNCTIONAL_CLASS', 'SYSTEM_CODE'],
                    maxRecordCount: 1000,
                    supportsPagination: true,
                    roadTypeMap: { Fw: [1], Ew: [2], MH: [3], mH: [4], PS: [5, 6] }
                },
                {
                    layerID: 6,
                    fcPropName: 'FUNCTIONAL_CLASS',
                    idPropName: 'OBJECTID',
                    outFields: ['OBJECTID', 'FUNCTIONAL_CLASS', 'SYSTEM_CODE'],
                    maxRecordCount: 1000,
                    supportsPagination: true,
                    roadTypeMap: { Fw: [1], Ew: [2], MH: [3], mH: [4], PS: [5, 6] }
                }
            ],
            /* eslint-enable object-curly-newline */
            information: { Source: 'GDOT', Permission: 'Visible to R4+ or R3-AM', Description: 'Federal and State highways set to a minimum of mH.' },
            getWhereClause() {
                return null;
            },
            getFeatureRoadType(feature, layer) {
                if (layer.getFeatureRoadType) {
                    return layer.getFeatureRoadType(feature);
                }
                const attr = feature.attributes;
                const fc = attr.FUNCTIONAL_CLASS;
                if (attr.SYSTEM_CODE === '1' && fc > 4) {
                    return STATE_SETTINGS.global.getRoadTypeFromFC(4, layer);
                }
                return STATE_SETTINGS.global.getFeatureRoadType(feature, layer);
            }
        },
        HI: {
            baseUrl: 'https://geodata.hawaii.gov/arcgis/rest/services/Transportation/MapServer/',
            defaultColors: {
                Fw: '#ff00c5',
                Ew: '#4f33df',
                MH: '#149ece',
                mH: '#4ce600',
                PS: '#cfae0e',
                St: '#eeeeee'
            },
            zoomSettings: { maxOffset: [30, 15, 8, 4, 2, 1, 1, 1, 1, 1], excludeRoadTypes: [[], [], [], [], [], [], [], [], [], [], []] },
            fcMapLayers: [
                {
                    layerID: 12,
                    fcPropName: 'f_system',
                    idPropName: 'objectid',
                    outFields: ['objectid', 'f_system'],
                    roadTypeMap: {
                        Fw: [1],
                        Ew: [2],
                        MH: [3],
                        mH: [4],
                        PS: [5, 6],
                        St: [7]
                    },
                    maxRecordCount: 1000,
                    supportsPagination: false
                }
            ],
            information: { Source: 'HDOT', Permission: 'Visible to R4+ or R3-AM', Description: 'Raw unmodified FC data.' },
            getWhereClause(context) {
                if (context.mapContext.zoom < 16) {
                    return `${context.layer.fcPropName}<7`;
                }
                return null;
            },
            getFeatureRoadType(feature, layer) {
                if (layer.getFeatureRoadType) {
                    return layer.getFeatureRoadType(feature);
                }
                return STATE_SETTINGS.global.getFeatureRoadType(feature, layer);
            }
        },
        ID: {
            baseUrl: 'https://gisportalp.itd.idaho.gov/xserver/rest/services/RH_GeneralService/MapServer/',
            supportsPagination: false,
            defaultColors: {
                Fw: '#ff00c5',
                Ew: '#149ece',
                MH: '#149ece',
                mH: '#4ce600',
                PS: '#cfae0e',
                St: '#eeeeee'
            },
            zoomSettings: { maxOffset: [30, 15, 8, 4, 2, 1, 1, 1, 1, 1], excludeRoadTypes: [[], [], [], [], [], [], [], [], [], [], []] },
            fetchAllFC: true,
            /* eslint-disable object-curly-newline */
            fcMapLayers: [
                {
                    layerID: 67,
                    fcPropName: 'FunctionalClass',
                    idPropName: 'ObjectId',
                    outFields: ['ObjectId', 'FunctionalClass'],
                    maxRecordCount: 1000,
                    supportsPagination: false,
                    roadTypeMap: { Fw: [1], Ew: [2], MH: [3], mH: [4], PS: [5, 6] }
                }
            ],
            /* eslint-enable object-curly-newline */
            information: { Source: 'ITD', Permission: 'Visible to R4+ or R3-AM', Description: 'Raw unmodified FC data.' },
            getWhereClause() {
                return null;
            },
            getFeatureRoadType(feature, layer) {
                if (layer.getFeatureRoadType) {
                    return layer.getFeatureRoadType(feature);
                }
                return STATE_SETTINGS.global.getFeatureRoadType(feature, layer);
            }
        },
        IL: {
            baseUrl: 'https://gis1.dot.illinois.gov/arcgis/rest/services/AdministrativeData/FunctionalClass/MapServer/',
            supportsPagination: false,
            defaultColors: {
                Fw: '#ff00c5',
                Ew: '#ff00c5',
                MH: '#149ece',
                mH: '#4ce600',
                PS: '#cfae0e',
                St: '#eeeeee'
            },
            zoomSettings: { maxOffset: [30, 15, 8, 4, 2, 1, 1, 1, 1, 1] },
            fcMapLayers: [
                {
                    layerID: 0,
                    idPropName: 'OBJECTID',
                    fcPropName: 'FC',
                    outFields: ['FC'],
                    roadTypeMap: {
                        Fw: ['1'],
                        Ew: ['2'],
                        MH: ['3'],
                        mH: ['4'],
                        PS: ['5', '6'],
                        St: ['7']
                    },
                    maxRecordCount: 1000,
                    supportsPagination: false
                }
            ],
            isPermitted() {
                return rank >= 4;
            },
            information: { Source: 'IDOT', Permission: 'Visible to R4+', Description: 'Raw unmodified FC data.' },
            getWhereClause(context) {
                return context.mapContext.zoom < 16 ? 'FC<>7' : null;
            },
            getFeatureRoadType(feature, layer) {
                if (layer.getFeatureRoadType) {
                    return layer.getFeatureRoadType(feature);
                }
                return STATE_SETTINGS.global.getFeatureRoadType(feature, layer);
            }
        },
        IN: {
            baseUrl: 'https://gis.indot.in.gov/ro/rest/services/DOT/INDOT_LTAP/MapServer/',
            supportsPagination: false,
            overrideUrl: '1Sbwc7e6BfHpZWSTfU3_1otXGSxHrdDYcbn7fOf1VjpA',
            defaultColors: {
                Fw: '#ff00c5',
                Ew: '#149ece',
                MH: '#149ece',
                mH: '#4ce600',
                PS: '#cfae0e',
                St: '#eeeeee'
            },
            zoomSettings: {
                maxOffset: [30, 15, 8, 4, 2, 1, 1, 1, 1, 1],
                excludeRoadTypes: [['St'], ['St'], ['St'], ['St'], [], [], [], [], [], [], []],
                hideRoadTypes: [['St'], ['St'], ['St'], ['St'], [], [], [], [], [], [], []]
            },
            fcMapLayers: [
                {
                    layerID: 10,
                    idPropName: 'OBJECTID',
                    fcPropName: 'FUNCTIONAL_CLASS',
                    outFields: ['FUNCTIONAL_CLASS', 'OBJECTID', 'TO_DATE'],
                    roadTypeMap: {
                        Fw: [1],
                        Ew: [2],
                        MH: [3],
                        mH: [4],
                        PS: [5, 6],
                        St: [7]
                    },
                    maxRecordCount: 100000,
                    supportsPagination: false
                }
            ],
            isPermitted() {
                return true;
            },
            information: { Source: 'INDOT', Description: 'Raw unmodified FC data.' },
            getWhereClause(context) {
                let whereParts = ['TO_DATE IS NULL'];
                if (context.mapContext.zoom < 16) {
                    whereParts += ` AND ${context.layer.fcPropName} <> 7`;
                }
                return whereParts;
            },
            getFeatureRoadType(feature, layer) {
                if (layer.getFeatureRoadType) {
                    return layer.getFeatureRoadType(feature);
                }
                return STATE_SETTINGS.global.getFeatureRoadType(feature, layer);
            }
        },
        IA: {
            baseUrl: 'https://gis.iowadot.gov/agshost/rest/services/RAMS/Road_Network/FeatureServer/',
            defaultColors: {
                Fw: '#ff00c5',
                Ew: '#149ece',
                MH: '#149ece',
                mH: '#4ce600',
                PS: '#cfae0e',
                St: '#eeeeee',
                PSGr: '#cc6533',
                StGr: '#e99cb6'
            },
            zoomSettings: { maxOffset: [30, 15, 8, 4, 2, 1, 1, 1, 1, 1], excludeRoadTypes: [['St'], ['St'], ['St'], ['St'], [], [], [], [], [], [], []] },
            fcMapLayers: [
                {
                    layerID: 0,
                    fcPropName: 'FED_FUNCTIONAL_CLASS',
                    idPropName: 'OBJECTID',
                    outFields: ['OBJECTID', 'FED_FUNCTIONAL_CLASS', 'STATE_ROUTE_NAME_1', 'ACCESS_CONTROL', 'SURFACE_TYPE'],
                    roadTypeMap: {
                        Fw: [1],
                        MH: [2, 3],
                        mH: [4],
                        PS: [5, 6],
                        St: [7]
                    },
                    maxRecordCount: 1000,
                    supportsPagination: false
                }
            ],
            information: { Source: 'Iowa DOT', Permission: 'Visible to R4+ or R3-AM', Description: 'Additional colors denote unpaved PS and LS segements.' },
            getWhereClause(context) {
                let theWhereClause = 'FACILITY_TYPE<>7'; // Removed proposed roads
                if (context.mapContext.zoom < 16) {
                    theWhereClause += ` AND ${context.layer.fcPropName}<7`;
                }
                return theWhereClause;
            },
            getFeatureRoadType(feature, layer) {
                const attr = feature.attributes;
                let fc = parseInt(attr[layer.fcPropName], 10);
                const isFw = attr.ACCESS_CONTROL === 1;
                const isUS = /^STATE OF IOWA, US/.test(attr.STATE_ROUTE_NAME_1);
                const isState = /^STATE OF IOWA, IA/.test(attr.STATE_ROUTE_NAME_1);
                if (isFw) fc = 1;
                else if (fc > 3 && isUS) fc = 3;
                else if (fc > 4 && isState) fc = 4;
                if (fc > 4 && attr.SURFACE_TYPE === 20) {
                    return fc < 7 ? 'PSGr' : 'StGr';
                }
                return STATE_SETTINGS.global.getRoadTypeFromFC(fc, layer);
            }
        },
        KS: {
            baseUrl: 'http://wfs.ksdot.org/arcgis_web_adaptor/rest/services/Transportation/',
            defaultColors: {
                Fw: '#ff00c5',
                Ew: '#4f33df',
                MH: '#149ece',
                mH: '#4ce600',
                PS: '#cfae0e',
                St: '#eeeeee'
            },
            zoomSettings: { maxOffset: [30, 15, 8, 4, 2, 1, 1, 1, 1, 1], excludeRoadTypes: [['St'], ['St'], ['St'], ['St'], [], [], [], [], [], [], []] },
            fcMapLayers: [
                {
                    layerID: 3,
                    layerPath: 'Functional_Classification/MapServer/',
                    idPropName: 'Id',
                    fcPropName: 'FunctionalClassification',
                    outFields: ['FunctionalClassification', 'Id'],
                    roadTypeMap: {
                        Fw: [1],
                        MH: [2, 3],
                        mH: [4],
                        PS: [5, 6],
                        St: [7]
                    },
                    maxRecordCount: 1000,
                    supportsPagination: false
                },

                // 2024-03-20 (mapomatic) The "non-state system" layer was removed from the KS server,
                // so we're forced to use the function_classification layer (above) which doesn't include
                // any metadata for US/state road designations. I'm leaving the old layers commented below
                // in case they're of use in the future.

                // {
                //     layerID: 0,
                //     layerPath: 'Non_State_System/MapServer/',
                //     idPropName: 'ID2',
                //     fcPropName: 'FUNCLASS',
                //     outFields: ['FUNCLASS', 'ID2', 'ROUTE_ID'],
                //     roadTypeMap: {
                //         Fw: [1], MH: [2, 3], mH: [4], PS: [5, 6], St: [7]
                //     },
                //     maxRecordCount: 1000,
                //     supportsPagination: false
                // },
                {
                    layerID: 0,
                    layerPath: 'State_System/MapServer/',
                    idPropName: 'OBJECTID',
                    fcPropName: 'FUN_CLASS_CD',
                    outFields: ['FUN_CLASS_CD', 'OBJECTID', 'NHS'],
                    roadTypeMap: {
                        Fw: [1],
                        Ew: [2],
                        MH: [3],
                        mH: [4],
                        PS: [5, 6],
                        St: [7]
                    },
                    maxRecordCount: 1000,
                    supportsPagination: false
                }
            ],
            isPermitted() {
                return rank >= 3 || isAM;
            },
            information: { Source: 'KDOT', Permission: 'Visible to area managers', Description: 'Federal and State highways set to a minimum of mH.' },
            getWhereClause(context) {
                if (context.mapContext.zoom < 16) {
                    return `${context.layer.fcPropName}<>'7'`;
                }
                return null;
            },
            getFeatureRoadType(feature, layer) {
                const attr = feature.attributes;
                let fc = parseInt(attr[layer.fcPropName], 10);
                const roadNHS = attr.NHS;
                const isUS = roadNHS === 'YES';
                const isState = roadNHS === 'NO';
                if (fc > 3 && isUS) fc = 3;
                else if (fc > 4 && isState) fc = 4;
                return STATE_SETTINGS.global.getRoadTypeFromFC(fc, layer);
            }
        },
        KY: {
            baseUrl: 'https://maps.kytc.ky.gov/arcgis/rest/services/BaseMap/System/MapServer/',
            supportsPagination: false,
            defaultColors: {
                Fw: '#ffaac5',
                Ew: '#ff00c5',
                MH: '#149ece',
                mH: '#4ce600',
                PS: '#cfae0e',
                St: '#eeeeee'
            },
            zoomSettings: { maxOffset: [30, 15, 8, 4, 2, 1, 1, 1, 1, 1] },
            /* eslint-disable object-curly-newline */
            fcMapLayers: [
                {
                    layerID: 0,
                    idPropName: 'OBJECTID',
                    fcPropName: 'FC',
                    outFields: ['FC', 'OBJECTID', 'RT_PREFIX', 'RT_SUFFIX'],
                    roadTypeMap: { Fw: [1], Ew: [2], MH: [3], mH: [4], PS: [5, 6], St: [7] },
                    maxRecordCount: 1000,
                    supportsPagination: false
                }
            ],
            isPermitted() {
                return true;
            },
            information: { Source: 'KYTC', Permission: 'Visible to All', Description: 'Federal and State highways set to a minimum of mH.' },
            getWhereClause(context) {
                if (context.mapContext.zoom < 16) {
                    return `${context.layer.fcPropName}<7`;
                }
                return null;
            },
            getFeatureRoadType(feature, layer) {
                const attr = feature.attributes;
                let fc = parseInt(attr[layer.fcPropName], 10);
                if (fc > 3 && attr.RT_PREFIX === 'US') {
                    const suffix = attr.RT_SUFFIX;
                    fc = suffix && suffix.indexOf('X') > -1 ? 4 : 3;
                }
                return STATE_SETTINGS.global.getRoadTypeFromFC(fc, layer);
            }
        },
        LA: {
            baseUrl: 'https://maps.dotd.la.gov/road/rest/services/Roads_and_Highways_OpenData/FeatureServer/',
            supportsPagination: false,
            defaultColors: {
                Fw: '#ff00c5',
                Ew: '#4f33df',
                MH: '#149ece',
                mH: '#4ce600',
                PS: '#cfae0e',
                St: '#eeeeee'
            },
            zoomSettings: { maxOffset: [30, 15, 8, 4, 2, 1, 1, 1, 1, 1], excludeRoadTypes: [['St'], ['St'], ['St'], ['St'], [], [], [], [], [], [], []] },
            /* eslint-disable object-curly-newline */
            fcMapLayers: [
                {
                    layerID: 84,
                    fcPropName: 'FunctionalSystem',
                    idPropName: 'OBJECTID',
                    outFields: ['OBJECTID', 'FunctionalSystem', 'RouteID'],
                    roadTypeMap: { Fw: [1], Ew: [2], MH: [3], mH: [4], PS: [5, 6], St: [7] },
                    maxRecordCount: 1000,
                    supportsPagination: false
                }
            ],
            /* eslint-enable object-curly-newline */
            information: { Source: 'LaDOTD', Permission: 'Visible to R4+ or R3-AM', Description: 'Federal and State highways set to a minimum of mH.' },
            getWhereClause(context) {
                if (context.mapContext.zoom < 16) {
                    return `${context.layer.fcPropName}<7`;
                }
                return null;
            },
            getFeatureRoadType(feature, layer) {
                let fc = feature.attributes[layer.fcPropName];
                if (fc === '2a' || fc === '2b') {
                    fc = 2;
                }
                fc = parseInt(fc, 10);
                const route = feature.attributes.RouteID.split('_')[1].trim();
                const isUS = /^US \d/.test(route);
                const isState = /^LA \d/.test(route);
                const isBiz = / BUS$/.test(route);
                if (fc > 3 && isUS) fc = isBiz ? 4 : 3;
                else if (fc > 4 && isState) fc = isBiz ? 5 : 4;
                return STATE_SETTINGS.global.getRoadTypeFromFC(fc, layer);
            }
        },
        ME: {
            baseUrl: 'https://arcgisserver.maine.gov/arcgis/rest/services/mdot/MaineDOT_Dynamic/MapServer/',
            defaultColors: {
                Fw: '#ff00c5',
                Ew: '#4f33df',
                MH: '#149ece',
                mH: '#4ce600',
                PS: '#cfae0e',
                St: '#eeeeee'
            },
            zoomSettings: { maxOffset: [30, 15, 8, 4, 2, 1, 1, 1, 1, 1], excludeRoadTypes: [['St'], ['St'], ['St'], ['St'], [], [], [], [], [], [], []] },
            fcMapLayers: [
                {
                    layerID: 6,
                    fcPropName: 'fedfunccls',
                    idPropName: 'objectid',
                    outFields: ['objectid', 'fedfunccls'],
                    roadTypeMap: {
                        Fw: [1],
                        Ew: [2],
                        MH: [3],
                        mH: [4],
                        PS: [5, 6],
                        St: [7]
                    },
                    maxRecordCount: 1000,
                    supportsPagination: false
                }
            ],
            information: { Source: 'MaineDOT', Permission: 'Visible to R4+ or R3-AM', Description: 'Raw unmodified FC data.' },
            isPermitted() {
                return rank >= 4 || (rank === 3 && isAM);
            },
            getWhereClause(context) {
                if (context.mapContext.zoom < 16) {
                    return `${context.layer.fcPropName}<>'Local'`;
                }
                return null;
            },
            getFeatureRoadType(feature, layer) {
                const attr = feature.attributes;
                let fc = attr[layer.fcPropName];
                switch (fc) {
                    case 'Interstate':
                        fc = 1;
                        break;
                    case 'Other Freeway or Expressway':
                        fc = 2;
                        break;
                    case 'Other Principal Arterial':
                        fc = 3;
                        break;
                    case 'Minor Arterial':
                        fc = 4;
                        break;
                    case 'Major Collector':
                    case 'Minor Collector':
                        fc = 5;
                        break;
                    default:
                        fc = 7;
                }
                // 2024-6-28 (mapomatic) MaineDOT removed the prirtename field so we can't "upgrade" FC anymore.
                // const route = attr.prirtename;
                // const isUS = /^US \d/.test(route);
                // const isState = /^ST RTE \d/.test(route);
                // const isBiz = (isUS && /(1B|1BS)$/.test(route)) || (isState && /(15B|24B|25B|137B)$/.test(route));
                // if (fc > 3 && isUS) fc = isBiz ? 4 : 3;
                // else if (fc > 4 && isState) fc = isBiz ? 5 : 4;
                return STATE_SETTINGS.global.getRoadTypeFromFC(fc, layer);
            }
        },
        MD: {
            baseUrl: 'https://services.arcgis.com/njFNhDsUCentVYJW/arcgis/rest/services/MDOT_SHA_Roadway_Functional_Classification/FeatureServer/',
            defaultColors: {
                Fw: '#ff00c5',
                Ew: '#4f33df',
                MH: '#149ece',
                mH: '#4ce600',
                PS: '#ffff00',
                St: '#eeeeee'
            },
            zoomSettings: { maxOffset: [30, 15, 8, 4, 2, 1, 1, 1, 1, 1], excludeRoadTypes: [['St'], ['St'], ['St'], ['St'], [], [], [], [], [], [], []] },
            fcMapLayers: [
                {
                    layerID: 0,
                    fcPropName: 'FUNCTIONAL_CLASS',
                    idPropName: 'OBJECTID',
                    outFields: ['OBJECTID', 'FUNCTIONAL_CLASS', 'ID_PREFIX', 'MP_SUFFIX'],
                    roadTypeMap: {
                        Fw: [1],
                        Ew: [2],
                        MH: [3],
                        mH: [4],
                        PS: [5, 6],
                        St: [7]
                    },
                    maxRecordCount: 1000,
                    supportsPagination: false
                }
            ],
            information: { Source: 'MDOT', Permission: 'Visible to R4+ or R3-AM', Description: 'Federal and State highways set to a minimum of mH.' },
            getWhereClause(context) {
                if (context.mapContext.zoom < 16) {
                    return "(FUNCTIONAL_CLASS < 7 OR ID_PREFIX IN('MD'))";
                }
                return null;
            },
            getFeatureRoadType(feature, layer) {
                const attr = feature.attributes;
                let fc = parseInt(attr.FUNCTIONAL_CLASS, 10);
                const isUS = attr.ID_PREFIX === 'US';
                const isState = attr.ID_PREFIX === 'MD';
                const isBiz = attr.MP_SUFFIX === 'BU';
                if (fc > 3 && isUS) fc = isBiz ? 4 : 3;
                else if (fc > 4 && isState) fc = isBiz ? 5 : 4;
                return STATE_SETTINGS.global.getRoadTypeFromFC(fc, layer);
            }
        },
        MA: {
            baseUrl: 'https://gis.massdot.state.ma.us/arcgis/rest/services/Roads/RoadInventory/MapServer/',
            defaultColors: {
                Fw: '#ff00c5',
                Ew: '#4f33df',
                MH: '#149ece',
                mH: '#4ce600',
                PS: '#cfae0e',
                St: '#eeeeee'
            },
            zoomSettings: { maxOffset: [30, 15, 8, 4, 2, 1, 1, 1, 1, 1], excludeRoadTypes: [['St'], ['St'], ['St'], ['St'], [], [], [], [], [], [], []] },
            fcMapLayers: [
                {
                    layerID: 0,
                    fcPropName: 'F_F_Class',
                    idPropName: 'OBJECTID',
                    outFields: ['OBJECTID', 'F_F_Class', 'route_id'],
                    roadTypeMap: {
                        Fw: [1],
                        Ew: [2],
                        MH: [3],
                        mH: [4],
                        PS: [5, 6],
                        St: [7]
                    },
                    maxRecordCount: 1000,
                    supportsPagination: false
                }
            ],
            information: { Source: 'MDOT', Permission: 'Visible to R2+', Description: 'Federal and State highways set to a minimum of mH.' },
            isPermitted() {
                return rank >= 2;
            },
            getWhereClause(context) {
                if (context.mapContext.zoom < 16) {
                    return `${context.layer.fcPropName}<>7`;
                }
                return null;
            },
            getFeatureRoadType(feature, layer) {
                const attr = feature.attributes;
                let fc = parseInt(attr[layer.fcPropName], 10);
                const route = attr.route_id;
                const isUS = /^US\d/.test(route);
                const isState = /^SR\d/.test(route);
                if (fc > 3 && isUS) fc = 3;
                else if (fc > 4 && isState) fc = 4;
                return STATE_SETTINGS.global.getRoadTypeFromFC(fc, layer);
            }
        },
        MI: {
            baseUrl: 'https://mdotgis.state.mi.us/arcgis/rest/services/DataAccess/NfcNhsPub/MapServer/',
            defaultColors: {
                Fw: '#ff00c5',
                Ew: '#149ece',
                MH: '#149ece',
                mH: '#4ce600',
                PS: '#cfae0e',
                St: '#eeeeee'
            },
            zoomSettings: { maxOffset: [30, 15, 8, 4, 2, 1, 1, 1, 1, 1], excludeRoadTypes: [['St'], ['St'], ['St'], ['St'], [], [], [], [], [], [], []] },
            fcMapLayers: [
                {
                    layerID: 353,
                    idPropName: 'OBJECTID',
                    fcPropName: 'FunctionalSystem',
                    outFields: ['FunctionalSystem'],
                    roadTypeMap: {
                        Fw: [1],
                        Ew: [2],
                        MH: [3],
                        mH: [4],
                        PS: [5, 6],
                        St: [7]
                    },
                    maxRecordCount: 1000,
                    supportsPagination: false
                }
            ],
            isPermitted() {
                return true;
            },
            information: { Source: 'MDOT', Permission: 'Visible to All', Description: 'Raw unmodified FC data.' },
            getWhereClause(context) {
                if (context.mapContext.zoom < 16) {
                    return `${context.layer.fcPropName}<7`;
                }
                return null;
            },
            getFeatureRoadType(feature, layer) {
                if (layer.getFeatureRoadType) {
                    return layer.getFeatureRoadType(feature);
                }
                return STATE_SETTINGS.global.getFeatureRoadType(feature, layer);
            }
        },
        MN: {
            baseUrl: 'https://dotapp9.dot.state.mn.us/lrs/rest/services/emma/emma_op/MapServer/',
            defaultColors: {
                Fw: '#ff00c5',
                Ew: '#149ece',
                MH: '#149ece',
                mH: '#4ce600',
                PS: '#cfae0e',
                St: '#eeeeee'
            },
            zoomSettings: { maxOffset: [30, 15, 8, 4, 2, 1, 1, 1, 1, 1], excludeRoadTypes: [['St'], ['St'], ['St'], ['St'], [], [], [], [], [], [], []] },
            fcMapLayers: [
                {
                    layerID: 13,
                    idPropName: 'OBJECTID',
                    fcPropName: 'FUNCTIONAL_CLASS',
                    outFields: ['FUNCTIONAL_CLASS', 'ROUTE_ID'],
                    roadTypeMap: {
                        Fw: [1],
                        Ew: [2],
                        MH: [3],
                        mH: [4],
                        PS: [5, 6],
                        St: [7]
                    },
                    maxRecordCount: 1000,
                    supportsPagination: false
                }
            ],
            isPermitted() {
                return true;
            },
            information: { Source: 'MnDOT', Permission: 'Visible to All', Description: 'Raw unmodified FC data.' },
            getWhereClause(context) {
                if (context.mapContext.zoom < 16) {
                    return `${context.layer.fcPropName}<>7`;
                }
                return null;
            },
            getFeatureRoadType(feature, layer) {
                if (layer.getFeatureRoadType) {
                    return layer.getFeatureRoadType(feature);
                }
                return STATE_SETTINGS.global.getFeatureRoadType(feature, layer);
            }
        },
        MO: {
            baseUrl: 'https://mapping.modot.org/arcgis/rest/services/BaseMap/TmsUtility/MapServer/',
            defaultColors: {
                Fw: '#ff00c5',
                Ew: '#4f33df',
                MH: '#149ece',
                mH: '#4ce600',
                PS: '#cfae0e',
                St: '#eeeeee'
            },
            zoomSettings: { maxOffset: [30, 15, 8, 4, 2, 1, 1, 1, 1, 1], excludeRoadTypes: [['St'], ['St'], ['St'], ['St'], [], [], [], [], [], [], []] },
            fcMapLayers: [
                {
                    layerID: 5,
                    fcPropName: 'FUNC_CLASS_NAME',
                    idPropName: 'SS_PAVEMENT_ID',
                    outFields: ['SS_PAVEMENT_ID', 'FUNC_CLASS_NAME', 'TRAVELWAY_DESG', 'TRAVELWAY_NAME', 'ACCESS_CAT_NAME'],
                    roadTypeMap: {
                        Fw: [1],
                        Ew: [2],
                        MH: [3],
                        mH: [4],
                        PS: [5, 6],
                        St: [7]
                    },
                    maxRecordCount: 1000,
                    supportsPagination: false
                }
            ],
            isPermitted() {
                return rank >= 3 || (rank >= 2 && isAM);
            },
            information: { Source: 'MoDOT', Permission: 'Visible to R3+ or R2-AM', Description: 'Federal and State highways set to a minimum of mH.' },
            getWhereClause(context) {
                if (context.mapContext.zoom < 13) {
                    return '1=0'; // WME very laggy at zoom 0
                }
                // Remove duplicate rows, but suss out interstate business loops
                return "FUNC_CLASS_NAME <> ' ' AND (TRAVELWAY_ID = CNTL_TW_ID OR (TRAVELWAY_ID <> CNTL_TW_ID AND TRAVELWAY_DESG = 'LP'))";
            },
            getFeatureRoadType(feature, layer) {
                const attr = feature.attributes;
                let fc = attr[layer.fcPropName];
                const rtType = attr.TRAVELWAY_DESG;
                const route = attr.TRAVELWAY_NAME;
                switch (fc) {
                    case 'INTERSTATE':
                        fc = 1;
                        break;
                    case 'FREEWAY':
                        fc = 2;
                        break;
                    case 'PRINCIPAL ARTERIAL':
                        fc = 3;
                        break;
                    case 'MINOR ARTERIAL':
                        fc = 4;
                        break;
                    case 'MAJOR COLLECTOR':
                        fc = 5;
                        break;
                    case 'MINOR COLLECTOR':
                        fc = 6;
                        break;
                    default:
                        fc = 8; // not a typo
                }
                const usHwys = ['24', '36', '40', '50', '54', '56', '59', '60', '61', '62', '63', '65', '67', '69', '71', '136', '159', '160', '166', '169', '275', '400', '412'];
                const isUS = ['US', 'LP'].includes(rtType); // is US or interstate biz
                const isState = ['MO', 'AL'].includes(rtType);
                const isSup = rtType === 'RT';
                const isBiz = ['BU', 'SP'].includes(rtType) || /BUSINESS .+ \d/.test(route);
                const isUSBiz = isBiz && usHwys.includes(route);
                if ((fc === 2 && attr.ACCESS_CAT_NAME !== 'FULL') || (fc > 3 && isUS)) fc = 3;
                else if (fc > 4 && (isState || isUSBiz)) fc = 4;
                else if (fc > 6 && (isSup || isBiz)) fc = 6;
                return STATE_SETTINGS.global.getRoadTypeFromFC(fc, layer);
            }
        },
        MT: {
            baseUrl: 'https://app.mdt.mt.gov/arcgis/rest/services/Standard/FUNCTIONAL_CLASS/MapServer/',
            defaultColors: {
                Fw: '#ff00c5',
                Ew: '#4f33df',
                MH: '#149ece',
                mH: '#4ce600',
                PS: '#cfae0e',
                St: '#eeeeee'
            },
            zoomSettings: { maxOffset: [30, 15, 8, 4, 2, 1, 1, 1, 1, 1], excludeRoadTypes: [['St'], ['St'], ['St'], ['St'], [], [], [], [], [], [], []] },
            fcMapLayers: [
                {
                    layerID: 0,
                    fcPropName: 'FUNC_CLASS',
                    idPropName: 'OBJECTID',
                    outFields: ['OBJECTID', 'FUNC_CLASS', 'SIGN_ROUTE', 'ROUTE_NAME'],
                    roadTypeMap: {
                        Fw: ['1-Interstate']
                    },
                    maxRecordCount: 1000,
                    supportsPagination: false
                },
                {
                    layerID: 1,
                    fcPropName: 'FUNC_CLASS',
                    idPropName: 'OBJECTID',
                    outFields: ['OBJECTID', 'FUNC_CLASS', 'SIGN_ROUTE', 'ROUTE_NAME'],
                    roadTypeMap: {
                        MH: ['3-Principal Arterial - Other']
                    },
                    maxRecordCount: 1000,
                    supportsPagination: false
                },
                {
                    layerID: 2,
                    fcPropName: 'FUNC_CLASS',
                    idPropName: 'OBJECTID',
                    outFields: ['OBJECTID', 'FUNC_CLASS', 'SIGN_ROUTE', 'ROUTE_NAME'],
                    roadTypeMap: {
                        mH: ['4-Minor Arterial']
                    },
                    maxRecordCount: 1000,
                    supportsPagination: false
                },
                {
                    layerID: 3,
                    fcPropName: 'FUNC_CLASS',
                    idPropName: 'OBJECTID',
                    outFields: ['OBJECTID', 'FUNC_CLASS', 'SIGN_ROUTE', 'ROUTE_NAME'],
                    roadTypeMap: {
                        PS: ['5-Major Collector']
                    },
                    maxRecordCount: 1000,
                    supportsPagination: false
                },
                {
                    layerID: 4,
                    fcPropName: 'FUNC_CLASS',
                    idPropName: 'OBJECTID',
                    outFields: ['OBJECTID', 'FUNC_CLASS', 'SIGN_ROUTE', 'ROUTE_NAME'],
                    roadTypeMap: {
                        PS: ['6-Minor Collector']
                    },
                    maxRecordCount: 1000,
                    supportsPagination: false
                },
                {
                    layerID: 5,
                    fcPropName: 'FUNC_CLASS',
                    idPropName: 'OBJECTID',
                    outFields: ['OBJECTID', 'FUNC_CLASS', 'SIGN_ROUTE', 'ROUTE_NAME'],
                    roadTypeMap: {
                        St: ['7-Local']
                    },
                    maxRecordCount: 1000,
                    supportsPagination: false
                }
            ],
            isPermitted() {
                /* return _r >= 3; */ return ['mapomatic', 'bobc455', 'js55ct'].includes(userNameLC);
            },
            information: { Source: 'MDT', Permission: '?', Description: 'Federal and State highways set to a minimum of mH.' },
            getWhereClause(context) {
                if (context.mapContext.zoom < 16) {
                    return `${context.layer.fcPropName}<>'LOCAL'`;
                }
                return null;
            },
            getFeatureRoadType(feature, layer) {
                let rt = STATE_SETTINGS.global.getFeatureRoadType(feature, layer);
                const roadID = feature.attributes.SIGN_ROUTE || feature.attributes.ROUTE_NAME;
                const isUS = /^US[ -]?\d+/.test(roadID);
                const isState = /^MONTANA \d+|ROUTE \d+|S-\d{3}\b/.test(roadID);
                if (isUS && ['St', 'PS', 'mH'].includes(rt)) {
                    rt = 'MH';
                } else if (isState && ['St', 'PS'].includes(rt)) {
                    rt = 'mH';
                }
                return rt;
            }
        },
        NV: {
            baseUrl: 'https://gis.dot.nv.gov/rhgis/rest/services/GeoHub/FSystem/MapServer/',
            defaultColors: {
                Fw: '#ff00c5',
                Ew: '#4f33df',
                MH: '#149ece',
                mH: '#4ce600',
                PS: '#cfae0e',
                St: '#eeeeee'
            },
            zoomSettings: { maxOffset: [30, 15, 8, 4, 2, 1, 1, 1, 1, 1], excludeRoadTypes: [[], [], [], [], [], [], [], [], [], [], []] },
            fcMapLayers: [
                {
                    layerID: 0,
                    fcPropName: 'FSystem',
                    idPropName: 'OBJECTID',
                    outFields: ['OBJECTID', 'FSystem'],
                    roadTypeMap: {
                        Fw: [1],
                        Ew: [2],
                        MH: [3],
                        mH: [4],
                        PS: [5, 6],
                        St: [7]
                    },
                    maxRecordCount: 1000,
                    supportsPagination: false
                }
            ],
            isPermitted() {
                return ['mapomatic', 'turbomkt', 'tonestertm', 'geopgeop', 'ojlaw', 'js55ct'].includes(userNameLC);
            },
            information: { Source: 'NDOT', Permission: '?', Description: 'Raw unmodified FC data.' },
            getWhereClause(context) {
                if (context.mapContext.zoom < 16) {
                    return `${context.layer.fcPropName}<7`;
                }
                return null;
            },
            getFeatureRoadType(feature, layer) {
                const fc = parseInt(feature.attributes[layer.fcPropName], 10);
                return STATE_SETTINGS.global.getRoadTypeFromFC(fc, layer);
            }
        },
        NH: {
            baseUrl: 'https://maps.dot.nh.gov/arcgis_server/rest/services/Highways/NHDOT_HIGHWAYS_Functional_System/FeatureServer/',
            defaultColors: {
                Fw: '#ff00c5',
                Ew: '#4f33df',
                MH: '#149ece',
                mH: '#4ce600',
                PS: '#cfae0e',
                St: '#eeeeee'
            },
            zoomSettings: { maxOffset: [30, 15, 8, 4, 2, 1, 1, 1, 1, 1], excludeRoadTypes: [[], [], [], [], [], [], [], [], [], [], []] },
            fcMapLayers: [
                {
                    layerID: 19, // 0
                    fcPropName: 'FUNCT_SYSTEM',
                    idPropName: 'OBJECTID',
                    outFields: ['OBJECTID', 'FUNCT_SYSTEM', 'STREET', 'TIER'],
                    roadTypeMap: {
                        Fw: [1],
                        Ew: [2],
                        MH: [2, 3],
                        mH: [4],
                        PS: [5, 6],
                        St: [7, 0]
                    },
                    maxRecordCount: 1000,
                    supportsPagination: false
                }
            ],
            isPermitted() {
                return rank >= 2;
            },
            information: { Source: 'NH GRANIT', Permission: 'Visible to R2+', Description: 'Federal and State highways set to a minimum of mH.' },
            getWhereClause(context) {
                if (context.mapContext.zoom < 16) {
                    return `${context.layer.fcPropName}>0 AND ${context.layer.fcPropName}<7`;
                }
                return null;
            },
            getFeatureRoadType(feature, layer) {
                let fc = parseInt(feature.attributes[layer.fcPropName], 10);
                if (!(fc > 0)) {
                    fc = 7;
                }
                const route = feature.attributes.STREET_ALIASES;
                const isUS = /US /.test(route);
                const isState = /NH /.test(route);
                if (fc === 2) fc = feature.attributes.TIER === 1 ? 1 : 3;
                else if (fc > 3 && isUS) fc = /US 3B/.test(route) ? 4 : 3;
                else if (fc > 4 && isState) fc = 4;
                return STATE_SETTINGS.global.getRoadTypeFromFC(fc, layer);
            }
        },
        NM: {
            baseUrl: 'https://services.arcgis.com/hOpd7wfnKm16p9D9/ArcGIS/rest/services/NMDOT_Functional_Class/FeatureServer/',
            defaultColors: {
                Fw: '#ff00c5',
                Ew: '#ff00c5',
                MH: '#149ece',
                mH: '#4ce600',
                PS: '#cfae0e',
                St: '#eeeeee'
            },
            zoomSettings: { maxOffset: [30, 15, 8, 4, 2, 1, 1, 1, 1, 1] },
            fcMapLayers: [
                {
                    layerID: 0,
                    fcPropName: 'FSystem',
                    idPropName: 'OBJECTID',
                    maxRecordCount: 1000,
                    supportsPagination: false,
                    outFields: ['OBJECTID', 'FSystem', 'RouteID'],
                    roadTypeMap: {
                        Fw: [1],
                        Ew: [2],
                        MH: [3],
                        mH: [4],
                        PS: [5, 6],
                        St: [7, 0]
                    }
                }
            ],
            isPermitted() {
                return true;
            },
            information: { Source: 'NMDOT', Permission: 'Visible to All', Description: 'Federal and State highways set to a minimum of mH.' },
            getWhereClause(context) {
                if (context.mapContext.zoom < 16) {
                    return `${context.layer.fcPropName}>0 AND ${context.layer.fcPropName}<7`;
                }
                return null;
            },
            getFeatureRoadType(feature, layer) {
                let fc = parseInt(feature.attributes[layer.fcPropName], 10);
                const roadType = feature.attributes.RouteID.substring(0, 2); // Get first two characters
                const isBiz = roadType === 'BL'; // Interstate Business Loop
                const isUS = roadType === 'US';
                const isState = roadType === 'NM';

                if (roadType === 'IX') {
                    fc = 0;
                } else if (fc > 3 && (isBiz || isUS)) {
                    fc = 3;
                } else if (fc > 4 && isState) {
                    fc = 4;
                }

                return STATE_SETTINGS.global.getRoadTypeFromFC(fc, layer);
            }
        },
        NY: {
            // https://gis.dot.ny.gov/hostingny/rest/services/Basemap/MapServer/21
            baseUrl: 'https://gis.dot.ny.gov/hostingny/rest/services/',
            defaultColors: {
                Fw: '#ff00c5',
                Ew: '#5f33df',
                MH: '#149ece',
                mH: '#4ce600',
                PS: '#cfae0e',
                St: '#eeeeee'
            },
            zoomSettings: { maxOffset: [30, 15, 8, 4, 2, 1, 1, 1, 1, 1] },
            fcMapLayers: [
                {
                    layerID: 1,
                    layerPath: 'Geocortex/FC/MapServer/',
                    fcPropName: 'FUNC_CLASS',
                    idPropName: 'OBJECTID',
                    outFields: ['OBJECTID', 'FUNC_CLASS', 'SEGMENT_NAME', 'ROUTE_NO'],
                    roadTypeMap: {
                        Fw: [1, 11],
                        Ew: [2, 12],
                        MH: [4, 14],
                        mH: [6, 16],
                        PS: [7, 8, 17, 18],
                        St: [9, 19]
                    },
                    maxRecordCount: 1000,
                    supportsPagination: false
                },
                {
                    layerID: 21,
                    layerPath: 'Basemap/MapServer/',
                    idPropName: 'OBJECTID',
                    outFields: ['OBJECTID', 'SHIELD'],
                    maxRecordCount: 1000,
                    supportsPagination: false
                }
            ],
            information: { Source: 'NYSDOT', Permission: 'Visible to R4+ or R3-AM', Description: 'Federal and State highways set to a minimum of mH.' },
            getWhereClause(context) {
                if (context.layer.layerID === 21) {
                    return "SHIELD IN ('C','CT')";
                }
                return null;
            },
            getFeatureRoadType(feature, layer) {
                let roadType;
                if (layer.layerID === 21) {
                    roadType = 'PS';
                } else {
                    roadType = STATE_SETTINGS.global.getFeatureRoadType(feature, layer);
                    const routeNo = feature.attributes.ROUTE_NO;
                    if (/^NY.*/.test(routeNo)) {
                        if (roadType === 'PS') roadType = 'mH';
                    } else if (/^US.*/.test(routeNo)) {
                        if (roadType === 'PS' || roadType === 'mH') roadType = 'MH';
                    }
                }
                return roadType;
            }
        },
        NC: {
            baseUrl: 'https://gis11.services.ncdot.gov/arcgis/rest/services/NCDOT_FunctionalClassQtr/MapServer/',
            defaultColors: {
                Fw: '#ff00c5',
                Rmp: '#999999',
                Ew: '#5f33df',
                MH: '#149ece',
                mH: '#4ce600',
                PS: '#cfae0e',
                St: '#eeeeee'
            },
            zoomSettings: { maxOffset: [30, 15, 8, 4, 2, 1, 1, 1, 1, 1], excludeRoadTypes: [['St'], ['St'], ['St'], ['St'], [], [], [], [], [], [], []] },
            fcMapLayers: [
                {
                    layerID: 0,
                    fcPropName: 'FuncClass',
                    idPropName: 'OBJECTID',
                    outFields: ['OBJECTID', 'FuncClass', 'RouteClass', 'RouteQualifier'],
                    roadTypeMap: {
                        Fw: [1],
                        Ew: [2],
                        MH: [3],
                        mH: [4],
                        PS: [5, 6],
                        St: [7]
                    },
                    zoomLevels: [3, 4, 5, 6, 7, 8, 9, 10],
                    maxRecordCount: 1000,
                    supportsPagination: false
                }
            ],
            isPermitted() {
                return rank >= 3;
            },
            information: { Source: 'NCDOT', Permission: 'Visible to R3+', Description: 'Federal and State highways set to a minimum of mH.' },
            getWhereClause(context) {
                if (context.mapContext.zoom < 16) {
                    const clause = `(${context.layer.fcPropName} < 7 OR RouteClass IN ('I','FED','NC','RMP','US'))`;
                    return clause;
                }
                return null;
            },
            getFeatureRoadType(feature, layer) {
                const fc = feature.attributes[layer.fcPropName];
                let roadType;
                switch (this.getHwySys(feature)) {
                    case 'interstate':
                        if (fc <= 2 || !this.isBusinessRoute(feature)) roadType = 'Fw';
                        else roadType = 'MH';
                        break;
                    case 'us':
                        if (fc <= 2) roadType = 'Ew';
                        else if (fc === 3 || !this.isBusinessRoute(feature)) roadType = 'MH';
                        else roadType = 'mH';
                        break;
                    case 'state':
                        if (fc <= 2) roadType = 'Ew';
                        else if (fc === 3) roadType = 'MH';
                        else if (fc === 4 || !this.isBusinessRoute(feature)) roadType = 'mH';
                        else roadType = 'PS';
                        break;
                    case 'ramp':
                        roadType = 'Rmp';
                        break;
                    default:
                        if (fc === 2) roadType = 'Ew';
                        else if (fc === 3) roadType = 'MH';
                        else if (fc === 4) roadType = 'mH';
                        else if (fc <= 6) roadType = 'PS';
                        else roadType = 'St';
          // roadType = fc === 2 ? 'Ew' : (fc === 3 ? 'MH' : (fc === 4 ? 'mH' : (fc <= 6 ? 'PS' : 'St')));
                }
                return roadType;
            },
            getHwySys(feature) {
                let hwySys;
                switch (feature.attributes.RouteClass.toString()) {
                    case '1':
                        hwySys = 'interstate';
                        break;
                    case '2':
                        hwySys = 'us';
                        break;
                    case '3':
                        hwySys = 'state';
                        break;
                    case '80':
                        hwySys = 'ramp';
                        break;
                    default:
                        hwySys = 'local';
                }
                return hwySys;
            },
            isBusinessRoute(feature) {
                const qual = feature.attributes.RouteQualifier.toString();
                return qual === '9';
            }
        },
        ND: {
            baseUrl: 'https://ndgishub.nd.gov/arcgis/rest/services/Basemap_General/MapServer/',
            defaultColors: {
                Fw: '#ff00c5',
                Ew: '#149ece',
                MH: '#149ece',
                mH: '#4ce600',
                PS: '#cfae0e',
                St: '#eeeeee'
            },
            zoomSettings: { maxOffset: [30, 15, 8, 4, 2, 1, 1, 1, 1, 1], excludeRoadTypes: [['St'], ['St'], ['St'], ['St'], [], [], [], [], [], [], []] },
            fcMapLayers: [
                {
                    layerID: 193,
                    fcPropName: 'FUNCTIONAL_CLASS',
                    idPropName: 'OBJECTID',
                    outFields: ['OBJECTID', 'FUNCTIONAL_CLASS'],
                    roadTypeMap: {
                        MH: [3],
                        mH: [4],
                        PS: [5, 6],
                        St: [7]
                    },
                    maxRecordCount: 1000,
                    supportsPagination: false
                },
                {
                    layerID: 192,
                    fcPropName: 'RTE_SIN',
                    idPropName: 'OBJECTID',
                    outFields: ['OBJECTID', 'RTE_SIN'],
                    roadTypeMap: {
                        Fw: ['I'],
                        MH: ['U'],
                        mH: ['S']
                    },
                    maxRecordCount: 1000,
                    supportsPagination: false
                }
            ],
            information: { Source: 'NDDOT', Permission: 'Visible to R4+ or R3-AM', Description: 'Federal and State highways set to a minimum of mH.' },
            getWhereClause(context) {
                if (context.mapContext.zoom < 16) {
                    if (context.layer.layerID === 193) {
                        return `${context.layer.fcPropName} < 7`;
                    }
                    if (context.layer.layerID === 192) {
                        return "RTE_SIN IN ('I','U','S')";
                    }
                }
                return null;
            },
            getFeatureRoadType(feature, layer) {
                if (layer.getFeatureRoadType) {
                    return layer.getFeatureRoadType(feature);
                }
                return STATE_SETTINGS.global.getFeatureRoadType(feature, layer);
            }
        },
        OH: {
            baseUrl: 'https://gis.dot.state.oh.us/arcgis/rest/services/TIMS/Roadway_Information/MapServer/',
            defaultColors: {
                Fw: '#ff00c5',
                Ew: '#4f33df',
                MH: '#149ece',
                mH: '#4ce600',
                PS: '#cfae0e',
                St: '#eeeeee'
            },
            zoomSettings: { maxOffset: [30, 15, 8, 4, 2, 1, 1, 1, 1, 1], excludeRoadTypes: [['St'], ['St'], ['St'], ['St'], [], [], [], [], [], [], []] },

            fcMapLayers: [
                {
                    layerID: 8,
                    fcPropName: 'FUNCTION_CLASS_CD',
                    idPropName: 'ObjectID',
                    outFields: ['FUNCTION_CLASS_CD', 'ROUTE_TYPE', 'ROUTE_NBR', 'ObjectID'],
                    maxRecordCount: 1000,
                    supportsPagination: false,
                    roadTypeMap: {
                        Fw: [1],
                        Ew: [2],
                        MH: [3],
                        mH: [4],
                        PS: [5, 6],
                        St: [7]
                    }
                }
            ],
            isPermitted() {
                return true;
            },
            information: { Source: 'ODOT', Permission: 'Visible to All', Description: 'Federal and State highways set to a minimum of mH.' },
            getWhereClause(context) {
                if (context.mapContext.zoom < 16) {
                    const clause = `(${context.layer.fcPropName} < 7 OR ROUTE_TYPE IN ('CR','SR','US')) AND ${context.layer.fcPropName} IS NOT NULL`;
                    return clause;
                }
                return `${context.layer.fcPropName} IS NOT NULL`;
            },
            getFeatureRoadType(feature, layer) {
                let fc = feature.attributes[layer.fcPropName];
                const prefix = feature.attributes.ROUTE_TYPE;
                const isUS = prefix === 'US';
                const isState = prefix === 'SR';
                const isCounty = prefix === 'CR';
                if (isUS && fc > 3) {
                    fc = 3;
                }
                if (isState && fc > 4) {
                    fc = 4;
                }
                if (isCounty && fc > 6) {
                    fc = 6;
                }
                return STATE_SETTINGS.global.getRoadTypeFromFC(fc, layer);
            }
        },
        OK: {
            baseUrl: 'https://services6.arcgis.com/RBtoEUQ2lmN0K3GY/arcgis/rest/services/Roadways/FeatureServer/',
            defaultColors: {
                Fw: '#ff00c5',
                Ew: '#4f33df',
                MH: '#149ece',
                mH: '#4ce600',
                PS: '#cfae0e',
                St: '#eeeeee'
            },
            zoomSettings: { maxOffset: [30, 15, 8, 4, 2, 1, 1, 1, 1, 1], excludeRoadTypes: [['St'], ['St'], ['St'], ['St'], [], [], [], [], [], [], []] },
            fcMapLayers: [
                {
                    layerID: 0,
                    fcPropName: 'FUNCTIONALCLASS',
                    idPropName: 'OBJECTID',
                    outFields: ['OBJECTID', 'FUNCTIONALCLASS', 'FHWAPRIMARYROUTE', 'ODOTROUTECLASS', 'ACCESSCONTROL'],
                    maxRecordCount: 1000,
                    supportsPagination: false,
                    roadTypeMap: {
                        Fw: [1],
                        Ew: [2],
                        MH: [3],
                        mH: [4],
                        PS: [5, 6],
                        St: [7]
                    }
                }
            ],
            information: { Source: 'ODOT', Permission: 'Visible to R4+ or R3-AM', Description: 'Federal and State highways set to a minimum of mH.' },
            getWhereClause(context) {
                if (context.mapContext.zoom < 16) {
                    return `${context.layer.fcPropName} < 7 OR ODOTROUTECLASS IN ('U','S','I')`;
                }
                return null;
            },
            getFeatureRoadType(feature, layer) {
                let fc = feature.attributes[layer.fcPropName];
                const route = (feature.attributes.FHWAPRIMARYROUTE || '').trim();
                const isBusinessOrSpur = /BUS$|SPR$/i.test(route);
                const prefix = isBusinessOrSpur ? route.substring(0, 1) : feature.attributes.ODOTROUTECLASS;
                const isFw = parseInt(feature.attributes.ACCESSCONTROL, 10) === 1;
                const isInterstate = prefix === 'I';
                const isUS = prefix === 'U';
                const isState = prefix === 'S';
                if (isFw) fc = 1;
                else if (fc > 3 && ((isUS && !isBusinessOrSpur) || (isInterstate && isBusinessOrSpur))) fc = 3;
                else if (fc > 4 && ((isUS && isBusinessOrSpur) || (isState && !isBusinessOrSpur))) fc = 4;
                else if (fc > 5 && isState && isBusinessOrSpur) fc = 5;
                return STATE_SETTINGS.global.getRoadTypeFromFC(fc, layer);
            }
        },
        OR: {
            baseUrl: 'https://gis.odot.state.or.us/arcgis1006/rest/services/transgis/catalog/MapServer/',
            defaultColors: {
                Fw: '#ff00c5',
                Ew: '#4f33df',
                MH: '#149ece',
                mH: '#4ce600',
                PS: '#cfae0e',
                St: '#eeeeee'
            },
            zoomSettings: { maxOffset: [30, 15, 8, 4, 2, 1, 1, 1, 1, 1], excludeRoadTypes: [['St'], ['St'], ['St'], ['St'], [], [], [], [], [], [], []] },
            fcMapLayers: [
                {
                    layerID: 171,
                    fcPropName: 'NEW_FC_CD',
                    idPropName: 'OBJECTID',
                    outFields: ['OBJECTID', 'NEW_FC_CD'],
                    roadTypeMap: {
                        Fw: ['1'],
                        Ew: ['2'],
                        MH: ['3'],
                        mH: ['4'],
                        PS: ['5', '6'],
                        St: ['7']
                    },
                    maxRecordCount: 1000,
                    supportsPagination: false
                },
                {
                    layerID: 173,
                    fcPropName: 'NEW_FC_CD',
                    idPropName: 'OBJECTID',
                    outFields: ['OBJECTID', 'NEW_FC_CD'],
                    roadTypeMap: {
                        Fw: ['1'],
                        Ew: ['2'],
                        MH: ['3'],
                        mH: ['4'],
                        PS: ['5', '6'],
                        St: ['7']
                    },
                    maxRecordCount: 1000,
                    supportsPagination: false
                }
            ],
            information: { Source: 'ODOT', Permission: 'Visible to R4+ or R3-AM', Description: 'Raw unmodified FC data.' },
            getWhereClause(context) {
                if (context.mapContext.zoom < 16) {
                    return `${context.layer.fcPropName} < 7`;
                }
                return null;
            },
            getFeatureRoadType(feature, layer) {
                if (layer.getFeatureRoadType) {
                    return layer.getFeatureRoadType(feature);
                }
                return STATE_SETTINGS.global.getFeatureRoadType(feature, layer);
            }
        },
        PA: {
            baseUrl: 'https://gis.penndot.gov/arcgis/rest/services/opendata/roadwayadmin/MapServer/',
            supportsPagination: false,
            defaultColors: {
                Fw: '#ff00c5',
                Ew: '#4f33df',
                MH: '#149ece',
                mH: '#4ce600',
                PS: '#cfae0e',
                St: '#eeeeee'
            },
            zoomSettings: { maxOffset: [30, 15, 8, 4, 2, 1, 1, 1, 1, 1], excludeRoadTypes: [['St'], ['St'], ['St'], ['St'], [], [], [], [], [], [], []] },
            fcMapLayers: [
                {
                    layerID: 0,
                    features: new Map(),
                    fcPropName: 'FUNC_CLS',
                    idPropName: 'MSLINK',
                    outFields: ['MSLINK', 'FUNC_CLS'],
                    maxRecordCount: 1000,
                    supportsPagination: false,
                    roadTypeMap: {
                        Fw: ['01', '11'],
                        Ew: ['12'],
                        MH: ['02', '14'],
                        mH: ['06', '16'],
                        PS: ['07', '08', '17'],
                        St: ['09', '19']
                    }
                }
            ],
            isPermitted() {
                return rank >= 4;
            },
            information: { Source: 'PennDOT', Permission: 'Visible to R4+', Description: 'Raw unmodified FC data.' },
            getWhereClause(context) {
                return context.mapContext.zoom < 16 ? `${context.layer.fcPropName} NOT IN ('09','19')` : null;
            },
            getFeatureRoadType(feature, layer) {
                if (layer.getFeatureRoadType) {
                    return layer.getFeatureRoadType(feature);
                }
                const fc = feature.attributes[layer.fcPropName];
                return STATE_SETTINGS.global.getRoadTypeFromFC(fc, layer);
            }
        },
        RI: {
            baseUrl: 'https://services2.arcgis.com/S8zZg9pg23JUEexQ/arcgis/rest/services/RIDOT_Roads_2016/FeatureServer/',
            defaultColors: {
                Fw: '#ff00c5',
                Ew: '#4f33df',
                MH: '#149ece',
                mH: '#4ce600',
                PS: '#cfae0e',
                St: '#eeeeee'
            },
            zoomSettings: { maxOffset: [30, 15, 8, 4, 2, 1, 1, 1, 1, 1], excludeRoadTypes: [[], [], [], [], [], [], [], [], [], [], []] },
            fcMapLayers: [
                {
                    layerID: 0,
                    fcPropName: 'F_SYSTEM',
                    idPropName: 'OBJECTID',
                    outFields: ['OBJECTID', 'F_SYSTEM', 'ROADTYPE', 'RTNO'],
                    roadTypeMap: {
                        Fw: [1],
                        Ew: [2],
                        MH: [3],
                        mH: [4],
                        PS: [5, 6],
                        St: [7, 0]
                    },
                    maxRecordCount: 1000,
                    supportsPagination: false
                }
            ],
            isPermitted() {
                return rank >= 2;
            },
            information: { Source: 'RIDOT', Permission: 'Visible to R2+', Description: 'Federal and State highways set to a minimum of mH.' },
            getWhereClause(context) {
                return context.mapContext.zoom < 16 ? `${context.layer.fcPropName} NOT IN (7,0)` : null;
            },
            getFeatureRoadType(feature, layer) {
                let fc = parseInt(feature.attributes[layer.fcPropName], 10);
                const type = feature.attributes.ROADTYPE;
                const rtnum = feature.attributes.RTNO;
                if (fc === 2 && ['10', '24', '37', '78', '99', '138', '403'].includes(rtnum)) fc = 1; // isFW
                else if ((fc > 3 && type === 'US') || rtnum === '1') fc = 3; // isUS
                else if (fc > 4 && rtnum.trim() !== '') fc = 4; // isState
                return STATE_SETTINGS.global.getRoadTypeFromFC(fc, layer);
            }
        },
        SC: {
            baseUrl: 'https://services1.arcgis.com/VaY7cY9pvUYUP1Lf/ArcGIS/rest/services/FunctionalClass/FeatureServer/',
            defaultColors: {
                Fw: '#ff00c5',
                Ew: '#4f33df',
                MH: '#149ece',
                mH: '#4ce600',
                PS: '#cfae0e',
                St: '#eeeeee'
            },
            zoomSettings: { maxOffset: [30, 15, 8, 4, 2, 1, 1, 1, 1, 1], excludeRoadTypes: [['St'], ['St'], ['St'], ['St'], [], [], [], [], [], [], []] },
            fcMapLayers: [
                {
                    layerID: 0,
                    fcPropName: 'Functional',
                    idPropName: 'FID',
                    outFields: ['FID', 'Functional', 'RouteType'],
                    maxRecordCount: 1000,
                    supportsPagination: false,
                    roadTypeMap: {
                        Fw: [1, 11],
                        Ew: [6, 12],
                        MH: [2, 13],
                        mH: [3, 14],
                        PS: [4, 5, 15, 16],
                        St: []
                    }
                }
            ],
            isPermitted() {
                return rank >= 4;
            },
            information: { Source: 'SCDOT', Permission: 'Visible to R4+', Description: 'Federal and State highways set to a minimum of mH.' },
            getWhereClause() {
                return null;
            },
            getFeatureRoadType(feature, layer) {
                const SCroadType = feature.attributes.RouteType;
                const isFw = SCroadType === 1;
                const isUS = SCroadType === 2;
                const isState = SCroadType === 4;

                let roadType = STATE_SETTINGS.global.getFeatureRoadType(feature, layer);
                if (roadType === 'Fw' || roadType === 'Ew' || isFw) {
                    roadType = 'Fw';
                } else if ((roadType === 'mH' || roadType === 'PS') && isUS) {
                    roadType = 'MH';
                } else if (roadType === 'PS' && isState) {
                    roadType = 'mH';
                }
                return roadType;
            }
        },
        SD: {
            baseUrl: 'https://arcgis.sd.gov/arcgis/rest/services/SD_All/Transportation_Roads/MapServer/',
            defaultColors: {
                Fw: '#ff00c5',
                Ew: '#149ece',
                MH: '#149ece',
                mH: '#4ce600',
                PS: '#cfae0e',
                St: '#eeeeee',
                PSGr: '#cc6533',
                StGr: '#e99cb6'
            },
            zoomSettings: { maxOffset: [30, 15, 8, 4, 2, 1, 1, 1, 1, 1], excludeRoadTypes: [['St'], ['St'], ['St'], ['St'], [], [], [], [], [], [], []] },
            fcMapLayers: [
                {
                    layerID: 1,
                    fcPropName: 'HighwayClass',
                    idPropName: 'GisHighwayCategoryID',
                    maxRecordCount: 1000,
                    supportsPagination: false,
                    outFields: ['GisHighwayCategoryID', 'HighwayClass'],
                    roadTypeMap: {
                        Fw: ['IN'],
                        MH: ['US'],
                        mH: ['SD']

                    }
                },
                {
                    layerID: 2,
                    fcPropName: 'FUNC_CLASS',
                    idPropName: 'OBJECTID',
                    maxRecordCount: 1000,
                    supportsPagination: false,
                    outFields: ['OBJECTID', 'FUNC_CLASS', 'SURFACE_TYPE', 'ROADNAME'],
                    roadTypeMap: {
                        Fw: [1, 11],
                        Ew: [2, 12],
                        MH: [4, 14],
                        mH: [6, 16],
                        PS: [7, 8, 17],
                        St: [9, 19]
                    }
                }
            ],
            information: { Source: 'SDDOT', Permission: 'Visible to R4+ or R3-AM', Description: 'Additional colors denote unpaved PS and LS segements.' },
            getWhereClause(context) {
                if (context.mapContext.zoom < 16) {
                    if (context.layer.layerID === 2) {
                        return `${context.layer.fcPropName} NOT IN (9,19)`;
                    }
                }
                return null;
            },
            getFeatureRoadType(feature, layer) {
                const attr = feature.attributes;
                let fc = attr[layer.fcPropName];
                const fc2 = parseInt(fc, 10) % 10;

                const isUS = /^US HWY /i.test(attr.ROADNAME);
                const isState = /^SD HWY /i.test(attr.ROADNAME);
                const isBiz = /^(US|SD) HWY .* (E|W)?(B|L)$/i.test(attr.ROADNAME);
                const isPaved = parseInt(attr.SURFACE_TYPE, 10) > 5;

                if (fc2 > 4 && isUS) fc = isBiz ? 6 : 4;
                else if (fc2 > 6 && isState) fc = isBiz ? 7 : 6;
                if (fc2 > 6 && !isPaved) {
                    return fc < 9 ? 'PSGr' : 'StGr';
                }
                return STATE_SETTINGS.global.getRoadTypeFromFC(fc, layer);
            }
        },
        TN: {
            baseUrl: 'https://',
            defaultColors: {
                Fw: '#ff00c5',
                Ew: '#4f33df',
                MH: '#149ece',
                mH: '#4ce600',
                PS: '#cfae0e',
                PS2: '#cfae0e',
                St: '#eeeeee'
            },
            zoomSettings: { maxOffset: [30, 15, 8, 4, 2, 1, 1, 1, 1, 1] },
            fcMapLayers: [
                {
                    layerPath: 'services2.arcgis.com/nf3p7v7Zy4fTOh6M/ArcGIS/rest/services/Road_Segment/FeatureServer/',
                    maxRecordCount: 1000,
                    supportsPagination: false,
                    layerID: 0,
                    fcPropName: 'FUNC_CLASS',
                    idPropName: 'OBJECTID',
                    outFields: ['OBJECTID', 'FUNC_CLASS', 'NBR_RTE', 'NBR_US_RTE'],
                    getWhereClause(context) {
                        if (context.mapContext.zoom < 16) {
                            return `${context.layer.fcPropName} NOT LIKE '%Local'`;
                        }
                        return null;
                    },
                    roadTypeMap: {
                        Fw: ['Urban Interstate', 'Rural Interstate'],
                        Ew: ['Urban Freeway or Expressway', 'Rural Freeway or Expressway'],
                        MH: ['Urban Other Principal Arterial', 'Rural Other Principal Arterial'],
                        mH: ['Urban Minor Arterial', 'Rural Minor Arterial'],
                        PS: ['Urban Major Collector', 'Rural Major Collector'],
                        PS2: ['Urban Minor Collector', 'Rural Minor Collector'],
                        St: ['Urban Local', 'Rural Local']
                    }
                }
            ],
            information: {
                Source: 'Memphis, Nashville Area MPO',
                Permission: 'Visible to R4+ or R3-AM',
                Description: 'Raw unmodified FC data for the Memphis and Nashville regions only.'
            },
            getWhereClause(context) {
                if (context.layer.getWhereClause) {
                    return context.layer.getWhereClause(context);
                }
                return null;
            },
            getFeatureRoadType(feature, layer) {
                if (layer.getFeatureRoadType) {
                    return layer.getFeatureRoadType(feature);
                }
                let fc = STATE_SETTINGS.global.getRoadTypeFromFC(feature.attributes.FUNC_CLASS, layer);
                if ((fc === 'PS' || fc === 'mH') && feature.attributes.NBR_US_RTE != null) {
                    fc = feature.attributes.NBR_US_RTE.endsWith('BR') ? 'mH' : 'MH';
                } else if (fc === 'PS' && (feature.attributes.NBR_RTE.startsWith('SR') || feature.attributes.NBR_RTE.startsWith('TN'))) {
                    fc = 'mH';
                }
                return fc;
            }
        },
        TX: {
            baseUrl: 'https://services.arcgis.com/KTcxiTD9dsQw4r7Z/ArcGIS/rest/services/TxDOT_Functional_Classification/FeatureServer/',
            defaultColors: {
                Fw: '#ff00c5',
                Ew: '#4f33df',
                MH: '#149ece',
                mH: '#4ce600',
                PS: '#cfae0e',
                St: '#eeeeee'
            },
            zoomSettings: { maxOffset: [30, 15, 8, 4, 2, 1, 1, 1, 1, 1] },
            fcMapLayers: [
                {
                    layerID: 0,
                    fcPropName: 'F_SYSTEM',
                    idPropName: 'OBJECTID',
                    outFields: ['OBJECTID', 'F_SYSTEM', 'RTE_PRFX'],
                    maxRecordCount: 1000,
                    supportsPagination: false,
                    roadTypeMap: {
                        Fw: [1],
                        Ew: [2],
                        MH: [3],
                        mH: [4],
                        PS: [5, 6],
                        St: [7]
                    }
                }
            ],
            isPermitted() {
                return rank >= 2;
            },
            information: { Source: 'TxDOT', Permission: 'Visible to R2+', Description: 'Federal and State highways set to a minimum of mH.' },
            getWhereClause(context) {
                let where = ' F_SYSTEM IS NOT NULL AND RTE_PRFX IS NOT NULL';
                if (context.mapContext.zoom < 16) {
                    where += ` AND ${context.layer.fcPropName} <> 7`;
                }
                return where;
            },
            getFeatureRoadType(feature, layer) {
                // On-System:
                // IH=Interstate BF=Business FM
                // US=US Highway FM=Farm to Mkt
                // UA=US Alt. RM=Ranch to Mkt
                // UP=US Spur RR=Ranch Road
                // SH=State Highway PR=Park Road
                // SA=State Alt. RE=Rec Road
                // SL=State Loop RP=Rec Rd Spur
                // SS=State Spur FS=FM Spur
                // BI=Business IH RS=RM Spur
                // BU=Business US RU=RR Spur
                // BS=Business State PA=Principal Arterial
                // Off-System:
                // TL=Off-System Tollroad CR=County Road
                // FC=Func. Classified St. LS=Local Street
                if (layer.getFeatureRoadType) {
                    return layer.getFeatureRoadType(feature);
                }
                let fc = feature.attributes[layer.fcPropName];
                const type = feature.attributes.RTE_PRFX.substring(0, 2).toUpperCase();
                if (type === 'IH' && fc > 1) {
                    fc = 1;
                } else if ((type === 'US' || type === 'BI' || type === 'UA') && fc > 3) {
                    fc = 3;
                } else if ((type === 'UP' || type === 'BU' || type === 'SH' || type === 'SA') && fc > 4) {
                    fc = 4;
                } else if ((type === 'SL' || type === 'SS' || type === 'BS') && fc > 6) {
                    fc = 6;
                }
                return STATE_SETTINGS.global.getRoadTypeFromFC(fc, layer);
            }
        },
        UT: {
            baseUrl: 'https://roads.udot.utah.gov/server/rest/services/Public/Functional_Class/MapServer/0',
            defaultColors: {
                Fw: '#ff00c5',
                Ew: '#4f33df',
                MH: '#149ece',
                mH: '#4ce600',
                PS: '#cfae0e',
                St: '#eeeeee'
            },
            zoomSettings: { maxOffset: [30, 15, 8, 4, 2, 1, 1, 1, 1, 1], excludeRoadTypes: [['St'], ['St'], ['St'], ['St'], [], [], [], [], [], [], []] },
            fcMapLayers: [
                {
                    layerID: 0,
                    fcPropName: 'FUNCTIONAL_CLASS',
                    idPropName: 'OBJECTID',
                    outFields: ['OBJECTID', 'FUNCTIONAL_CLASS', 'route_id'],
                    roadTypeMap: {
                        Fw: [1],
                        Ew: [2],
                        MH: [3],
                        mH: [4],
                        PS: [5, 6],
                        St: [7]
                    },
                    maxRecordCount: 1000,
                    supportsPagination: false
                }
            ],
            information: { Source: 'UDOT', Permission: 'Visible to R4+ or R3-AM', Description: 'Federal and State highways set to a minimum of mH.' },
            getWhereClause(context) {
                return `${context.layer.fcPropName} NOT LIKE 'Proposed%'`;
            },
            getFeatureRoadType(feature, layer) {
                const attr = feature.attributes;
                let fc = attr[layer.fcPropName];
                const routeID = attr.route_id;
                const roadNum = parseInt(routeID.substring(0, 4), 10);
                switch (fc) {
                    case 'Interstate':
                        fc = 1;
                        break;
                    case 'Other Freeways and Expressways':
                        fc = 2;
                        break;
                    case 'Other Principal Arterial':
                        fc = 3;
                        break;
                    case 'Minor Arterial':
                        fc = 4;
                        break;
                    case 'Major Collector':
                        fc = 5;
                        break;
                    case 'Minor Collector':
                        fc = 6;
                        break;
                    default:
                        fc = 7;
                }
                const re = /^(6|40|50|89|91|163|189|191|491)$/;
                if (re.test(roadNum) && fc > 3) {
                    // US highway
                    fc = 3;
                } else if (roadNum <= 491 && fc > 4) {
                    // State highway
                    fc = 4;
                }
                return STATE_SETTINGS.global.getRoadTypeFromFC(fc, layer);
            }
        },
        VT: {
            baseUrl: 'https://maps.vtrans.vermont.gov/arcgis/rest/services/Master/General/FeatureServer/',
            defaultColors: {
                Fw: '#ff00c5',
                Ew: '#4f33df',
                MH: '#149ece',
                mH: '#4ce600',
                PS: '#cfae0e',
                St: '#eeeeee'
            },
            zoomSettings: { maxOffset: [30, 15, 8, 4, 2, 1, 1, 1, 1, 1], excludeRoadTypes: [['St'], ['St'], ['St'], ['St'], [], [], [], [], [], [], []] },
            fcMapLayers: [
                {
                    layerID: 39,
                    fcPropName: 'FUNCL',
                    idPropName: 'OBJECTID',
                    outFields: ['OBJECTID', 'FUNCL', 'HWYSIGN'],
                    roadTypeMap: {
                        Fw: [1],
                        Ew: [2],
                        MH: [3],
                        mH: [4],
                        PS: [5, 6],
                        St: [7]
                    },
                    maxRecordCount: 1000,
                    supportsPagination: false
                }
            ],
            information: { Source: 'VTrans', Permission: 'Visible to R2+' },
            isPermitted() {
                return rank >= 2;
            },
            getWhereClause(context) {
                if (context.mapContext.zoom < 16) {
                    return `${context.layer.fcPropName}<>7 AND ${context.layer.fcPropName}<>0`;
                }
                return null;
            },
            getFeatureRoadType(feature, layer) {
                const roadID = feature.attributes.HWYSIGN;
                let fc = feature.attributes[layer.fcPropName];
                if (!(fc > 0)) {
                    fc = 7;
                }
                const isUS = /^U/.test(roadID);
                const isState = /^V/.test(roadID);
                const isUSBiz = /^B/.test(roadID);
                if (fc > 3 && isUS) fc = 3;
                else if (fc > 4 && (isUSBiz || isState)) fc = 4;
                return STATE_SETTINGS.global.getRoadTypeFromFC(fc, layer);
            }
        },
        VA: {
            baseUrl: 'https://services.arcgis.com/p5v98VHDX9Atv3l7/arcgis/rest/services/FC_2014_FHWA_Submittal1/FeatureServer/',
            defaultColors: {
                Fw: '#ff00c5',
                Ew: '#ff00c5',
                MH: '#149ece',
                mH: '#4ce600',
                PS: '#cfae0e',
                St: '#eeeeee'
            },
            zoomSettings: { maxOffset: [30, 15, 8, 4, 2, 1, 1, 1, 1, 1], excludeRoadTypes: [['St'], ['St'], ['St'], ['St'], [], [], [], [], [], [], []] },
            fcMapLayers: [
                {
                    layerID: 0,
                    fcPropName: 'STATE_FUNCT_CLASS_ID',
                    idPropName: 'OBJECTID',
                    outFields: ['OBJECTID', 'STATE_FUNCT_CLASS_ID', 'RTE_NM'],
                    maxRecordCount: 2000,
                    supportsPagination: true,
                    roadTypeMap: {
                        Fw: [1],
                        Ew: [2],
                        MH: [3],
                        mH: [4],
                        PS: [5, 6],
                        St: [7]
                    }
                },
                {
                    layerID: 1,
                    fcPropName: 'STATE_FUNCT_CLASS_ID',
                    idPropName: 'OBJECTID',
                    outFields: ['OBJECTID', 'STATE_FUNCT_CLASS_ID', 'Opp_RTE_NM', 'ROUTE_NO'],
                    maxRecordCount: 2000,
                    supportsPagination: true,
                    roadTypeMap: {
                        Fw: [1],
                        Ew: [2],
                        MH: [3],
                        mH: [4],
                        PS: [5, 6],
                        St: [7]
                    }
                },
                {
                    layerID: 3,
                    fcPropName: 'TMPD_FC',
                    idPropName: 'OBJECTID',
                    outFields: ['OBJECTID', 'TMPD_FC', 'RTE_NM'],
                    maxRecordCount: 2000,
                    supportsPagination: true,
                    roadTypeMap: {
                        Fw: [1],
                        Ew: [2],
                        MH: [3],
                        mH: [4],
                        PS: [5, 6],
                        St: [7]
                    }
                }
            ],
            information: { Source: 'VDOT', Permission: 'Visible to R4+ or R3-AM', Description: 'Federal and State highways set to a minimum of mH.' },
            srExceptions: [
                217, 302, 303, 305, 308, 310, 313, 314, 315, 317, 318, 319, 320, 321, 322, 323, 324, 325,
                326, 327, 328, 329, 330, 331, 332, 333, 334, 335, 336, 339, 341, 342, 343, 344, 345, 346,
                347, 348, 350, 353, 355, 357, 358, 361, 362, 363, 364, 365, 366, 367, 368, 369, 370, 371,
                372, 373, 374, 375, 376, 377, 378, 379, 382, 383, 384, 385, 386, 387, 388, 389, 390, 391,
                392, 393, 394, 396, 397, 398, 399, 785, 895
            ],
            getWhereClause(context) {
                if (context.mapContext.zoom < 16) {
                    return `${context.layer.fcPropName}<7`;
                }
                // NOTE: As of 9/14/2016 there does not appear to be any US/SR/VA labeled routes with FC = 7.
                return null;
            },
            getFeatureRoadType(feature, layer) {
                if (layer.getFeatureRoadType) {
                    return layer.getFeatureRoadType(feature);
                }
                let fc = parseInt(feature.attributes[layer.fcPropName], 10);
                const rtName = feature.attributes.RTE_NM || feature.attributes.Opp_RTE_NM;
                const match = /^R-VA\s*(US|VA|SR)(\d{5})..(BUS)?/.exec(rtName);
                const isBusiness = match && match !== null && match[3] === 'BUS';
                const isState = match && match !== null && (match[1] === 'VA' || match[1] === 'SR');
                let rtNumText;
                if (layer.layerID === 1) {
                    rtNumText = feature.attributes.ROUTE_NO;
                } else if (match) {
                    // eslint-disable-next-line prefer-destructuring
                    rtNumText = match[2];
                } else {
                    rtNumText = '99999';
                }
                const rtNum = parseInt(rtNumText, 10);
                const rtPrefix = match && match[1];
                if (fc > 3 && rtPrefix === 'US') {
                    fc = isBusiness ? 4 : 3;
                } else if (isState && fc > 4 && this.srExceptions.indexOf(rtNum) === -1 && rtNum < 600) {
                    fc = isBusiness ? 5 : 4;
                }
                return STATE_SETTINGS.global.getRoadTypeFromFC(fc, layer);
            }
        },
        WA: {
            baseUrl: 'https://data.wsdot.wa.gov/arcgis/rest/services/FunctionalClass/WSDOTFunctionalClassMap/MapServer/',
            defaultColors: {
                Fw: '#ff00c5',
                Ew: '#4f33df',
                MH: '#149ece',
                mH: '#4ce600',
                PS: '#cfae0e',
                St: '#eeeeee'
            },
            zoomSettings: { maxOffset: [30, 15, 8, 4, 2, 1, 1, 1, 1, 1], excludeRoadTypes: [['St'], ['St'], ['St'], ['St'], [], [], [], [], [], [], []] },
            fcMapLayers: [
                {
                    layerID: 2,
                    fcPropName: 'FederalFunctionalClassCode',
                    idPropName: 'OBJECTID',
                    outFields: ['OBJECTID', 'FederalFunctionalClassCode'],
                    roadTypeMap: {
                        Fw: [1],
                        Ew: [2],
                        MH: [3],
                        mH: [4],
                        PS: [5, 6],
                        St: [7]
                    },
                    maxRecordCount: 1000,
                    supportsPagination: false
                },
                {
                    layerID: 1,
                    fcPropName: 'FederalFunctionalClassCode',
                    idPropName: 'OBJECTID',
                    outFields: ['OBJECTID', 'FederalFunctionalClassCode'],
                    roadTypeMap: {
                        Fw: [1],
                        Ew: [2],
                        MH: [3],
                        mH: [4],
                        PS: [5, 6],
                        St: [7]
                    },
                    maxRecordCount: 1000,
                    supportsPagination: false
                },
                {
                    layerID: 4,
                    fcPropName: 'FederalFunctionalClassCode',
                    idPropName: 'OBJECTID',
                    outFields: ['OBJECTID', 'FederalFunctionalClassCode'],
                    roadTypeMap: {
                        Fw: [1],
                        Ew: [2],
                        MH: [3],
                        mH: [4],
                        PS: [5, 6],
                        St: [7]
                    },
                    maxRecordCount: 1000,
                    supportsPagination: false
                }
            ],
            information: { Source: 'WSDOT', Permission: 'Visible to R4+ or R3-AM', Description: 'Raw unmodified FC data.' },
            getWhereClause(context) {
                if (context.mapContext.zoom < 16) {
                    return `${context.layer.fcPropName} <> 7`;
                }
                return null;
            },
            getFeatureRoadType(feature, layer) {
                if (layer.getFeatureRoadType) {
                    return layer.getFeatureRoadType(feature);
                }
                return STATE_SETTINGS.global.getFeatureRoadType(feature, layer);
            }
        },
        WV: {
            baseUrl: 'https://gis.transportation.wv.gov/arcgis/rest/services/Routes/MapServer/',
            defaultColors: {
                Fw: '#ff00c5',
                Ew: '#ff00c5',
                MH: '#149ece',
                mH: '#4ce600',
                PS: '#cfae0e',
                St: '#eeeeee'
            },
            zoomSettings: { maxOffset: [30, 15, 8, 4, 2, 1, 1, 1, 1, 1], excludeRoadTypes: [['St'], ['St'], ['St'], ['St'], [], [], [], [], [], [], []] },
            fcMapLayers: [
                {
                    layerID: 2,
                    fcPropName: 'NAT_FUNCTIONAL_CLASS',
                    idPropName: 'OBJECTID',
                    outFields: ['OBJECTID', 'NAT_FUNCTIONAL_CLASS', 'ROUTE_ID'],
                    maxRecordCount: 1000,
                    supportsPagination: true,
                    roadTypeMap: {
                        Fw: [1],
                        Ew: [2],
                        MH: [3],
                        mH: [4],
                        PS: [5, 6],
                        St: [7]
                    }
                }
            ],
            information: { Source: 'WV DOT' },
            isPermitted() {
                return true;
            },
            getWhereClause(context) {
                if (context.mapContext.zoom < 16) {
                    return `${context.layer.fcPropName} NOT IN (9,19)`;
                }
                return null;
            },
            getFeatureRoadType(feature, layer) {
                if (layer.getFeatureRoadType) {
                    return layer.getFeatureRoadType(feature);
                }
                const fcCode = feature.attributes[layer.fcPropName];
                let fc = fcCode;
                if (fcCode === 11) fc = 1;
                else if (fcCode === 4 || fcCode === 12) fc = 2;
                else if (fcCode === 2 || fcCode === 14) fc = 3;
                else if (fcCode === 6 || fcCode === 16) fc = 4;
                else if (fcCode === 7 || fcCode === 17 || fcCode === 8 || fcCode === 18) fc = 5;
                else fc = 7;
                const id = feature.attributes.ROUTE_ID;
                const prefix = id.substr(2, 1);
                const isInterstate = prefix === '1';
                const isUS = prefix === '2';
                const isState = prefix === '3';
                if (fc > 1 && isInterstate) fc = 1;
                else if (fc > 3 && isUS) fc = 3;
                else if (fc > 4 && isState) fc = 4;
                return STATE_SETTINGS.global.getRoadTypeFromFC(fc, layer);
            }
        },
        WY: {
            baseUrl: 'https://gisservices.wyoroad.info/arcgis/rest/services/ITSM/ITSM_Data_Layers/MapServer/',
            defaultColors: {
                Fw: '#ff00c5',
                Ew: '#4f33df',
                MH: '#149ece',
                mH: '#4ce600',
                PS: '#cfae0e',
                St: '#eeeeee'
            },
            zoomSettings: { maxOffset: [30, 15, 8, 4, 2, 1, 1, 1, 1, 1], excludeRoadTypes: [['St'], ['St'], ['St'], ['St'], [], [], [], [], [], [], []] },
            fcMapLayers: [
                {
                    layerID: 20,
                    fcPropName: 'classification',
                    idPropName: 'objectid',
                    outFields: ['objectid', 'classification', 'common_route_name'],
                    roadTypeMap: {
                        Fw: [1],
                        Ew: [2],
                        MH: [3],
                        mH: [4],
                        PS: [5, 6],
                        St: [7]
                    },
                    maxRecordCount: 1000,
                    supportsPagination: false
                },
                {
                    layerID: 21,
                    fcPropName: 'classification',
                    idPropName: 'objectid',
                    outFields: ['objectid', 'classification', 'common_route_name'],
                    roadTypeMap: {
                        Fw: [1],
                        Ew: [2],
                        MH: [3],
                        mH: [4],
                        PS: [5, 6],
                        St: [7]
                    },
                    maxRecordCount: 1000,
                    supportsPagination: false
                },
                {
                    layerID: 22,
                    fcPropName: 'classification',
                    idPropName: 'objectid',
                    outFields: ['objectid', 'classification', 'common_route_name'],
                    roadTypeMap: {
                        Fw: [1],
                        Ew: [2],
                        MH: [3],
                        mH: [4],
                        PS: [5, 6],
                        St: [7]
                    },
                    maxRecordCount: 1000,
                    supportsPagination: false
                },
                {
                    layerID: 23,
                    fcPropName: 'classification',
                    idPropName: 'objectid',
                    outFields: ['objectid', 'classification', 'common_route_name'],
                    roadTypeMap: {
                        Fw: [1],
                        Ew: [2],
                        MH: [3],
                        mH: [4],
                        PS: [5, 6],
                        St: [7]
                    },
                    maxRecordCount: 1000,
                    supportsPagination: false
                },
                {
                    layerID: 24,
                    fcPropName: 'classification',
                    idPropName: 'objectid',
                    outFields: ['objectid', 'classification', 'common_route_name'],
                    roadTypeMap: {
                        Fw: [1],
                        Ew: [2],
                        MH: [3],
                        mH: [4],
                        PS: [5, 6],
                        St: [7]
                    },
                    maxRecordCount: 1000,
                    supportsPagination: false
                },
                {
                    layerID: 25,
                    fcPropName: 'classification',
                    idPropName: 'objectid',
                    outFields: ['objectid', 'classification', 'common_route_name'],
                    roadTypeMap: {
                        Fw: [1],
                        Ew: [2],
                        MH: [3],
                        mH: [4],
                        PS: [5, 6],
                        St: [7]
                    },
                    maxRecordCount: 1000,
                    supportsPagination: false
                },
                {
                    layerID: 26,
                    fcPropName: 'classification',
                    idPropName: 'objectid',
                    outFields: ['objectid', 'classification', 'common_route_name'],
                    roadTypeMap: {
                        Fw: [1],
                        Ew: [2],
                        MH: [3],
                        mH: [4],
                        PS: [5, 6],
                        St: [7]
                    },
                    maxRecordCount: 1000,
                    supportsPagination: false
                }
            ],
            information: { Source: 'WYDOT', Permission: 'Visible to R4+ or R3-AM', Description: 'Minimum suggested FC.' },
            getWhereClause(context) {
                if (context.mapContext.zoom < 16) {
                    return `${context.layer.fcPropName} <> 'Local'`;
                }
                return null;
            },
            getFeatureRoadType(feature, layer) {
                const attr = feature.attributes;
                let fc = parseInt(attr[layer.fcPropName], 10);
                const route = attr.common_route_name;
                const isIntBiz = /I (25|80) BUS/.test(route);
                const isUS = /US \d+/.test(route);
                const isUSBiz = /US \d+ BUS/.test(route);
                const isState = /WY \d+/.test(route);
                const isStateBiz = /WY \d+ BUS/.test(route);
                if (fc > 3 && (isUS || isIntBiz)) fc = isUSBiz ? 4 : 3;
                else if (fc > 4 && isState) fc = isStateBiz ? 5 : 4;
                return STATE_SETTINGS.global.getRoadTypeFromFC(fc, layer);
            }
        }
    };

    function log(message, object) {
        if (object !== undefined) {
            console.log('FC Layer:', message, object);
        } else {
            console.log('FC Layer:', message);
        }
    }

    function debugLog(message, object) {
        if (debug) {
            if (object !== undefined) {
                console.debug('FC Layer:', message, object);
            } else {
                console.debug('FC Layer:', message);
            }
        }
    }

    function errorLog(message, object) {
        if (object !== undefined) {
            console.error('FC Layer:', message, object);
        } else {
            console.error('FC Layer:', message);
        }
    }

    function loadSettingsFromStorage() {
        const storedSettings = $.parseJSON(localStorage.getItem(settingsStoreName)) || {};
        const defaultSettings = {
            layerVisible: true,
            activeStateAbbr: 'ALL',
            hideStreet: false
        };
        settings = { ...defaultSettings, ...storedSettings };
    }

    function saveSettingsToStorage() {
        if (localStorage) {
            // In case the layer is turned off some other way...
            settings.layerVisible = sdk.Map.isLayerVisible({ layerName });
            localStorage.setItem(settingsStoreName, JSON.stringify(settings));
        }
    }

    function sortArray(array) {
        array.sort((a, b) => {
            if (a < b) return -1;
            if (a > b) return 1;
            return 0;
        });
    }

    function getVisibleStateAbbreviations() {
        const { activeStateAbbr } = settings;
        return sdk.DataModel.States.getAll()
            .map(state => STATES_HASH[state.name])
            .filter(stateAbbr => STATE_SETTINGS[stateAbbr] && STATE_SETTINGS.global.isPermitted(stateAbbr) && (!activeStateAbbr || activeStateAbbr === 'ALL' || activeStateAbbr === stateAbbr));
    }

    function getAsync(url, context) {
        debugLog(
            `Fetching data for ${context.stateAbbr} from ${context.state.baseUrl}
        ${context.layer.layerPath ? context.layer.layerPath : ''}${context.layer.layerID ? context.layer.layerID : ''}`,
            context
        );

        return new Promise((resolve, reject) => {
            GM_xmlhttpRequest({
                context,
                method: 'GET',
                url,
                onload(res) {
                    if (res.status.toString() === '200') {
                        const parsedResponse = JSON.parse(res.responseText);
                        if (parsedResponse.error) {
                            reject(new Error(`API Error: ${parsedResponse.error.message}`));
                        } else {
                            resolve({ responseText: res.responseText, context });
                        }
                    } else {
                        reject(new Error(`HTTP ${res.status}: ${res.responseText}`));
                    }
                },
                onerror() {
                    reject(new Error('Network Error'));
                }
            });
        });
    }

    function getUrl(context, queryType, queryParams) {
        const { extent } = context.mapContext;
        const { zoom } = context.mapContext;
        const { layer } = context;
        const { state } = context;

        const whereParts = [];

        const geometry = {
            xmin: extent[0],
            ymin: extent[1],
            xmax: extent[2],
            ymax: extent[3],
            spatialReference: {
                wkid: 4326
            }
        };
        const geometryStr = JSON.stringify(geometry);
        const stateWhereClause = state.getWhereClause(context);
        const layerPath = layer.layerPath || '';
        let url = `${state.baseUrl + layerPath + layer.layerID}/query?geometry=${encodeURIComponent(geometryStr)}`;

        if (queryType === 'countOnly') {
            url += '&returnCountOnly=true';
        } else if (queryType === 'idsOnly') {
            url += '&returnIdsOnly=true';
        } else if (queryType === 'paged') {
            // TODO
        } else {
            // Convert to degrees (4326) from the old Meters (3857)
            url += `&returnGeometry=true&maxAllowableOffset=${state.zoomSettings.maxOffset[zoom - 12] / 111000}`;
            url += `&outFields=${encodeURIComponent(layer.outFields.join(','))}`;
            if (queryType === 'idRange') {
                whereParts.push(`(${queryParams.idFieldName}>=${queryParams.range[0]} AND ${queryParams.idFieldName}<=${queryParams.range[1]})`);
            }
        }
        if (stateWhereClause) whereParts.push(stateWhereClause);
        if (whereParts.length > 0) url += `&where=${encodeURIComponent(whereParts.join(' AND '))}`;
        url += '&spatialRel=esriSpatialRelIntersects&geometryType=esriGeometryEnvelope&inSR=4326&outSR=4326&f=json'; // &geometryPrecision=7  Not needed as it scales with maxAllowableOffset
        // debugLog(`URL Fetch Type = ${queryType}`, url );
        return url;
    }

    function convertFcToRoadTypeLineStrings(feature, context) {
        const { state, stateAbbr, layer } = context;
        const roadType = state.getFeatureRoadType(feature, layer);
        const attr = {
            state: stateAbbr,
            layerID: layer.layerID,
            roadType,
            color: state.defaultColors[roadType]
        };

        const lineStrings = feature.geometry.paths.map(path => {
            const line = turf.lineString(path, attr);
            line.id = 0;
            return line;
        });

        return lineStrings;
    }

    function fetchLayerFC(context) {
        const url = getUrl(context, 'idsOnly');
        context.idsOnlyURL = url;
        if (!context.parentContext.cancel) {
            return getAsync(url, context)
                .bind(context)
                .then(res => {
                    try {
                        const ids = JSON.parse(res.responseText);
                        if (!ids.objectIds) ids.objectIds = [];
                        if (ids.objectIds.length === 0) {
                            debugLog(`objectIds array is empty or undefined for State "${context.stateAbbr}" Layer "${
                                context.layer.layerID}" with context:`, context);
                        }
                        sortArray(ids.objectIds);
                        // debugLog(``,ids);
                        return ids;
                    } catch (err) {
                        errorLog(`Error parsing URL response JSON for State "${context.stateAbbr}" Layer "${context.layer.layerID}" with context:`, context);
                        throw err;
                    }
                })
                .then(res => {
                    const idRanges = [];
                    if (res.objectIds) {
                        const len = res.objectIds ? res.objectIds.length : 0;
                        let currentIndex = 0;
                        const offset = Math.min(context.layer.maxRecordCount, 1000);
                        while (currentIndex < len) {
                            let nextIndex = currentIndex + offset;
                            if (nextIndex >= len) nextIndex = len - 1;
                            idRanges.push({
                                range: [res.objectIds[currentIndex], res.objectIds[nextIndex]],
                                idFieldName: res.objectIdFieldName
                            });
                            currentIndex = nextIndex + 1;
                        }
                    }
                    return idRanges;
                })
                .map(idRange => {
                    if (!context.parentContext.cancel) {
                        const newUrl = getUrl(context, 'idRange', idRange);
                        context.idRangeURL = newUrl;
                        return getAsync(newUrl, context).then(res => {
                            if (!context.parentContext.cancel) {
                                let { features } = JSON.parse(res.responseText);
                                context.parentContext.callCount++;
                                features = features || [];
                                return features.map(feature => convertFcToRoadTypeLineStrings(feature, context)).filter(feature => !(feature[0].properties.roadType === 'St' && settings.hideStreet));
                            }
                            return null;
                        });
                    }
                    // debugLog('Async call cancelled');
                    return null;
                });
        }
        return null;
    }

    function fetchStateFC(context) {
        const state = STATE_SETTINGS[context.stateAbbr];
        const contexts = state.fcMapLayers.map(layer => ({
            parentContext: context.parentContext,
            layer,
            state,
            stateAbbr: context.stateAbbr,
            mapContext: context.mapContext
        }));

        return Promise.map(contexts, ctx => fetchLayerFC(ctx).catch(err => {
            const errorMessage = `
        | Failed to fetch layer:
        | State: ${ctx.stateAbbr}
        | layerID: ${ctx.layer.layerID}
        | Base URL: ${ctx.state.baseUrl}.
        | ${err.message}.
      `;
            return Promise.reject(new Error(errorMessage.trim()));
        }));
    }

    let _lastPromise = null;
    let _lastContext = null;
    let _fcCallCount = 0;

    function getArrayDepth(arr) {
        if (Array.isArray(arr)) {
            return 1 + Math.max(0, ...arr.map(getArrayDepth));
        }
        return 0;
    }

    function fetchAllFC() {
        if (!sdk.Map.isLayerVisible({ layerName })) return;

        if (_lastPromise) {
            _lastPromise.cancel();
        }
        $('#fc-loading-indicator').css('color', 'green').html('<span>Loading FC Layers ...</span>');

        const mapContext = { zoom: sdk.Map.getZoomLevel(), extent: sdk.Map.getMapExtent() };
        if (mapContext.zoom > MIN_ZOOM_LEVEL) {
            const parentContext = { callCount: 0, startTime: Date.now() };

            if (_lastContext) _lastContext.cancel = true;
            _lastContext = parentContext;

            const contexts = getVisibleStateAbbreviations().map(stateAbbr => ({ parentContext, stateAbbr, mapContext }));
            let errorOccurred = false; // Flag to track error state
            let featureCount = 0;

            const map = Promise.map(contexts, ctx => fetchStateFC(ctx))
                .then(statesLineStringArrays => {
                    if (!parentContext.cancel) {
                        sdk.Map.removeAllFeaturesFromLayer({ layerName });

                        // Determine the depth of the nested array structure
                        const depth = getArrayDepth(statesLineStringArrays);
                        debugLog(`Detected array depth: ${depth}`);

                        // Flatten the array based on the detected depth
                        const flattenedFeatures = statesLineStringArrays.flat(depth);
                        featureCount = flattenedFeatures.length;

                        // Add all features to the layer at once
                        sdk.Map.dangerouslyAddFeaturesToLayerWithoutValidation({
                            layerName,
                            features: flattenedFeatures
                        });
                    }
                    return statesLineStringArrays;
                })
                .catch(e => {
                    const formattedMessage = e.message.replace(/\|/g, '<br>');
                    $('#fc-loading-indicator').css('color', 'red').html(`${formattedMessage}`);
                    errorOccurred = true;
                    errorLog(e.message);
                })
                .finally(() => {
                    _fcCallCount -= 1;
                    if (_fcCallCount === 0 && !errorOccurred) {
                        $('#fc-loading-indicator').html('<span></span>');
                    }

                    const endTime = Date.now();
                    const durationSeconds = (endTime - parentContext.startTime) / 1000;
                    debugLog(`Loaded ${featureCount} features in ${durationSeconds.toFixed(2)} seconds`);
                });

            _fcCallCount += 1;
            _lastPromise = map;
        } else {
            // if zoomed out too far, clear the layer
            sdk.Map.removeAllFeaturesFromLayer({ layerName });
        }
    }

    function onLayerCheckboxChanged(args) {
        setEnabled(args.checked);
    }

    function checkLayerZIndex() {
        try {
            if (sdk.Map.getLayerZIndex({ layerName }) !== MAP_LAYER_Z_INDEX) {
                // ("ADJUSTED FC LAYER Z-INDEX " + mapLayerZIndex + ', ' + mapLayer.getZIndex());
                sdk.Map.setLayerZIndex({ layerName, zIndex: MAP_LAYER_Z_INDEX });
            }
        } catch {
            // ignore this hack if it crashes
        }
    }

    function initLayer() {
        const styleRules = [
            {
                style: {
                    strokeColor: 'black',
                    strokeDashstyle: 'solid',
                    strokeOpacity: 1.0,
                    strokeWidth: '15'
                }
            }
        ];
        for (let zoom = 12; zoom < 22; zoom++) {
            styleRules.push({
                // eslint-disable-next-line no-loop-func
                predicate: () => sdk.Map.getZoomLevel() === zoom,
                style: {
                    strokeWidth: 12 * 1.15 ** (zoom - 13)
                }
            });
        }
        Object.values(STATE_SETTINGS)
            .filter(state => !!state.defaultColors)
            .forEach(state => Object.values(state.defaultColors).forEach(color => {
                if (!styleRules.some(rule => rule.style.strokeColor === color)) {
                    styleRules.push({
                        predicate: props => props.color === color,
                        style: { strokeColor: color }
                    });
                }
            }));

        STATE_SETTINGS.global.roadTypes.forEach((roadType, index) => {
            styleRules.push({
                predicate: props => props.roadType === roadType,
                style: { graphicZIndex: index * 100 }
            });
        });
        sdk.Map.addLayer({
            layerName,
            styleRules,
            zIndexing: true
        });

        sdk.Map.setLayerOpacity({ layerName, opacity: 0.5 });
        sdk.Map.setLayerVisibility({ layerName, visibility: settings.layerVisible });
        MAP_LAYER_Z_INDEX = sdk.Map.getLayerZIndex({ layerName: 'roads' }) - 3;
        sdk.Map.setLayerZIndex({ layerName, zIndex: MAP_LAYER_Z_INDEX });

        window.addEventListener('beforeunload', () => saveSettingsToStorage);

        sdk.LayerSwitcher.addLayerCheckbox({ name: 'FC Layer' });
        sdk.LayerSwitcher.setLayerCheckboxChecked({ name: 'FC Layer', isChecked: settings.layerVisible });
        sdk.Events.on({ eventName: 'wme-layer-checkbox-toggled', eventHandler: onLayerCheckboxChanged });

        // Hack to fix layer zIndex.  Some other code is changing it sometimes but I have not been able to figure out why.
        // It may be that the FC layer is added to the map before some Waze code loads the base layers and forces other layers higher. (?)
        setInterval(checkLayerZIndex, 1000);

        sdk.Events.on({ eventName: 'wme-map-move-end', eventHandler: fetchAllFC });
    }

    function onHideStreetsClicked() {
        settings.hideStreet = $(this).is(':checked');
        saveSettingsToStorage();
        sdk.Map.removeAllFeaturesFromLayer({ layerName });
        fetchAllFC();
    }

    function onStateSelectionChanged() {
        settings.activeStateAbbr = this.value;
        saveSettingsToStorage();
        loadStateFCInfo();
        fetchAllFC();
    }

    function setEnabled(value) {
        sdk.Map.setLayerVisibility({ layerName, visibility: value });
        settings.layerVisible = value;
        saveSettingsToStorage();

        const color = value ? '#00bd00' : '#ccc';
        $('span#fc-layer-power-btn').css({ color });
        if (value) fetchAllFC();
        sdk.LayerSwitcher.setLayerCheckboxChecked({ name: 'FC Layer', isChecked: value });
    }

    async function initUserPanel() {
        const $panel = $('<div>');
        // Updated to play better with DarkMode
        const $stateSelect = $('<select>', {
            id: 'fcl-state-select',
            class: 'form-control disabled',
            style: `
        border-radius: 4px;
        padding: 6px 12px;
        background-color: var(--background_default); /* Use dark mode background */
        color: var(--content_default); /* Use dark mode content color */
        border: 1px solid var(--separator_default); /* Dark mode border color */
        transition: background-color 0.3s, color 0.3s, border-color 0.3s;
        outline: none;
        cursor: pointer;
        font-weight: bold;
    `
        }).append($('<option>', { value: 'ALL' }).text('All'));

        Object.keys(STATE_SETTINGS).forEach(stateAbbr => {
            if (stateAbbr !== 'global') {
                $stateSelect.append($('<option>', { value: stateAbbr }).text(reverseStatesHash(stateAbbr)));
            }
        });

        $stateSelect.val(settings.activeStateAbbr ? settings.activeStateAbbr : 'ALL');

        const $hideStreet = $('<div>', { id: 'fcl-hide-street-container', class: 'controls-container' })
            .append($('<input>', { type: 'checkbox', name: 'fcl-hide-street', id: 'fcl-hide-street' }).prop('checked', settings.hideStreet).click(onHideStreetsClicked))
            .append($('<label>', { for: 'fcl-hide-street' }).text('Hide local street highlights'));

        $panel.append(
            $('<div>', { class: 'form-group' })
                .append($('<label>', { class: 'control-label' }).text('Select a state'))
                .append($('<div>', { class: 'controls', id: 'fcl-state-select-container' }).append($('<div>').append($stateSelect))),
            $hideStreet,
            $('<div>', { id: 'fcl-table-container' })
        );

        $panel.append(
            $('<div>', {
                class: 'loading-indicator',
                id: 'fc-loading-indicator',
                style: 'margin-top:10px; margin-right:10px; font-weight:bold; color:green; font-size:0.9em;'
            }).html('<span></span>')
        );

        $panel.append($('<div>', { id: 'fcl-state-info' }));

        $panel.append(
            $('<div>', { style: 'margin-top:10px;font-size:10px;color:#999999;' })
                .append($('<div>').text(`version ${scriptVersion}`))
                .append($('<div>').append($('<a>', { href: '#' /* , target:'__blank' */ }).text('Discussion Forum (currently n/a)')))
        );

        const { tabLabel, tabPane } = await sdk.Sidebar.registerScriptTab();
        $(tabLabel).text('FC');
        $(tabPane).append($panel);

        // append the power button
        if (!$('#fc-layer-power-btn').length) {
            const color = settings.layerVisible ? '#00bd00' : '#ccc';
            $(tabLabel).prepend(
                $('<span>', {
                    class: 'fa fa-power-off',
                    id: 'fc-layer-power-btn',
                    style: `margin-right: 5px;cursor: pointer;color: ${color};font-size: 13px;`,
                    title: 'Toggle FC Layer'
                }).click(evt => {
                    evt.stopPropagation();
                    setEnabled(!settings.layerVisible);
                })
            );
        }

        $('#fcl-state-select').change(onStateSelectionChanged);
        loadStateFCInfo();
    }

    function loadStateFCInfo() {
        $('#fcl-state-info').empty();
        if (STATE_SETTINGS[settings.activeStateAbbr]) {
            const stateInfo = STATE_SETTINGS[settings.activeStateAbbr].information;
            const $panelStateInfo = $('<dl>');
            Object.keys(stateInfo).forEach(propertyName => {
                $panelStateInfo.append($('<dt>', { style: 'margin-top:1em;color:#777777' }).text(propertyName)).append($('<dd>').text(stateInfo[propertyName]));
            });
            $('#fcl-state-info').append($panelStateInfo);
        }
    }

    async function initGui() {
        initLayer();
        await initUserPanel();
    }

    async function init() {
        if (debug && Promise.config) {
            Promise.config({
                warnings: true,
                longStackTraces: true,
                cancellation: true,
                monitoring: false
            });
        } else {
            Promise.config({
                warnings: false,
                longStackTraces: false,
                cancellation: true,
                monitoring: false
            });
        }

        const u = sdk.State.getUserInfo();
        rank = u.rank + 1;
        isAM = u.isAreaManager;
        userNameLC = u.userName.toLowerCase();

        loadSettingsFromStorage();
        await initGui();
        fetchAllFC();
        log('Initialized.');
    }

    init();
})();