define([
                                "dojo/_base/declare",
                                "dojo/dom",
                                "dojo/on",
                                "dojo/query",
                                "dojo/dom-construct",
                                "dojo/NodeList-dom",
                                "dojo/Deferred",
                                "dojo/DeferredList",
                                "esri/tasks/locator",
                                "esri/geometry/Extent",
                                "dojo/text!./LocationSearchResultsView.html",
                                "dojo/text!./LocationSearchToolbarView.html",
                                "xstyle/css!Hud.Common/LocationSearchTool/LocationSearch.css"
                            ],
                            function (
                                declare,
                                dom,
                                on,
                                query,
                                domConstruct,
                                nlDom,
                                Deferred,
                                DeferredList,
                                Locator,
                                Extent,
                                LocationSearchResultsView,
                                LocationSearchToolbarView) {
                            
                                return declare(null, {
                                    //properties
                                    map: null,
                                    locator: null,
                                    resultStore: null,
                            
                                    /**
                                    * Constructs a new LocationSearchController class.
                                    * A user interface control that generates a location search tool.
                                    *
                                    * @class Common.LocationSearchController
                                    * @constructor
                                    */
                                    constructor: function (options) {
                                        this.map = options.map;
                            
                                        this.initialize(options);
                                    },
                            
                                    /**
                                      * Initializes a new LocationSearch menu.
                                      * @method initialize
                                      * @param {Object} options   
                                      */
                                    initialize: function (options) {
                                        var self = this;
                            
                                        domConstruct.place(LocationSearchToolbarView, options.toolbarContainerId, "first");
                                        domConstruct.place(LocationSearchResultsView, options.pageContainerId, "last");
                            
                                        //initialize esri locator
                                        var geocoderUrl = (options.geocoderUrl ? options.geocoderUrl : "https://geocode.arcgis.com/arcgis/rest/services/World/GeocodeServer");
                                        self.locator = new Locator(geocoderUrl);
                                        self.locator.outSpatialReference = self.map.spatialReference;
                            
                                        //bind click event
                                        on(dojo.byId("txt-search-input"), "keyup", function (e) {
                                            if (e.keyCode == 13) {
                                                self.processSearch();
                                            }
                                        });
                                        on(dojo.byId("btn-search-location"), "click", function (evt) {
                                            self.processSearch();
                                        });
                                    },
                                    /**
                                     * Returns location results and locates the selected POI on the map.
                                     * @method processSearch
                                     */
                                    processSearch: function () {
                                        var self = this;
                            
                                        var searchStr = dom.byId("txt-search-input").value;
                                        var a = { "singleLine": searchStr };
                                        var p = { address: a };
                                        var d = self.locator.addressToLocations(p);
                                        d.then(function (results) {
                                            dom.byId("txt-search-input").value = "";
                                            self.resultStore = results;
                            
                                            var result, html = "<div class=\"list-group\">";
                                            for (var i = 0, length = results.length; i < length; i++) {
                                                result = results[i];
                                                html += "<a href=\"#\" class=\"list-group-item ls-result-list\" itemIndex=\"" + i + "\">" + result.address + "</a>";
                                            }
                                            html += "</div>";
                                            domConstruct.place(html, "location-result-container", "only");
                            
                                            var nl = query(".ls-result-list");
                                            nl.on("click", function (e) {
                                                var itemIndex = e.target.attributes.itemindex.value;
                                                var location = self.resultStore[itemIndex];
                            
                                                if (location.extent) {
                                                    var extent = new Extent(
                                                        location.extent.xmin,
                                                        location.extent.ymin,
                                                        location.extent.xmax,
                                                        location.extent.ymax,
                                                        self.map.spatialReference);
                                                    self.map.setExtent(extent);
                                                }
                                                else {
                                                    self.map.centerAndZoom(location.location, 10);
                                                }
                                                $("#location-search-results-dialog").modal("hide");
                                            });
                                        });
                                        $("#location-search-results-dialog").modal("show");
                                    },
                            
                                    /**
                                     * Sets the placeholder text in the text input control.
                                     * @method setPlaceholderText
                                     * @param {string} text A string to inject into the text input's placeholder attribute.
                                     */
                                    setPlaceholderText: function (text) {
                                        if (text && typeof text === "string") {
                                            document.getElementById("txt-search-input").placeholder = text;
                                        }
                                    }
                                });
                            });