define([
                                "dojo/_base/declare",
                                "dojo/_base/lang",
                                "dojo/_base/Color",
                                "dojo/Evented",
                                "dojo/on",
                                "dojo/dom",
                                "dojo/dom-style",
                                "dojo/dom-construct",
                                "dojo/dom-class",
                                "dojo/query",
                                "dojo/json",
                                "dojo/NodeList-dom",
                                "dojo/DeferredList",
                                "esri/geometry/Extent",
                                "esri/layers/FeatureLayer",
                                "esri/InfoTemplate",
                                "Hud.Common/ThematicRenderer/ThematicRenderer",
                                "Hud.Affht/Tools/AffhtAjax",
                                "Hud.Affht/Tools/AffhtMap",
                                "Hud.Affht/Sidebar/AffhtSidebar",
                                "Hud.Affht/Tools/AffhtTocController",
                                "dojo/text!./MapSelectorView.html",
                                "xstyle/css!Hud.Affht/MapSelector/MapSelector.css"
                            ],
                            function (
                                declare,
                                lang,
                                Color,
                                Evented,
                                on,
                                dom,
                                domStyle,
                                domConstruct,
                                domClass,
                                query,
                                JSON,
                                nlDom,
                                DeferredList,
                                Extent,
                                FeatureLayer,
                                InfoTemplate,
                                ThematicRenderer,
                                AffhtAjax,
                                AffhtMap,
                                AffhtSidebar,
                                AffhtToc,
                                MapSelectorView) {
                            
                                return declare([Evented], {
                                    //properties
                                    config: null,
                                    map: null,
                                    legend: null,
                                    toc: null,
                                    graphicsLayer: null,
                                    mapData: null,
                                    selectedJurisdiction: null,
                                    selectedRegion: null,
                                    selectedMap: null,
                                    selectedMapName: null,
                                    selectedMapVariation: null,
                                    selectedMapId: null,
                                    selectedFeature: null,
                                    mapDefinition: null,
                                    aoi: "jurisdiction",
                                    regionFields: null,
                                    jurisdictionFields: null,
                                    jurisdictionInfo: null,
                                    defaultDotValue: null,
                                    opacitySliders: [],
                                    regionExtent: null,
                                    useQueryString: null,
                                    showVariationButton: false,
                                    jurisdictionId: null,
                                    mapNumber: null,
                                    toc: null,
                                    fields: null,
                            
                                    /**
                            	     * A class for handling the selection and loading of AFFHT maps. 
                                     *
                                     * @class Affht.MapSelectorController
                                     * @constructor
                            	     */
                                    constructor: function (options) {
                                        this.config = options.config;
                                        this.map = options.map;
                            
                                        this.initialize(options);
                                    },
                            
                                    /**
                                     * @method initialize
                                     * @param {Object} options   
                                     */
                                    initialize: function (options) {
                                        AffhtMap.setConfig(this.config);
                            
                                        var self = this;
                                        var cssClass = "col-sm-6 col-md-3";
                            
                                        //query required datasets
                                        var dQuery = AffhtAjax.getAllStates(self.config.url + "/" + self.config.jurisdictionLayerId);
                                        var dMaps = AffhtAjax.getMapCollection(self.config.mapDataUrl);
                                        var dl = new DeferredList([dQuery, dMaps]);
                                        dl.then(function (resultArray) {
                                            var queryResults = resultArray[0][1];
                                            var mapCollection = self.mapData = resultArray[1][1];
                            
                                            //inject the HTML view
                                            domConstruct.place(MapSelectorView, options.containerId, "last");
                            
                                            //filter unique map types
                                            var mapTiles = [], mapItem = null;
                                            for (var x = 0, length = mapCollection.features.length; x < length; x++) {
                                                var mapItem = mapCollection.features[x];
                                                var _skip = false;
                                                for (var j = 0, _length = mapTiles.length; j < _length; j++) {
                                                    if (mapTiles[j].attributes.MAP_NAME == mapItem.attributes.MAP_NAME) {
                                                        _skip = true;
                                                        break;
                                                    }
                                                }
                                                if (_skip === false) mapTiles.push(mapItem);
                                            }
                                            //processing for arcgis 10.0 and lower
                                            var compareByMapname = function (a, b) {
                                                if (a.attributes.MAP_NAME.match(/(\d+)/g) != null && b.attributes.MAP_NAME.match(/(\d+)/g) != null)
                                                    return (parseInt(a.attributes.MAP_NAME.match(/(\d+)/g)[0]) - parseInt(b.attributes.MAP_NAME.match(/(\d+)/g)[0]));
                                                else
                                                    return (a.attributes.MAP_NAME < b.attributes.MAP_NAME) ? -1 : (a.attributes.MAP_NAME > b.attributes.MAP_NAME) ? 1 : 0;
                                            }
                                            mapTiles.sort(compareByMapname);
                            
                                            //build UI for map selection
                                            var html = "",
                                                mapItem = null;
                                            for (var i = 0, length = mapTiles.length; i < length; i++) {
                                                mapItem = mapTiles[i];
                                                //Pick random dot density graphic TODO: refactor
                                                var imgHtml = "<img src=\"images/dot_sample.png\" />";
                                                if (i > 0 && i < 5) {
                                                    imgHtml = "<img src=\"images/dot_sample" + i + ".png\" />";
                                                }
                                                else if ((i > 4) && (i / 2) < 5) {
                                                    imgHtml = "<img src=\"images/dot_sample" + Math.floor((i / 2)) + ".png\" />";
                                                }
                                                else if ((i > 8) && (i / 4) < 5) {
                                                    imgHtml = "<img src=\"images/dot_sample" + Math.floor((i / 4)) + ".png\" />";
                                                }
                                                //build UI thumbnail
                                                html +=
                                                    "<div class=\"" + cssClass + "\">" +
                                                        "<div class=\"thumbnail\">" +
                                                            "<a class=\"affht-map-item\" href=\"javascript:void(0);\" " +
                                                                "mapname=\"" + mapItem.attributes.MAP_NAME + "\"" +
                                                                "mapid=\"" + mapItem.attributes.MAPID + "\">" +
                                                                imgHtml +
                                                                "<span>" + mapItem.attributes.MAP_NAME + "</span>" +
                                                            "</a>" +
                                                        "</div>" +
                                                    "</div>";
                                            }
                                            domConstruct.place(html, "affht-map-picker-container", "last");
                            
                                            //state picker
                                            html = "";
                                            //processing for arcgis 10.0 and lower
                                            var stateList = [];
                                            for (var i = 0, length = queryResults.features.length; i < length; i++) {
                                                if (stateList.indexOf(queryResults.features[i].attributes.STUSAB) === -1) {
                                                    stateList.push(queryResults.features[i].attributes.STUSAB);
                                                }
                                            }
                                            stateList.sort();
                                            //build and inject UI html
                                            for (var i = 0, length = stateList.length; i < length; i++) {
                                                var state = stateList[i];
                                                html += "<option>" + state + "</option>";
                                            }
                                            domConstruct.place(html, "state-selector-dropdown", "last");
                            
                                            /* EVENT HANDLERS */
                                            //map icon click
                                            $(".affht-map-item").click(function (evt) {
                                                var items = $(".affht-map-item");
                                                for (var i = 0, length = items.length; i < length; i++) {
                                                    $(items[i].parentElement).removeClass("selectedMap");
                                                }
                                                $(evt.currentTarget.parentElement).addClass("selectedMap");
                                                self.selectedMapName = evt.currentTarget.attributes.mapname.value;
                                                self.selectedMapId = evt.currentTarget.attributes.mapid.value;
                                                domStyle.set(dom.byId("map-select-warning"), "display", "none");
                                                domClass.remove("affht-map-picker-container", "bg-danger");
                            
                                            });
                                            //state selection
                                            on(dom.byId("state-selector-dropdown"), "change", function (evt) {
                                                var state = evt.target.options[evt.target.selectedIndex].value;
                            
                                                //must be a valid selection
                                                if (state == "-1") { return };
                                                self.selectedFeature = null;
                            
                                                domClass.remove("step-2-state", "bg-danger");
                                                domStyle.set(dom.byId("mapselector-warning"), "display", "none");
                            
                                                self.buildJurisdictionList(state);
                                            });
                            
                                            //Variation dialog 'Back' button
                                            $("#btn-variation-back").click(function () {
                                                $("#affht-map-picker-container").show();
                                                $("#affht-state-picker-container").hide();
                                                $("#affht-map-picker-dialog").modal("show");
                                                $("#map-variation-dialog").modal("hide");
                                                $("#btn-map-picker-map").hide();
                                                $("#btn-map-picker-load").show();
                                            });
                                            //'Choose a map' button on grantee form
                                            $("#btn-map-picker-map").click(function () {
                                                //validate state input
                                                if (dom.byId("state-selector-dropdown").selectedIndex == 0) {
                                                    domClass.add("step-2-state", "bg-danger");
                            
                                                    domStyle.set(dom.byId("mapselector-warning"), "display", "block");
                                                    return;
                                                }
                                                //validate jurisdiction input
                                                if (self.selectedFeature === null) {
                                                    domClass.add("step-3-jurisdiction", "bg-danger");
                                                    domStyle.set(dom.byId("mapselector-warning"), "display", "block");
                                                    return;
                                                }
                            
                                                //hide the grantee panel
                                                $("#affht-state-picker-container").hide();
                            
                                                //toggle the back/next buttons
                                                $("#btn-map-picker-map").hide();
                                                $("#btn-map-picker-grantee").show();
                            
                                                //show the load button
                                                $("#btn-map-picker-load").show();
                            
                                                //show the map picker panel
                                                $("#affht-map-picker-container").show();
                                                $("#div-chosemap").show();                   
                            
                                                //reset the map picker validation warning
                                                domStyle.set(dom.byId("mapselector-warning"), "display", "none");
                                            });
                                            //'Back' button on map thumbnails form
                                            $("#btn-map-picker-grantee").click(function () {
                                                //hide the map picker panel
                                                $("#affht-map-picker-container").hide();
                                                $("#div-chosemap").hide();
                            
                                                //toggle the next/back button visibility
                                                $("#btn-map-picker-map").show();
                                                $("#btn-map-picker-grantee").hide();
                            
                                                //determine the visibility of the load button
                                                if (self.selectedMapName != null) {
                                                    $("#btn-map-picker-load").show();
                                                }
                                                else {
                                                    $("#btn-map-picker-load").hide();
                                                }
                            
                                                //show the grantee panel
                                                $("#affht-state-picker-container").show();
                            
                                                //hide the required field warnings
                                                domStyle.set(dom.byId("map-select-warning"), "display", "none");
                                                domClass.remove("affht-map-picker-container", "bg-danger");
                                            });
                                            // 'Load AFFHT Map' button on Select Map Variation modal
                                            on(dom.byId("btn-process-map-variation"), "click", function () {
                                                //Ensure user has selected a map variation
                                                if (self.selectedMapVariation == "") {
                                                    domClass.add("map-variation-modal-body", "bg-danger");
                                                    domStyle.set(dom.byId("variationselect-warning"), "display", "block");
                                                    return;
                                                }
                            
                                                var mapFeature;
                                                for (var i = 0, l = self.mapData.features.length; i < l; i++) {
                                                    if (self.selectedMapVariation == self.mapData.features[i].attributes.MAP_NUMBER) {
                                                        mapFeature = self.mapData.features[i];
                                                        self.selectedMap = mapFeature
                                                        break;
                                                    }
                                                }
                                                self.loadMap();
                                                // Display 'Map Variation' button in left-panel
                                                domStyle.set("btn-map-variation", "display", "block");
                                                // Hide modal
                                                $("#map-variation-dialog").modal("hide");
                                            });
                            
                                            $("#btn-map-picker-load").click(function (evt) {
                                                self.useQueryString = false;
                            
                                                //assign aoi values
                                                if (dom.byId("state-selector-dropdown").selectedIndex == 0) {
                                                    domClass.add("step-2-state", "bg-danger");
                            
                                                    domStyle.set(dom.byId("mapselector-warning"), "display", "block");
                                                    return;
                                                }
                            
                                                if (self.selectedMapName == null) {
                                                    domClass.add("affht-map-picker-container", "bg-danger");
                            
                                                    domStyle.set(dom.byId("map-select-warning"), "display", "block");
                                                    return;
                                                }
                                                if (self.selectedFeature === null) {
                                                    domClass.add("step-3-jurisdiction", "bg-danger");
                                                    domStyle.set(dom.byId("mapselector-warning"), "display", "block");
                                                    return;
                                                }
                            
                                                if (dom.byId("affht-aoi-option1").checked === true) { self.aoi = "jurisdiction"; }
                                                else { self.aoi = "region"; }
                            
                                                self.processMapSelection();
                                                $("#affht-map-picker-dialog").modal("hide");
                                            });
                            
                                            $("#jslabel").click(function (evt) {
                                                var reg = document.getElementById("reglabel");
                                                reg.setAttribute("style", "background:#fff;color:#000");
                            
                                                var js = document.getElementById("jslabel");
                                                js.setAttribute("style", "background:#063D6B;color:white")
                                            });
                            
                                            $("#reglabel").click(function (evt) {
                                                var reg = document.getElementById("reglabel");
                                                reg.setAttribute("style", "background:#063D6B;color:white");
                            
                                                var js = document.getElementById("jslabel");
                                                js.setAttribute("style", "background:#fff;color:#000")
                                            });
                            
                                            //on modal close
                                            $("#affht-map-picker-dialog").on("hidden.bs.modal", function (evt) {
                                                $("#affht-toolbar-nav").show();
                                                $(".esriSimpleSlider").show();
                                            });
                            
                                            self.emit("map-selector-loaded", {});
                                        });
                                    },
                            
                                    /**
                                    * Triggers the MapSelector to load a map from outside input (as opposed to the MapSelector GUI).
                                    * @method loadMapFromInput
                                    * 
                                    * @param {Object} mapInfo
                                    */
                                    loadMapFromInput: function (mapInfo) {
                                        var self = this;
                            
                                        //set web map if passed in
                                        if (mapInfo.mapJson) {
                                            self.mapDefinition = mapInfo.mapJson;
                                        }
                            
                                        //get map definition from collection by map number
                                        var mapFeature;
                                        for (var i = 0, l = self.mapData.features.length; i < l; i++) {
                                            if (self.mapData.features[i].attributes.MAP_NUMBER == mapInfo.mapNumber) {
                                                mapFeature = self.mapData.features[i];
                                                break;
                                            }
                                        }
                                        //validate qMapNumber
                                        if (mapFeature) {
                                            self.selectedMap = mapFeature;
                                            self.selectedMapName = mapFeature.attributes.MAP_NAME;
                                        }
                                        else {
                                            //TODO: show dialog stating the map number is invalid and the app will load normally.
                                            alert('bad map number');
                                            return;
                                        }
                            
                                        //evaluate zoom toogle
                                        if (mapInfo.zoomLevel && mapInfo.zoomLevel == "2") {
                                            self.aoi = "region";
                                        }
                                        else { self.aoi = "jurisdiction"; }
                            
                                        //set map selector properties so it opens preset to the load parameters
                                        var d = AffhtMap.queryJurisdictionById(mapInfo.jurisdictionId, true);
                                        d.then(function (results) {
                                            //set selected jurisdiction
                                            AffhtMap.setSelectedJurisdiction(results.features[0]);
                                            //set map selector inputs to selected jurisdiction
                                            document.getElementById("state-selector-dropdown").value = results.features[0].attributes.STUSAB;
                                            self.buildJurisdictionList(results.features[0].attributes.STUSAB);
                                            //set local map selector properties
                                            var jurisdictionInfo = {
                                                featureId: results.features[0].attributes.OBJECTID,
                                                cbsaId: results.features[0].attributes.CBSA_CODE
                                            };
                                            self.jurisdictionInfo = jurisdictionInfo;
                                            self.selectedFeature = results.features[0];
                            
                                            var _d = AffhtMap.queryRegionById(jurisdictionInfo.cbsaId);
                                            _d.then(function (regionResults) {
                                                //set memory to returned region
                                                AffhtMap.setSelectedRegion(regionResults.features);
                                                //populate the MapPicker UI label
                                                dom.byId("affht-map-region").innerHTML = regionResults.features[0].attributes.CBSA_NAME;
                                                //process map for variations
                                                self.processMapSelection(true);
                                                //load map from defintion
                                                self.loadMap();
                                            });
                                        });
                                    },
                            
                                    /**
                                    * Shows the map selector GUI form.
                                    * @method show
                                    */
                                    show: function () {
                                        //reset back/next buttons
                                        $("#btn-map-picker-map").show();
                                        $("#btn-map-picker-grantee").hide();
                            
                                        //determine the visibility of the load button
                                        if (this.selectedMap) {
                                            $("#btn-map-picker-load").show();
                                        }
                                        else {
                                            $("#btn-map-picker-load").hide();
                                        }
                            
                                        //hide the map picker panel
                                        $("#affht-map-picker-container").hide();
                                        $("#div-chosemap").hide();
                            
                                        //show the grantee picker panel
                                        $("#affht-state-picker-container").show();
                            
                                        //show the dialog
                                        $("#affht-map-picker-dialog").modal("show");
                                    },
                            
                                    /**
                                    * Hides the map selector GUI form.
                                    * @method hide
                                    */
                                    hide: function () {
                                        $("#affht-map-picker-container").hide();
                                        $("#affht-state-picker-container").hide();
                                        $("#affht-map-picker-dialog").modal("hide");
                                    },
                            
                                    /*
                                    * Shows the dialog for the map variation picker.
                                    * @method showVariationDialog
                                    */
                                    showVariationDialog: function() {
                                        $("#map-variation-dialog").modal("show");
                                        domStyle.set("btn-variation-close", "display", "block");
                                        $("#btn-variation-back").hide();
                                    },
                            
                                    /**
                                    * Constructs the UI pick list from the results of the jurisdiction query.
                                    * @method buildJurisdictionList
                                    * @param {String} state
                                    */
                                    buildJurisdictionList: function (state) {
                                        var self = this;
                            
                                        //show loading indicator
                                        domConstruct.place("<img src=\"images/loader-default.gif\" alt=\"loading...\" />", "affht-jurisdiction-container", "only");
                            
                                        var d = AffhtMap.queryJurisdictionsByState(state);
                                        d.then(function (results) {
                                            //processing for arcgis 10.0 and lower
                                            var compareByFeaturename = function (a, b) {
                                                if (a.attributes.NAME.match(/(\d+)/g) != null && b.attributes.NAME.match(/(\d+)/g) != null)
                                                    return (parseInt(a.attributes.NAME.match(/(\d+)/g)[0]) - parseInt(b.attributes.NAME.match(/(\d+)/g)[0]));
                                                else
                                                    return (a.attributes.NAME < b.attributes.NAME) ? -1 : (a.attributes.NAME > b.attributes.NAME) ? 1 : 0;
                                            }
                                            results.features.sort(compareByFeaturename);
                            
                                            var feature, html = "<div class=\"list-group\">";
                                            for (var i = 0, length = results.features.length; i < length; i++) {
                                                feature = results.features[i];
                                                html +=
                                                    "<a href=\"#\" cbsaCode=\"" + feature.attributes.CBSAID + "\" " +
                                                        "featureId=\"" + feature.attributes.UOGID + "\" " +
                                                        "objectId=\"" + feature.attributes.OBJECTID + "\" " +
                                                        "class=\"list-group-item affht-jurisdiction\">" +
                                                            feature.attributes.NAME +
                                                            " (" + feature.attributes.GRANTEE_CATEGORY + ")" +
                                                    "</a>";
                                            }
                            
                                            html += "</div>";
                                            domConstruct.place(html, "affht-jurisdiction-container", "only");
                            
                                            //wire up selection event
                                            var nl = query(".affht-jurisdiction");
                                            nl.on("click", function (evt) {
                                                nl.removeClass("active");
                                                domClass.add(evt.target, "active");
                            
                                                var featureId = evt.target.attributes.objectid.value;
                                                for (var i = 0, l = self.features.length; i < l; i++) {
                                                    if (featureId == self.features[i].attributes.OBJECTID) {
                                                        self.selectedFeature = self.features[i];
                                                        break;
                                                    }
                                                }
                            
                                                $("#affht-map-scope").bootstrapSwitch("disabled", false);
                            
                                                domClass.remove("step-3-jurisdiction", "bg-danger");
                                                domStyle.set(dom.byId("mapselector-warning"), "display", "none");
                            
                                                //Get the associated region
                                                var jurisdictionInfo = {
                                                    featureId: evt.target.attributes.featureId.value,
                                                    cbsaId: evt.target.attributes.cbsaCode.value
                                                };
                                                self.jurisdictionInfo = jurisdictionInfo;
                                                var rd = AffhtMap.queryRegionById(jurisdictionInfo.cbsaId);
                                                rd.then(function (results) {
                                                    //populate the MapPicker UI label
                                                    dom.byId("affht-map-region").innerHTML = results.features[0].attributes.CBSA_NAME;
                                                    //set memory to returned region
                                                    AffhtMap.setSelectedRegion(results.features);
                                                });
                            
                                                //call existing function to get jurisdiction geometry
                                                var jd = AffhtMap.queryJurisdictionById(self.selectedFeature.attributes.OBJECTID);
                                                jd.then(function (results) {
                                                    AffhtMap.setSelectedJurisdiction(results.features[0]);
                                                });
                                            });
                            
                                            self.features = results.features;
                                        });
                                    },
                            
                                    /**
                                    * Toggles the application area of interest between the jurisdiction and region of the selected grantee.
                                    * @method toggleAoi
                                    * @param {Deferred} d
                                    */
                                    toggleAoi: function () {
                                        var self = this;
                            
                                        var dotLayer, dotValue, dotSize, dotShape;
                                        var layerIds = this.map.layerIds;
                                        for (var i = 0, length = layerIds.length; i < length; i++) {
                                            var layer = this.map.getLayer(layerIds[i]);
                                            if (layer.id.indexOf("dot-density") > -1) {
                                                dotLayer = layer;
                                                dotValue = layer.renderer.dotValue;
                                                dotSize = layer.renderer.dotSize;
                                                dotShape = layer.renderer.dotShape;
                                                break;
                                            }
                                        }
                                        if (this.aoi === "region") {
                                            this.aoi = "jurisdiction";
                                            //zoom to jurisdiction
                                            AffhtMap.zoomToJurisdiction();
                                            AffhtMap.drawJurisdiction();
                            
                                            //change dot density to jurisdiction renderer
                                            dotLayer.setRenderer(AffhtMap.createDotDensityRenderer(dotValue, self.jurisdictionFields, dotSize, dotShape));
                                            layer.redraw();
                            
                                            var _d = AffhtMap.renderLegend();
                                            _d.then(function () { self.renderToc(); });
                                            //update map information
                                            dom.byId("affht-map-aoi-info").innerHTML =
                                                self.selectedFeature.attributes.NAME + " " +
                                                " (" + self.selectedFeature.attributes.GRANTEE_CATEGORY + ")";
                                        }
                                        else {
                                            this.aoi = "region";
                                            //zoom to region
                                            AffhtMap.zoomToRegion();
                                            AffhtMap.drawRegion();
                            
                                            //change dot density to region renderer, if region renderer fields exist
                                            if (self.regionFields) {
                                                dotLayer.setRenderer(AffhtMap.createDotDensityRenderer(dotValue, self.regionFields, dotSize, dotShape));
                                                layer.redraw();
                                            }
                            
                                            var _d = AffhtMap.renderLegend();
                                            _d.then(function () { self.renderToc(); });
                                            //update map informaton
                                            dom.byId("affht-map-aoi-info").innerHTML = AffhtMap.getSelectedRegion()[0].attributes.CBSA_NAME + " CBSA";
                                        }
                                    },
                            
                                    /**
                                    * Builds the Table of Contents (TOC) based on the current state of the map.
                                    * @method renderToc
                                    */
                                    renderToc: function () {
                                        //clear the toc
                                        dom.byId("affht-sidebar-toc").innerHTML = "";
                            
                                        this.toc = new AffhtToc({
                                            containid: "affht-sidebar-toc",
                                            map: this.map
                                        });
                                    },
                            
                                    /**
                                    * Pre-processes the map selection to validate inputs and determine if a map variation choice is needed.
                                    * @method processMapSelection
                                    */
                                    processMapSelection: function (hideDialog) {
                                        var self = this;
                            
                                        self.map.showLoadingIndicator("Loading...");
                            
                                        //find related map variations
                                        var mapAttributes = null,
                                            mapVariations = [];
                                        for (var i = 0, length = self.mapData.features.length; i < length; i++) {
                                            if (self.selectedMapName == self.mapData.features[i].attributes.MAP_NAME) {
                                                mapVariations.push(self.mapData.features[i]);
                                            }
                                        }
                            
                                        //reset variation property
                                        self.selectedMapVariation = null;
                            
                                        if (mapVariations.length > 1) {
                                            //build variation picker             
                                            var html = "";
                                            var htmlDropdown = "";
                                            for (var i = 0, _l = mapVariations.length; i < _l; i++) {
                                                html +=
                                                    "<a href=\"#\" " +
                                                    "class=\"list-group-item map-variation-option-list\" " +
                                                    "mapnumber=\"" + mapVariations[i].attributes.MAP_NUMBER +
                                                    "\" mapvariationname=\"" + mapVariations[i].attributes.MAP_VAR_NAME + "\">" +
                                                    mapVariations[i].attributes.MAP_VAR_NAME + "</a>";
                                                htmlDropdown +=
                                                    "<li><a href=\"#\" " +
                                                    "class=\"map-variation-option-list-li\" " +
                                                    "mapnumber=\"" + mapVariations[i].attributes.MAP_NUMBER +
                                                    "\" mapvariationname=\"" + mapVariations[i].attributes.MAP_VAR_NAME + "\">" +
                                                    mapVariations[i].attributes.MAP_VAR_NAME + "</a></li>";
                                            }
                                            domConstruct.place(html, "map-variation-option-container", "only");
                                            domConstruct.place(htmlDropdown, "ul-variation", "only");
                            
                                            // Map variation selected via modal
                                            var nl = query(".map-variation-option-list");
                                            nl.on("click", function (e) {
                                                //remove warning from the dialog
                                                domClass.remove("map-variation-modal-body", "bg-danger");
                                                domStyle.set(dom.byId("variationselect-warning"), "display", "none");
                                                nl.removeClass("active");
                                                domClass.add(e.target, "active");
                            
                                                self.selectedMapVariation = e.target.attributes.mapnumber.value;
                                                // Update RightPanel map variation info
                                                dom.byId("affht-map-variation-info").innerHTML = e.target.attributes.mapvariationname.value;
                                            });
                            
                                            // Map variation selected via 'Map Variations' button on map
                                            var _nl = query(".map-variation-option-list-li");
                                            _nl.on("click", function (e) {
                                                self.selectedMapVariation = e.target.attributes.mapnumber.value;
                                                // Update RightPanel map variation info
                                                dom.byId("affht-map-variation-info").innerHTML = e.target.attributes.mapvariationname.value;
                            
                                                // Get/set the selected map variation
                                                var mapFeature;
                                                for (var i = 0, l = self.mapData.features.length; i < l; i++) {
                                                    if (self.selectedMapVariation == self.mapData.features[i].attributes.MAP_NUMBER) {
                                                        mapFeature = self.mapData.features[i];
                                                        self.selectedMap = mapFeature
                                                        break;
                                                    }
                                                }
                                                // Load the map variation
                                                self.loadMap();
                                            });
                            
                                            //show variation picker unless loaded from query string
                                            if (!hideDialog) { $("#map-variation-dialog").modal("show"); }
                                            else {
                                                //set UI display text/labels
                                                dom.byId("affht-map-variation-info").innerHTML = self.selectedMap.attributes.MAP_VAR_NAME;
                                                self.selectedMapVariation = self.selectedMap.attributes.MAP_NUMBER;
                                            }
                            
                                            //show the variation button on the map UI
                                            self.showVariationButton = true;
                                        }
                                        else {
                                            //no variations - hide map button
                                            self.showVariationButton = false;
                                            //set the selected map and load
                                            if (!hideDialog) {
                                                self.selectedMap = mapVariations[0];
                                                self.loadMap();
                                            }
                                        }
                                    },
                            
                                    /**
                                    * Builds the AFFHT web map based on the user input.
                                    * @method loadMap
                                    */
                                    loadMap: function () {
                                        var self = this;
                            
                                        //set the selected map object to memory
                                        var mapFeature = self.selectedMap;
                                        AffhtMap.setSelectedAffhtMap(mapFeature);
                            
                                        //emit event for map loading
                                        self.emit("map-loading", {
                                            mapRecord: mapFeature.attributes,
                                            jurisdictionId: self.jurisdictionInfo.featureId,
                                            regionId: self.jurisdictionInfo.cbsaId
                                        });
                            
                                        //enable/disable, show/hide map variation buttons 
                                        if (self.showVariationButton === true) {
                                            //Map
                                            $("#btn-variation").removeClass("disabled");
                                            //LeftPanel
                                            domStyle.set("btn-map-variation", "display", "block");
                                        }
                                        else {
                                            //Map
                                            $("#btn-variation").addClass("disabled");
                                            //LeftPanel
                                            domStyle.set("btn-map-variation", "display", "none");
                                        }
                            
                                        //clear memory for last map
                                        self.jurisdictionFields = null;
                                        self.regionFields = null;
                                        self.defaultDotValue = null;
                            
                                        //hide legend while it is updated
                                        domStyle.set("affht-sidebar-legend", "display", "none");
                            
                                        //get map definiton
                                        var mapDef = JSON.parse(mapFeature.attributes.MAP_DEF);
                                        if (self.mapDefinition) { mapDef = JSON.parse(self.mapDefinition); }
                            
                                        //if a dot density layer, then store renderer properties in memory
                                        for (var i = 0; i < mapDef.itemData.operationalLayers.length; i++) {
                                            var a = mapDef.itemData.operationalLayers[i].layerDefinition.drawingInfo.renderer.type;
                                            if (a == "dotDensity") {
                                                self.jurisdictionFields = mapDef.itemData.operationalLayers[i].layerDefinition.drawingInfo.renderer.fields;
                                                self.defaultDotValue = mapDef.itemData.operationalLayers[i].layerDefinition.drawingInfo.renderer.dotValue;
                                                break;
                                            }
                                        }
                                        //if map defintion has regional dot density renderer, then store in memory
                                        if (mapDef.options) {
                                            if (mapDef.options.regionFields) self.regionFields = mapDef.options.regionFields;
                                            if (self.regionFields) {
                                                for (var x = 0, _fl = self.regionFields.length; x < _fl; x++) {
                                                    self.regionFields[x].color = new Color(self.regionFields[x].color);
                                                }
                                            }
                                        }
                            
                                        self.map.destroy();
                            
                                        //var mapControl = new MapController(options);
                                        //var d = mapControl.initializeMap();
                                        var d = AffhtMap.loadMap(mapDef, "mapDiv");
                                        d.then(function (map) {
                                            self.map = map,
                                            graphicsLayer = AffhtMap.getGraphicsLayer();
                            
                                            //make the affht maps menu close button available (only hidden on first use)
                                            domClass.remove('btn-affht-maps-close', 'hidden');
                            
                                            //add the existing graphics layer to the newly created map
                                            graphicsLayer.clear();
                                            self.map.addLayer(graphicsLayer);
                            
                                            //initialize map popups
                                            self.setLayerPopups();
                                            self.setThematicLayers();
                            
                                            //update dot density adjustor control
                                            //set dot density scale dependency and other properties
                                            var layerIds = self.map.layerIds, dotValue = null;
                                            for (var i = 0, length = layerIds.length; i < length; i++) {
                                                if (layerIds[i].indexOf("dot-density") > -1) {
                                                    //get the layer
                                                    var layer = self.map.getLayer(layerIds[i]);
                                                    //set scale dependencies
                                                    layer.setMinScale(self.config.minScale);
                                                    layer.setMaxScale(self.config.maxScale);
                                                    //set dot value reference
                                                    dotValue = layer.renderer.dotValue;
                                                    //set special layer properties
                                                    layer._isDotDensity = true;
                                                    self.dotDensityFieldsMaster = lang.clone(layer.renderer.fields);
                                                    self.dotDensityFields = lang.clone(layer.renderer.fields);
                                                    layer._dotDensityTocCallback = function (fieldName, visible) {
                                                        var field;
                                                        if (visible === true) {
                                                            for (var j = 0, len = self.dotDensityFieldsMaster.length; j < len; j++) {
                                                                if (self.dotDensityFieldsMaster[j].name === fieldName) {
                                                                    field = lang.clone(self.dotDensityFieldsMaster[j]);
                                                                    break;
                                                                }
                                                            }
                                                            self.dotDensityFields.push(field);
                                                        }
                                                        else {
                                                            for (var j = 0, len = self.dotDensityFields.length; j < len; j++) {
                                                                if (self.dotDensityFields[j].name === fieldName) {
                                                                    field = self.dotDensityFields[j];
                                                                    break;
                                                                }
                                                            }
                                                            self.dotDensityFields.splice(self.dotDensityFields.indexOf(field), 1);
                                                        }
                                                        layer.setRenderer(AffhtMap.createDotDensityRenderer(layer.renderer.dotValue, self.dotDensityFields, layer.renderer.dotSize, layer.renderer.dotShape));
                                                        layer.redraw();
                                                        AffhtMap.renderLegend();
                                                        self.emit("map-updated", {
                                                            map: self.map,
                                                            fields: self.dotDensityFields
                                                        });
                                                    }
                                                    break;
                                                }
                                            }
                            
                                            self.emit("map-loaded", {
                                                map: map,
                                                mapRecord: mapFeature.attributes,
                                                jurisdictionId: self.jurisdictionInfo.featureId,
                                                fields: self.dotDensityFieldsMaster,
                                                regionId: self.jurisdictionInfo.cbsaId
                                            });
                            
                                            if (self.aoi === "jurisdiction") {
                                                var z = AffhtMap.zoomToJurisdiction();
                                                AffhtMap.drawJurisdiction();
                                                z.then(function () {
                                                    var d = AffhtMap.renderLegend();
                                                    d.then(function () { self.renderToc(); });
                                                });
                                            }
                                            else {
                                                var sRegion = AffhtMap.getSelectedRegion();
                                                if (!sRegion) {
                                                    var qr = AffhtMap.queryRegionById(self.jurisdictionInfo.cbsaId);
                                                    qr.then(function (results) {
                                                        AffhtMap.setSelectedRegion(results);
                                                        AffhtMap.drawRegion();
                                                        AffhtMap.zoomToRegion();
                                                    })
                                                }
                                                else { AffhtMap.zoomToRegion(); AffhtMap.drawRegion(); }
                                                //render legend
                                                var d = AffhtMap.renderLegend();
                                                d.then(function () { self.renderToc(); });
                                            }
                            
                                            self.mapNumber = mapFeature.attributes.MAP_NUMBER.toString();
                                            self.jurisdictionId = self.jurisdictionInfo.featureId;
                            
                                            //change title for AOI
                                            var title = "";
                                            if (self.aoi.toLowerCase() === "jurisdiction") {
                                                title = self.selectedFeature.attributes.NAME + " " +
                                                " (" + self.selectedFeature.attributes.GRANTEE_CATEGORY + ")";
                                            }
                                            else {
                                                title = AffhtMap.getSelectedRegion()[0].attributes.CBSA_NAME + " CBSA";
                                            }
                                            dom.byId("affht-map-aoi-info").innerHTML = "<strong>" + title + "</strong>";
                                            dom.byId("affht-map-name-info").innerHTML = mapFeature.attributes.MAP_NAME;
                                            if (self.selectedMapVariation) {
                                                domStyle.set("tr-map-variation", "display", "");
                                            }
                                            else {
                                                domStyle.set("tr-map-variation", "display", "none");
                                            }
                            
                                            dom.byId("affht-map-desc-info").innerHTML = mapFeature.attributes.MAP_DESC;
                                            dom.byId("affht-jurisdiction-info").innerHTML =
                                                self.selectedFeature.attributes.NAME + " " +
                                                " (" + self.selectedFeature.attributes.GRANTEE_CATEGORY + ")";
                                            dom.byId("affht-region-info").innerHTML = AffhtMap.getSelectedRegion()[0].attributes.CBSA_NAME;
                            
                                            if (dotValue) {
                                                AffhtSidebar.showDotDensitySelect();
                                                AffhtSidebar.refreshDotDensityTools(dotValue);
                                            }
                                            else {
                                                AffhtSidebar.hideDotDensitySelect();
                                            }
                            
                                            //change renderer for AOI - map always loads jurisdiction renderer fields by default
                                            if (self.aoi.toLowerCase() == "region") {
                                                if (self.regionFields) { //if no region fields, then region uses same renderer fields as jurisdiction
                                                    var dotLayer;
                                                    for (var i = 0, length = self.map.layerIds.length; i < length; i++) {
                                                        if (self.map.layerIds[i].indexOf("dot-density") > -1) {
                                                            dotLayer = self.map.getLayer(self.map.layerIds[i]);
                                                            break;
                                                        }
                                                    }
                            
                                                    dotLayer.setRenderer(AffhtMap.createDotDensityRenderer(self.defaultDotValue, self.regionFields, dotLayer.renderer.dotSize, dotLayer.renderer.dotShape));
                                                    dotLayer.redraw();
                                                }
                                            }
                                        });
                                    },
                            
                                    /**
                                    * Calculates and applies a ClassBreaks renderer for the layers specified by configuration.
                                    * @method setThematicLayers
                                    */
                                    setThematicLayers: function () {
                                        var mapNumber = this.selectedMap.attributes.MAP_NUMBER.toString();
                            
                                        var feature = AffhtMap.getSelectedRegion()[0];
                                        var regionExtent = feature.geometry.getExtent();
                            
                                        for (var i = 0; i < this.config.thematicMaps.length; i++) {
                                            var thematicConfig = this.config.thematicMaps[i];
                            
                                            if (thematicConfig.mapNumber == mapNumber) {
                                                for (var x=0,l=thematicConfig.layers.length; x < l; x++) {
                                                    var layer = this.map.getLayer(thematicConfig.layers[x].id);
                                                    if (layer) {
                                                        layer.setVisibility(false);
                                                        var d = ThematicRenderer.updateClassBreaksByExtent(layer,
                                                            layer.renderer.attributeField,
                                                            thematicConfig.layers[x].breakCount,
                                                            regionExtent,
                                                            thematicConfig.layers[x].format,
                                                            this.config.thematicRendererUrl);
                                                        d.then(function (renderer) {
                                                            layer.setRenderer(renderer);
                                                            ThematicRenderer.setDescendingBreaks(layer);
                                                            layer.show();
                                                        });
                                                    }
                                                }
                                            }
                                        }
                                    },
                            
                                    /**
                                    * Sets the popup content for the layers specified by configuration.
                                    * @method setLayerPopups
                                    */
                                    setLayerPopups: function () {
                                        var self = this;
                            
                                        for (var i = 0; i < self.config.popupConfig.length; i++) {
                                            var infoLayers = self.config.popupConfig[i].layers;
                                            for (var j = 0; j < infoLayers.length; j++) {
                            
                                                var layerid = infoLayers[j].id,
                                                    infoLayer = self.map.getLayer(layerid),
                                                    fields = infoLayers[j].fields,
                                                    conditionalFieldGroups = infoLayers[j].conditionalFieldGroups,
                                                    infoTemplate = new InfoTemplate();
                                                if (infoLayer == null) {
                                                    return;
                                                }
                                                infoTemplate.setTitle(" ");
                                                infoTemplate.setContent(function getWindowContent(graphic) {
                                                    var templayer = graphic.getLayer(),
                                                        infoHtml = "";
                            
                                                    infoHtml =
                                                       "<div class='esriViewPopup'><div class='mainSection'>" +
                                                           "<div class='header'>" + templayer.name + "</div>" +
                                                           "<div class='hzLine'></div>" +
                                                           "<div>" +
                                                               "<table class='attrTable' cellpadding='0px' cellspacing='0px'>" +
                                                                   "<tbody>";
                            
                                                    for (var fieldindex = 0; fieldindex < fields.length; fieldindex++) {
                                                        infoHtml +=
                                                           "<tr valign='top'>" +
                                                               "<td class='attrName'>" + fields[fieldindex].alias + "</td>" +
                                                               "<td class='attrValue'>" +
                                                                   "<span class='esriStringValue'>" + graphic.attributes[fields[fieldindex].fieldname] + "</span>" +
                                                               "</td>" +
                                                           "</tr>";
                                                    }
                            
                                                    for (var c = 0, cl = conditionalFieldGroups.length; c < cl; c++) {
                                                        var condition = conditionalFieldGroups[c];
                                                        //build condition boolean
                                                        var conditional =
                                                            eval(graphic.attributes[condition.conditionField] + " " + condition.operator + " '" + condition.conditionValue + "'");
                            
                                                        //build input
                                                        for (var m = 0, fl = condition.fields.length; m < fl; m++) {
                                                            var strVal = "";
                                                            if (conditional === true) {
                                                                if (graphic.attributes[condition.fields[m].fieldname] !== null) {
                                                                    strVal = graphic.attributes[condition.fields[m].fieldname].toFixed(2).toString() + "%";
                                                                }
                                                                else {
                                                                    strVal = graphic.attributes[condition.fields[m].fieldname];
                                                                }
                                                            }
                                                            else {
                                                                strVal = "null";
                                                            }
                            
                                                            infoHtml +=
                                                              "<tr valign='top'>" +
                                                                  "<td class='attrName'>" + condition.fields[m].alias + "</td>" +
                                                                  "<td class='attrValue'>" +
                                                                      "<span class='esriStringValue'>" +
                                                                        strVal +
                                                                      "</span>" +
                                                                  "</td>" +
                                                              "</tr>";
                                                        }
                            
                                                    }
                            
                                                    infoHtml += "</tbody></table></div></div></div>";
                                                    return infoHtml;
                                                });
                                                infoLayer.setInfoTemplate(infoTemplate);
                                            }
                                        }
                                    },
                            
                                    resetForm: function (option) {
                                        $("#affht-map-picker-dialog").modal("show");
                                        $("#btn-map-picker-load").show();
                            
                                        if (option === "grantee") {
                                            $("#btn-map-picker-map").show();
                                            $("#btn-map-picker-grantee").hide();
                                            $("#affht-map-picker-container").hide();
                                            $("#affht-state-picker-container").show();
                                            $("#div-chosemap").hide();
                                        }
                                        else {
                                            $("#btn-map-picker-map").hide();
                                            $("#btn-map-picker-grantee").show();
                                            $("#affht-map-picker-container").show();
                                            $("#affht-state-picker-container").hide();
                                            $("#div-chosemap").show();
                                        }
                                    }
                                });
                            });