 //if(esri.version && (esri.version == 1.2 || esri.version == 1.3)) {
 //   fix for http://forums.esri.com/Thread.asp?c=158&f=2396&t=276110&mc=5#msgid855271

(function() {
  var d = dojo;
  if(dojo.isIE) {
    dojo._setOpacity = function(/*DomNode*/node, /*Number*/opacity){
      if(opacity == 1){
        var filterRE = /FILTER:[^;]*;?/i;
        node.style.cssText = node.style.cssText.replace(filterRE, "");
        if(node.nodeName.toLowerCase() == "tr"){
          d.query("> td", node).forEach(function(i){
            i.style.cssText = i.style.cssText.replace(filterRE, "");
          });
        }
      }else{
        var o = "Alpha(Opacity="+ opacity * 100 +")";
        node.style.filter = o;
      }
      if(node.nodeName.toLowerCase() == "tr"){
        d.query("> td", node).forEach(function(i){
          i.style.filter = o;
        });
      }
      return opacity;
    };
  }
})();

// }


dojo.require("esri.map");
dojo.require("esri.tasks.query");
dojo.require("dijit.Dialog");
dojo.require("dijit.form.Button");
dojo.require("dojo.parser");
dojo.require("dijit.TitlePane");
dojo.require("dojox.layout.FloatingPane");

var __g_map_app__ = null;

//begin Util.js
Number.prototype.round = function(numberOfDecimals) {
    var temp=this;
    temp=Math.round(temp*Math.pow(10,numberOfDecimals))/Math.pow(10,numberOfDecimals);
    return temp;
}

dojo.provide("mdot.mapping.framework.Util");
dojo.mixin(mdot.mapping.framework.Util, {
    ajaxRequest: function(requestUrl, successHandler, errorHandler){
        dojo.xhrGet( {
            url: requestUrl,
            handleAs: "json",
            mimetype: "application/json",
            headers:null,
            load: function(response, ioArgs) {
                successHandler(response);
            },
            error: function(response, ioArgs) {
                if(errorHandler) {
                    errorHandler(response);
                }
                else {
                    var msg = '';
                    for(var prop in response) {
                        msg += prop + ": " + response[prop] + "\n";
                    }
                    //alert('TODO - determine what to do with error in JSON request...:\n' + requestUrl + '\n' + msg);
                    alert('TODO - determine what to do with error in JSON request...:\n' + requestUrl + '\n' + response);
                }
            }
        });
    },
    processAjaxRequest: function(url, successHandler, errorHandler){
        dojo.xhrGet( {
            url: url,
            handleAs: "json",
            mimetype: "application/json; charset=utf-8",
            load: function(response, ioArgs) {
                successHandler(response);
            },
            error: function(response, ioArgs) {
                if(errorHandler) {
                    errorHandler(response);
                }
                else {
                    var msg = '';
                    for(var prop in response) {
                        msg += prop + ": " + response[prop] + "\n";
                    }
                    //alert('TODO - determine what to do with error in JSON request...:\n' + requestUrl + '\n' + msg);
                    alert('TODO - determine what to do with error in JSON request...:\n' + requestUrl + '\n' + response);
                }
            }
        });
    },    
    pointToEnvelope: function(point, buffer, map) {
        var upperLeft = map.toScreen(point);
        var lowerRight = map.toScreen(point);
        
        upperLeft.x -= buffer;
        upperLeft.y -= buffer;
        lowerRight.x += buffer;
        lowerRight.y += buffer;
        
        upperLeft = map.toMap(upperLeft);
        lowerRight = map.toMap(lowerRight);
        
        var extent = new esri.geometry.Extent(upperLeft.x, upperLeft.y, lowerRight.x, lowerRight.y, map.spatialReference);
        return extent;
    },
    toScreen: function(geometry, map) {
        var outGeometry = null;
        switch(geometry.type) {
            case 'extent':
                var ul = new esri.geometry.Point(geometry.xmin, geometry.ymax, map.spatialReference);
                var lr = new esri.geometry.Point(geometry.xmax, geometry.ymin, map.spatialReference);
                ul = map.toScreen(ul);
                lr = map.toScreen(lr);
                outGeometry = new esri.geometry.Extent(ul.x, lr.y, lr.x, ul.y, map.spatialReference);
                break;
            case 'point':
                outGeometry = map.toScreen(geometry);
                break;
        }
        return outGeometry;
    },
    replaceAll: function(str, searchStr, replaceStr) {
        return str ? str.split(searchStr).join(replaceStr) : str;
    },
    scrubString: function(searchStr, value, str) {
        return this.replaceAll(str, '${' + searchStr + '}', value);
    },
    scrubFeatures: function(features, template) {
        var str = '';
        var bRecordNumber = template.indexOf('${__recordNumber}') > -1 && index != null;
        for(var index = 0; index < features.length; index++) {
            var temp = this.scrub(features[index].attributes, template);
            if(bRecordNumber) {
                temp = this.scrubString('__recordNumber', index, temp);
            }
            str += temp;
        }
        return str;
    },
    scrubFeature: function(feature, template, index) {
        var str = '';
        var temp = this.scrub(feature.attributes, template);
        var bRecordNumber = template.indexOf('${__recordNumber}') > -1 && index != null;
        if(bRecordNumber) {
            temp = this.scrubString('__recordNumber', index, temp);
        }
        str += temp;
        return str;
    },
    scrub: function(object, str) {
        var returnStr = str;
        for(var prop in object) {
            returnStr = this.scrubString(prop, object[prop], returnStr);
        }
        return returnStr;
    },
    left: function(str, searchStr) {
        var index = str.indexOf(searchStr);
        if(index < 0) {
            return str;
        }
        else {
            return str.substring(0, index);
        }
    },
    right: function(str, searchStr) {
        var index = str.indexOf(searchStr);
        if(index < 0) {
            return str;
        }
        else {
            return str.substring(index + 1);
        }        
    },
    getString: function(str, defaultStr) {
        return str ? str : defaultStr;
    },
    getData: function(data, defaultData) {
        return(typeof(data) == "undefined" || data == null) ? defaultData : data;
    },
    getExtent: function(features) {
        var extent = null;
        
        for(var index = 0; index < features.length; index++) {
            try {
                var featureExtent = null;
                if(features[index].geometry.type == 'point') {
                    featureExtent = new esri.geometry.Extent(features[index].geometry.x, features[index].geometry.y, features[index].geometry.x, features[index].geometry.y, null);
                }
                else {
                    featureExtent = features[index].geometry.getExtent();
                }
    
                if(extent == null) {
                    extent = featureExtent;
                }
                else {
                    extent = extent.union(featureExtent);
                }
            }
            catch(e) {
            
            }
        }
        
        if(extent != null && features.length > 0 && features[0].geometry != null) {
            extent.spatialReference = features[0].geometry.spatialReference;
        }
        
        return extent;
    },
    getResultSetExtent: function(features, map, scale) {
        var extent = this.getExtent(features);
        if(extent != null) {
            if(extent.getWidth() == 0 || extent.getHeight() == 0) {
                if(scale) {
                    extent = this.getExtentFromScale(extent.getCenter(), map, scale);
                }
            }
            else {
                extent.spatialReference = map.spatialReference;
            }
        }
        return extent;
    },
    getExtentFromScale: function(center, map, scale) {
        //TODO - This method is expecting that the map units are in meters and that the DPI is 96...
        var pixelsPerMeter = 39.3700787 * 96;
        var deltaX = ((scale * map.width)/pixelsPerMeter)/2;
        var deltaY = ((scale * map.height)/pixelsPerMeter)/2;
        var minx = center.x - deltaX;
        var maxx = center.x + deltaX;
        var miny = center.y - deltaY;
        var maxy = center.y + deltaY;
        var extent = new esri.geometry.Extent(minx, miny, maxx, maxy, map.spatialReference);
        return extent;
    },
    getExtentFromScale2: function(center, mapWidth, mapHeight, scale) {
        //TODO - This method is expecting that the map units are in meters and that the DPI is 96...
        var pixelsPerMeter = 39.3700787 * 96;
        var deltaX = ((scale * mapWidth)/pixelsPerMeter)/2;
        var deltaY = ((scale * mapHeight)/pixelsPerMeter)/2;
        var minx = center.x - deltaX;
        var maxx = center.x + deltaX;
        var miny = center.y - deltaY;
        var maxy = center.y + deltaY;
        var extent = new esri.geometry.Extent(minx, miny, maxx, maxy);
        return extent;
    },
    getScale: function(extent, width, height) {
        var extentWidth = extent.getWidth();
        var extentHeight = extent.getHeight();
        if(extentWidth > extentHeight) {
            return this.getScaleX(extent, width);
        }
        else {
            return this.getScaleY(extent, height);
        }
    },
    getScaleX: function(extent, width) {
        //TODO - This method is expecting that the map units are in meters and that the DPI is 96...
        var pixelsPerMeter = 39.3700787 * 96;
        var x = extent.getWidth();
        return (x * pixelsPerMeter) / width;
    },
    getScaleY: function(extent, height) {
        //TODO - This method is expecting that the map units are in meters and that the DPI is 96...
        var pixelsPerMeter = 39.3700787 * 96;
        var y = extent.getHeight();
        return (y * pixelsPerMeter) / height;
    },
    getDistance: function(p1, p2) {
        return Math.sqrt(Math.pow(p1.x - p2.x, 2) + Math.pow(p1.y - p2.y, 2));
    },
    getCenter: function(geometry) {
        switch(geometry.type) {
            case 'point':
                return geometry;
                break;
            case 'polyline':
                if(!geometry.paths.length) {
                    return null;
                }
                
                var length = 0;
                
                //TODO - this function works on a single part only (if the polyline is multi-part)
                var polyline = geometry.paths[0];
                
                //get the total length of the polyline
                for(var index = 0; index < polyline.length - 1; index++) {
                    var p1 = geometry.getPoint(0, index);
                    var p2 = geometry.getPoint(0, index + 1);
                    var segmentLength = this.getDistance(p1, p2);
                    length += segmentLength;
                }
                
                //now find the points that contain half of the total length
                length /= 2;
                var distance = 0;
                for(var index = 0; index < polyline.length - 1; index++) {
                    var p1 = geometry.getPoint(0, index);
                    var p2 = geometry.getPoint(0, index + 1);
                    var segmentDistance = this.getDistance(p1, p2);
                    
                    if(distance + segmentDistance >= length) {
                        var k = (length - distance)/segmentDistance;
                        var x = p1.x + ((p2.x - p1.x) * k);
                        var y = p1.y + ((p2.y - p1.y) * k);
                        return new esri.geometry.Point(x, y, geometry.spatialReference);
                    }
                    else {
                        distance += segmentDistance;
                    }
                }
                
                break;
            default:
                alert(this.declaredClass + '.getCenter: Unsupported geometry type: ' + geometry.type);
                return null;
        }
    },
    setExtent: function(features, map, scale) {
        var extent = this.getExtent(features);
        if(extent != null) {
            if(extent.getWidth() == 0 || extent.getHeight() == 0) {
                if(scale) {
                    extent = this.getExtentFromScale(extent.getCenter(), map, scale);
                    map.setExtent(extent);
                }
                else {
                    map.centerAt(extent.getCenter());
                }
            }
            else {
                extent = extent.expand(1.25);
                extent.spatialReference = map.spatialReference;
                map.setExtent(extent);
            }
        }
    },
    /**
     * Brute force method to apply a style to a node.
     * This function will return a style object at the first occurence of the input styleName.
     */
    applyStyle: function(node, styleName) {
        var style = null;
        for(var index = 0; index < document.styleSheets.length; index++) {
            style = this.findStyle(document.styleSheets[index]);
            if(style != null) {
                break;
            }
        }
        
        if(style != null) {
            //TODO - go through all of the attributes in the style...
        }
    },
    findStyle: function(styleSheet, styleName) {
        var style = null;
        var tempStyleName = (styleName.indexOf('.') == 0) ? styleName : ('.' + styleName);
        for(var index = 0; index < styleSheet.cssRules.length; index++) {
            switch(styleSheet.cssRules[index].type) {
                case 1: //CSSStyleRule
                    if(styleSheet.cssRules[index].selectorText == tempStyleName) {
                        style = styleSheet.cssRules[index].style;
                        break;
                    }
                    break;
                case 3: //CSSImportRule
                    style = this.findStyle(styleSheet.cssRules[index].styleSheet, styleName);
                    break;
            }
        }
        return style;
    },
    getRequestData: function() {
        var params = new Array();
        var queryString = unescape(location.search.substring(1,location.search.length));
    
        queryString = queryString.replace(/\+/g, ' ');
	    var args = queryString.split('&');
	
	    for (var index = 0; index <args.length; index++) {
	        var index2 = args[index].indexOf('=');
	        if(index2 < 0) {
	            continue;
	        }
	        
	        var name = args[index].substring(0, index2);
	        var value = args[index].substring(index2 + 1);
	        params[name] = value;
	    }
        return params;
    },
    getRequestDataKeysLower: function() {
        var params = new Array();
        var queryString = unescape(location.search.substring(1,location.search.length));
    
        queryString = queryString.replace(/\+/g, ' ');
	    var args = queryString.split('&');
	
	    for (var index = 0; index <args.length; index++) {
            var index2 = args[index].indexOf('=');
	        if(index2 < 0) {
	            continue;
	        }
	        
	        var name = args[index].substring(0, index2).toLowerCase();
	        var value = args[index].substring(index2 + 1);
	        params[name] = value;
	    }
        return params;
    },
    getRequestDataKeysUpper: function() {
        var params = new Array();
        var queryString = unescape(location.search.substring(1,location.search.length));
    
        queryString = queryString.replace(/\+/g, ' ');
	    var args = queryString.split('&');
	
	    for (var index = 0; index <args.length; index++) {
            var index2 = args[index].indexOf('=');
	        if(index2 < 0) {
	            continue;
	        }
	        
	        var name = args[index].substring(0, index2).toUpperCase();
	        var value = args[index].substring(index2 + 1);
	        params[name] = value;
	    }
        return params;
    },
    contains: function(extent, geometry) {
        var bContains = false;
        switch(geometry.type) {
            case "point":
                bContains = extent.contains(geometry);
                break;
            case "polyline":
                for(var index = 0; index < geometry.paths.length; index++) {
                    var path = geometry.paths[index];
                    for(var index2 = 0; index2 < path.length; index2++) {
                        var point = geometry.getPoint(index, index2);
                        if(extent.contains(point)) {
                            bContains = true;
                            break;
                        }
                    }
                }
                break;
            case "polygon":
                for(var index = 0; index < geometry.rings.length; index++) {
                    var ring = geometry.rings[index];
                    for(var index2 = 0; index2 < ring.length; index2++) {
                        var point = geometry.getPoint(index, index2);
                        if(extent.contains(point)) {
                            bContains = true;
                            break;
                        }
                    }                    
                }
                break;
        }
        return bContains;
    },
    trim: function(str) {
        return str.replace(/^\s+|\s+$/g,"");
    },
    getStyleValue: function(className, attributeName, defaultValue) {
        //document.styleSheets[1].cssRules[0].selectorText  *|div.findDialogContainer
        //document.styleSheets[1].cssRules[0].cssText       *|div.findDialogContainer { overflow: scroll; width: auto; height: auto; }
        var attributeNameLower = attributeName.toLowerCase();
        var styleValue = this.getData(defaultValue, "");
        var bShowedMessage = false;
        var bIsIE = dojo.isIE > 0;
        try {
            for(var index = 0; index < document.styleSheets.length; index++) {
                var rules = null;
                try {
                    rules = bIsIE ? document.styleSheets[index].rules : document.styleSheets[index].cssRules;
                }
                catch(ex) {
                    //FireFox 3.1 throws a security error for imported style sheets...
                    continue;
                }
                
                if(!rules) {
                    continue;
                }
                for(var index2 = 0; index2 < rules.length; index2++) {
                    if(!bIsIE) {
                        if(rules[index2].type == 3) {
                            //import... TODO grab rule's stylesheet...
                            //document.styleSheets[index].cssRules[index2].styleSheet
                        }
                        if(rules[index2].type != 1) {
                            continue;
                        }
                    }
                    
                    var bFoundStyle = false;
                    var selectorText = rules[index2].selectorText;
                    
                    if(bIsIE) {
                        bFoundStyle = selectorText.toLowerCase() == className.toLowerCase();
                    }
                    else {
                        if(!bIsIE && className.indexOf('.') > -1) {
                            //i.e. div.findDialogContainer --> *|div.findDialogContainer
                            bFoundStyle = selectorText == ('*|' + className) || selectorText.toLowerCase() == className.toLowerCase();
                        }
                        else {
                            //i.e. findDialogContainer --> *|.findDialogContainer
                            bFoundStyle = selectorText == ('*|.' + className) || selectorText.toLowerCase() == className.toLowerCase();
                        }
                    }
                    
                    if(bFoundStyle) {
                        var cssText = bIsIE ? rules[index2].style.cssText : rules[index2].cssText;
                        var leftIndex = cssText.indexOf('{');
                        var rightIndex = cssText.indexOf('}');
                        var style = '';
                        if(leftIndex < 0 || rightIndex < 0) {
                            style = this.trim(cssText);
                        }
                        else {
                            style = this.trim(cssText.substring(leftIndex + 1, rightIndex));
                        }
                        var styles = style.split(';');
                        for(var index3 = 0; index3 < styles.length; index3++) {
                            var cssStyle = styles[index3].split(':');
                            if(cssStyle.length != 2) {
                                continue;
                            }
                            if(this.trim(cssStyle[0]).toLowerCase() == attributeNameLower) {
                                return this.trim(cssStyle[1]);
                            }
                        }
                        //failed to find attribute...
                        return styleValue;
                    }
                }
            }
        }
        catch(ex) {
            var msg = '';
            for(var prop in ex) {
                msg += prop + ': ' + ex[prop];
            }
            alert('Exception in getStyleValue: ' + msg);
            
        }
        return styleValue;
    },
    toEsriGeometry: function(shape, defaultSpatialReference) {
        if(!shape || !shape.type) {
            return null;
        }
        
        //TODO - finish this method...
        
        var spatialReference = defaultSpatialReference;
        if(shape.spatialReference) {
            spatialReference.wkid = shape.spatialReference;
        }
        
        var geometry = null;
        switch(shape.type) {
            case "point":
                geometry = new esri.geometry.Point(shape.x, shape.y, spatialReference);
                break;
            case "polyline":
                geometry = new esri.geometry.Polyline(defaultSpatialReference);
                for(var index = 0; index < shape.paths.length; index++) {
                    var points = [];
                    for(var pointIndex = 0; pointIndex < shape.paths[index].points.length; pointIndex++) {
                        var point = shape.paths[index].points[pointIndex];
                        points[points.length] = new esri.geometry.Point(point.x, point.y);
                    }
                    geometry.addPath(points);
                }
                break;
        }
        return geometry;
    },
    encode: function(input/*string*/) {
        var keyStr = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
        
        var output = "";
        var chr1, chr2, chr3 = "";
        var enc1, enc2, enc3, enc4 = "";
        var i = 0;

        do {
            chr1 = input.charCodeAt(i++);
            chr2 = input.charCodeAt(i++);
            chr3 = input.charCodeAt(i++);

            enc1 = chr1 >> 2;
            enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
            enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
            enc4 = chr3 & 63;

            if (isNaN(chr2)) {
                enc3 = enc4 = 64;
             } else if (isNaN(chr3)) {
                enc4 = 64;
            }

            output = output +
                keyStr.charAt(enc1) +
                keyStr.charAt(enc2) +
                keyStr.charAt(enc3) +
                keyStr.charAt(enc4);
            chr1 = chr2 = chr3 = "";
            enc1 = enc2 = enc3 = enc4 = "";
        } while (i < input.length);

        return output;
    },
    decode: function(input) {
        var keyStr = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
        var output = "";
        var chr1, chr2, chr3 = "";
        var enc1, enc2, enc3, enc4 = "";
        var i = 0;

        // remove all characters that are not A-Z, a-z, 0-9, +, /, or =
        var base64test = /[^A-Za-z0-9\+\/\=]/g;
        if (base64test.exec(input)) {
             alert("There were invalid base64 characters in the input text.\n" +
                   "Valid base64 characters are A-Z, a-z, 0-9, ?, ?, and ?\n" +
                   "Expect errors in decoding.");
        }
        input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");

        do {
            enc1 = keyStr.indexOf(input.charAt(i++));
            var bEnc2 = i < input.length;
            enc2 = keyStr.indexOf(input.charAt(i++));
            var bEnc3 = i < input.length;
            enc3 = keyStr.indexOf(input.charAt(i++));
            var bEnc4 = i < input.length;
            enc4 = keyStr.indexOf(input.charAt(i++));

            chr1 = (enc1 << 2) | (enc2 >> 4);
            chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
            chr3 = ((enc3 & 3) << 6) | enc4;
            
            if(i >= input.length - 10) {
                var temp = 10;
            }

            output = output + String.fromCharCode(chr1);

            if (bEnc3 && enc3 != 64) {
                output = output + String.fromCharCode(chr2);
            }
            if (bEnc4 && enc4 != 64) {
                output = output + String.fromCharCode(chr3);
            }

            chr1 = chr2 = chr3 = "";
            enc1 = enc2 = enc3 = enc4 = "";

        } while (i < input.length);

        return output;
    },
    copyToClipboard: function(data, copySource) {
        copySource.value = data;
        if(copySource.createTextRange) {
            var range = copySource.createTextRange();
            if(range) {
                range.execCommand('Copy');
            }
        }
    }/*,
    getMapService: function(mapServiceConfig, onMapServiceLoadedHandler) {
        var esriMapServiceLayer = null;
        if(mapServiceConfig.mapServiceType == mapServiceType.mapServiceTypeTiled) {
            esriMapServiceLayer = new esri.layers.ArcGISTiledMapServiceLayer(mapServiceConfig.url, {
                id:mapServiceConfig.name,
                visible:mapServiceConfig.visible,
                opacity:mapServiceConfig.opacity ? mapServiceConfig.opacity : 1.0
            });
            onMapServiceLoadedHandler(esriMapServiceLayer);
        }
        else {
            esriMapServiceLayer = new esri.layers.ArcGISDynamicMapServiceLayer(mapServiceConfig.url, {
                id:mapServiceConfig.name,
                visible:mapServiceConfig.visible,
                opacity:mapServiceConfig.opacity ? mapServiceConfig.opacity : 1.0
            }); 
            
            if(!esriMapServiceLayer.loaded) { //IE workaround...
                var ref = this;
                dojo.connect(esriMapServiceLayer, "onLoad", function(layer) {                    
                    esriMapServiceLayer = layer;
                    onMapServiceLoadedHandler(esriMapServiceLayer);
                });
            }
            else {
                onMapServiceLoadedHandler(esriMapServiceLayer);
            }
        }
    }*/
});
//end Util.js

//begin enumerations
function mapServiceType(){}
mapServiceType.mapServiceTypeTiled = 0;
mapServiceType.mapServiceTypeDynamic = 1;
mapServiceType.mapServiceTypeRaster = 2;

function toolAction() {}
toolAction.toolActionNone = -1;
toolAction.toolActionPoint = 0;
toolAction.toolActionEnvelope = 1;
toolAction.toolActionPolyline = 2;
toolAction.toolActionPolygon = 3;

function fieldType(){}
fieldType.fieldTypeString = 0;
fieldType.fieldTypeNumber = 1;
fieldType.fieldTypeDate = 2;
fieldType.fieldTypeGeometry = 3;

function resultSetDisplayType() {}
resultSetDisplayType.resultSetDisplayTypeNone = 0;
resultSetDisplayType.resultSetDisplayTypeList = 1;
resultSetDisplayType.resultSetDisplayTypeInfoWindow = 2;
resultSetDisplayType.resultSetDisplayTypeAccordian = 3;
resultSetDisplayType.resultSetDisplayTypeTab = 4;

function selectionDisplayType(){}
selectionDisplayType.selectionDisplayTypeNone = 0;
selectionDisplayType.selectionDisplayTypeSingleFeature = 1;
selectionDisplayType.selectionDisplayTypeAllFeatures = 2;

function zoomToSelectionType(){}
zoomToSelectionType.zoomToSelectionTypeNone = 0; 
zoomToSelectionType.zoomToSelectionTypeSingle = 1;
zoomToSelectionType.zoomToSelectionTypeAll = 2;
zoomToSelectionType.zoomToSelectionTypeBoth = 3;

function layerGroupType(){}
layerGroupType.layerGroupTypeSingle = 0;
layerGroupType.layerGroupTypeMultiple = 1;

function buttonType() {}    
buttonType.buttonTypeDefault = 0;   //standard button type, button with an image
buttonType.buttonTypeSimple = 1;    //simple Dojo button with no image
buttonType.buttonTypeDropDown = 2;  //Dojo drop down button
//end enumerations

//begin MapApplication.js
dojo.declare("mdot.mapping.framework.MapApplication", null,
{
    constructor: function(mapApplicationOptions) {
        this.mapDivId = mapApplicationOptions.mapDivId;
        this.mapApplicationOptions = mapApplicationOptions;
        this.mapApplicationConfig = null;         //Rest Object from Server
        this.map = null;                    //esri.Map
        this.mapServices = new Array();     //mdot.mapping.framework.MapService
        this.currentTool = null;
        this.lastTool = null;
        this.toolbar = new mdot.mapping.framework.Toolbar(this);
        this.toolEventListeners = new Array();
        this.layers = new Array();
        this.overviewMap = null;
        this.currentMapRequests = new Array();
        this.initialSliderLocation = null;
        this.initialExtent = null;
        
        if(!this.mapDivId) {
            throw new Exception("mapDivId is required!");
        }
        
        this.customDataSources = [];
        this.printService = mapApplicationOptions.mapConfig.printService;
        this.uploadService = null;
        
        this.esri12 = esri.version && esri.version >= 1.2;
        this.loadingImage = null;
        if(mapApplicationOptions.mapConfig.loadingImage) {
            this.loadingImageUrl = mapApplicationOptions.mapConfig.loadingImage.url;
            this.loadingImageWidth = mapApplicationOptions.mapConfig.loadingImage.width;
            this.loadingImageHeight = mapApplicationOptions.mapConfig.loadingImage.height;
        }
        else {
            this.loadingImageUrl = "";
            this.loadingImageWidth = 0;
            this.loadingImageHeight = 0;
        }
        this.loadedLayers = [];
        this.layersToLoad = [];
        
        this.scrubConfig(mapApplicationOptions);
        if(mapApplicationOptions.mapConfig.uploadManager) {
            this.uploadService = new mdot.mapping.framework.UploadManager(
                mapApplicationOptions.mapConfig.uploadManager.transactionInitUrl,
                mapApplicationOptions.mapConfig.uploadManager.uploadUrl
            );
        }
        
        var ref = this;
        ref.afterPreload(mapApplicationOptions);
    },
    scrubConfig: function(mapApplicationOptions) {
        if(!mapApplicationOptions.mapConfig) {
            throw "mapConfig in mapApplicationOptions is required!";
        }
        
        var mapConfig = mapApplicationOptions.mapConfig;
        if((!mapConfig.mapServices || !mapConfig.mapServices.length) && mapApplicationOptions.mapServicesConfig && dojo.isObject(mapApplicationOptions.mapServicesConfig)) {
            mapConfig.mapServices = mapApplicationOptions.mapServicesConfig;
        }
        
        if(mapConfig.mapServiceNames && mapConfig.mapServices) {
            //remove the unwanted map services...
            var mapServices = [];
            for(var index = 0; index < mapConfig.mapServiceNames.length; index++) {
                for(var index2 = 0; index2 < mapConfig.mapServices.length; index2++) {
                    if(mapConfig.mapServiceNames[index].name == mapConfig.mapServices[index2].name) {
                        mapServices[mapServices.length] = mapConfig.mapServices[index2];
                        mapServices[mapServices.length-1].visible = mapConfig.mapServiceNames[index].visible;
                        if(mapConfig.mapServiceNames[index].layers && mapServices[mapServices.length-1].mapServiceType == mapServiceType.mapServiceTypeDynamic){
                            //remove unwanted map service layers...
                            var mapServiceLayers = [];
                            for(var index3 = 0; index3 < mapConfig.mapServiceNames[index].layers.length; index3++) {
                                for(var index4 = 0; index4 < mapServices[mapServices.length-1].layers.length; index4++) {
                                    if(mapConfig.mapServiceNames[index].layers[index3].name == mapServices[mapServices.length-1].layers[index4].name) {
                                        mapServiceLayers[mapServiceLayers.length] = mapServices[mapServices.length-1].layers[index4];
                                        mapServiceLayers[mapServiceLayers.length - 1].visible = mapConfig.mapServiceNames[index].layers[index3].visible;
                                    }
                                }
                            }
                            mapServices[mapServices.length-1].layers = mapServiceLayers;
                        }
                    }
                }
            }
            mapConfig.mapServices = mapServices;
        }
        
        if(mapConfig.identifyOptionLayers && mapConfig.identifyOptions) {
            //remove the unwanted map identify options...
            var identifyOptions = [];
            for(var index = 0; index < mapConfig.identifyOptionLayers.length; index++) {
                for(var index2 = 0; index2 < mapConfig.identifyOptions.length; index2++) {
                    if(mapConfig.identifyOptionLayers[index] == mapConfig.identifyOptions[index2].layerName) {
                        identifyOptions[identifyOptions.length] = mapConfig.identifyOptions[index2];
                    }
                }
            }
            mapConfig.identifyOptions = identifyOptions;
        }
    },
    afterPreload: function(mapApplicationOptions) {        
        this.mapApplicationConfig = mapApplicationOptions.mapConfig;
        
        if(this.mapApplicationConfig.stylesheets) {
            var head = document.getElementsByTagName("head")[0];
            for(var index = 0; index < this.mapApplicationConfig.stylesheets.length; index++) {
                var cssNode = document.createElement('link');
                cssNode.type = 'text/css';
                cssNode.rel = 'stylesheet';
                cssNode.href = this.mapApplicationConfig.stylesheets[index];
                cssNode.media = 'screen';
                head.appendChild(cssNode);
            }
        }
        
        var useSlider = !mdot.mapping.framework.Util.getData(this.mapApplicationConfig.hideSlider, false); //kind of funky logic due to terminology
        if(this.mapApplicationConfig.initialExtent != null) {
            this.initialExtent = new esri.geometry.Extent(this.mapApplicationConfig.initialExtent.minx,
                                                          this.mapApplicationConfig.initialExtent.miny,
                                                          this.mapApplicationConfig.initialExtent.maxx,
                                                          this.mapApplicationConfig.initialExtent.maxy,
                                                          new esri.SpatialReference({wkid:26919}));
                this.map = new esri.Map(this.mapDivId,{displayGraphicsOnPan:! dojo.isIE, extent: this.initialExtent,slider:useSlider,nav:false}); 
        }
        else {
                this.map = new esri.Map(this.mapDivId,{displayGraphicsOnPan:! dojo.isIE, slider:useSlider,nav:false});
        }
        
        var ref = this;
        
        if(this.esri12) {
            this.loadingImage = document.createElement('img');
            this.loadingImage.src = this.loadingImageUrl;
            this.loadingImage.style.display = "none";
            this.loadingImage.style.zIndex = 20002;
            this.loadingImage.style.position = "absolute";
            this.loadingImage.style.width = this.loadingImageWidth;
            this.loadingImage.style.height = this.loadingImageHeight;
            this.getMapContainer().appendChild(this.loadingImage);
        }
        
        if(this.mapApplicationConfig.statusDialog) {
            this.mapApplicationConfig.statusDialog.maxProgressBarValue = this.mapApplicationConfig.mapServices.length;
            this.statusDialog = new mdot.mapping.framework.StatusDialog(this, this.mapApplicationConfig.statusDialog);
        }
        
        this.loadLayer(0);
    },
    loadLayer: function(index) {
        var ref = this;
        if(index < this.mapApplicationConfig.mapServices.length) {
            if(this.statusDialog) {
                this.statusDialog.setMessage("Loading " + this.mapApplicationConfig.mapServices[index].label);
            }
            
            var mdotMapService = new mdot.mapping.framework.MapService(this, 
                this.mapApplicationConfig.mapServices[index],
                function(layer, mapService) {
                    ref.map.addLayer(layer);
                    
                    if(mapService.mdotMapService.mapServiceType == mapServiceType.mapServiceTypeDynamic || mapService.mdotMapService.mapServiceType == mapServiceType.mapServiceTypeRaster) {
                        if(ref.esri12) {
                            ref.layersToLoad[layer.id] = true;
                            
                            dojo.connect(layer, "show", function() {
                                ref.showLoadingImage();
                            });
                            
                            dojo.connect(layer, "onUpdate", function() {
                                ref.hideLoadingImage(this); //this points to layer...
                            });
                        }
                    }
                    
                    ref.mapServices[ref.mapServices.length] = mapService;   
                    if(ref.statusDialog) {
                        ref.statusDialog.incrementProgressBar();
                    }
                    ref.loadLayer(index + 1);
                }
            );
        }
        else {
            this.onMapApplicationLoaded();
        }
    },
    onMapApplicationLoaded: function() {
        var ref = this;
        
        if(this.initialExtent) {
            //this will take care of the zoom levels
            this.setExtent2(this.initialExtent);
        }
        
        if(this.esri12) {
            dojo.connect(this.map, "onLoad", function() {
                ref.showLoadingImage();
            });
            dojo.connect(this.map, "onZoomStart", function() {
                ref.showLoadingImage();
            });
            dojo.connect(this.map, "onPanStart", function() {
                ref.showLoadingImage();
            });
        }
        
        if(this.map._slider) {
            this.initialSliderLocation = this.map._slider.domNode.getBoundingClientRect();
        }
        
        __g_map_app__ = ref;
        if(window.parent && window.parent.beforeMapApplicationLoaded) {
            window.parent.beforeMapApplicationLoaded(mapApplicationOptions);
        }
        
        if(window.opener && window.opener.beforeMapApplicationLoaded) {
            window.opener.beforeMapApplicationLoaded(mapApplicationOptions);
        }
        
        if(window.beforeMapApplicationLoaded) {
            window.beforeMapApplicationLoaded(mapApplicationOptions);
        }
        
        if(this.mapApplicationConfig.selectionSet) {
            mdot.mapping.framework.ResultSetDisplay.getInstance().defaultDisplayHandler(this.map, this.mapApplicationConfig.selectionSet);
        }
    
        if(this.statusDialog) {
            this.statusDialog.kill();
            this.statusDialog = null;
        }
        
        if(this.mapApplicationConfig.graphics) {
            for(var index = 0; index < this.mapApplicationConfig.graphics.length; index++) {
                var graphic = new esri.Graphic(this.mapApplicationConfig.graphics[index]);
                this.map.graphics.add(graphic);
            }            
        }
        
        if(this.mapApplicationConfig.overviewMap) {
            this.overviewMap = new mdot.mapping.framework.OverviewMap(this, this.mapApplicationConfig.overviewMap);
        }
        
        if(this.mapApplicationConfig.tocOptions) {
            this.tocControl = new mdot.mapping.framework.TocControl(this, this.mapApplicationConfig.tocOptions);
        }
        
        if(this.toolbar != null) {
            dojo.connect(this.map, "onClick", function(evt) {
                ref.onMapClick(evt);
            });
            this.toolbar.load();
        }
        
        if(this.mapApplicationConfig.activeTool && this.toolbar != null) {
            var tool = this.toolbar.findToolbarItem(this.mapApplicationConfig.activeTool);
            this.setCurrentTool(tool);
        }
        
        dojo.connect(window, "onresize", function() {
            ref.dock();
        });
        
        for(var index = 0; index < ref.mapServices.length; index++) {
            var mapService = ref.mapServices[index];
            if(mapService.hasVisibleLayer() && !mapService.esriMapServiceLayer.visible) {
                var layerNames = mapService.getVisibleLayerNames();
                try {
                    ref.setVisibleLayers(layerNames, null);
                }
                catch(e) {
                }
            }
        }
        
        this.map.reposition();
        this.map.resize();
        
        //If the map is loaded in an iframe or in a popup window, then the parent/opener window
        //can gain access to this map application by defining a function named "onMapApplicationLoaded"
        if(window.parent && window.parent != window && window.parent.onMapApplicationLoaded) {
            window.parent.onMapApplicationLoaded(this);
        }
        
        if(window.opener && window.opener.onMapApplicationLoaded) {
            window.opener.onMapApplicationLoaded(this);
        }
        
        if(window.onMapApplicationLoaded) {
            window.onMapApplicationLoaded(this);
        }
        
        this.dock();
    },
    showLoadingImage: function() {
        if(!this.esri12) {
            return;
        }
        
        var bShowLoadingImage = false;
        for(var layerId in this.layersToLoad) {
            var layer = this.map.getLayer(layerId);
            if(layer != null && layer.visible == true) {
                bShowLoadingImage = true;
                break;
            }
        }
        
        if(!bShowLoadingImage) {
            return;
        }
        
        var center = this.getCenterDockingPoint(this.loadingImageWidth, this.loadingImageHeight);
        var left = center.x - this.loadingImageWidth/2;
        var top = center.y + this.loadingImageHeight/2;
        this.loadingImage.style.left = left;
        this.loadingImage.style.top = top;
        this.loadingImage.style.display = "block";
        
        for(var layerId in this.layersToLoad) {
            var layer = this.map.getLayer(layerId);
            if(layer != null && layer.visible == true) {
                this.loadedLayers[layerId] = false;
            }
        }
    },
    hideLoadingImage: function(layer) {
        if(!this.esri12) {
            return;
        }
        
        this.loadedLayers[layer.id] = true;
        var bAllLoaded = true;
        for(var layerId in this.loadedLayers) {
            var layer = this.map.getLayer(layerId);
            if(layer != null && layer.visible == true) {
                if(this.loadedLayers[layerId] == false) {
                    bAllLoaded = false;
                    break;
                }
            }
        }
        
        if(bAllLoaded){
            this.loadingImage.style.display = "none";
        }
    },
    dock: function() {
        if(!this.mapApplicationConfig.dock) {
            return ;
        }
        
        var dockingParent = dojo.byId(this.mapApplicationConfig.dockingParent);
        if(!dockingParent) {
            return;
        }
        
        var mapDiv = dojo.byId(this.mapDivId);
        var bodyCoords = dojo.coords(document.body);
        var coords = dojo.coords(mapDiv);
        var parentCoords = dojo.coords(dockingParent);
        
        var msg = '';
        msg += 'MapDiv:  L: ' + coords.l + ', T: ' + coords.t + ', W: ' + coords.w + ', H: ' + coords.h + ', X: ' + coords.x + ', Y: ' + coords.y + '\n';
        msg += 'Parent:  L: ' + parentCoords.l + ', T: ' + parentCoords.t + ', W: ' + parentCoords.w + ', H: ' + parentCoords.h + ', X: ' + parentCoords.x + ', Y: ' + parentCoords.y + '\n';
        msg += 'Body:    L: ' + bodyCoords.l + ', T: ' + bodyCoords.t + ', W: ' + bodyCoords.w + ', H: ' + bodyCoords.h + ', X: ' + bodyCoords.x + ', Y: ' + bodyCoords.y + '\n';
        //alert(msg);        
        
        var l = coords.l;
        var t = coords.t;
        var r = coords.w;
        var b = coords.h;
        
        if(this.mapApplicationConfig.dock == "fill") {
            //l = parentCoords.x;
            //t = parentCoords.t;
            //r = parentCoords.w;
            //b = parentCoords.h - parentCoords.x;
            b = bodyCoords.h - parentCoords.y;
        }
        mapDiv.style.height = b;
        
        this.map.reposition();
        this.map.resize();
        this.afterResize();
    },
    repositionSlider: function(domNode) {
        //this.initialSliderLocation = this.map._slider.domNode.getBoundingClientRect();
        if(!this.initialSliderLocation) {
            return;
        }
        
        var x = this.initialSliderLocation.left;
        var y = this.initialSliderLocation.top;
        var r = this.initialSliderLocation.right;
        var b = this.initialSliderLocation.bottom;
        var w = r - x;
        var h = b - y;
        
        //TODO - this method is only moving the slider to the right if the rects of the objects intersect.
        //Need to determine if the slider needs to move up, down or left based on position of rects...
        if(domNode) {
            var domNodeRect = domNode.getBoundingClientRect();
            var bIntersects = ((x > domNodeRect.left && x < domNodeRect.right) || (r > domNodeRect.left && r < domNodeRect.right));
            
            if(bIntersects) {
                var offset = Math.max(domNodeRect.left, x) - Math.min(domNodeRect.left, x);
                x = domNodeRect.right + offset;
            }
        }
        
        this.map._slider.domNode.style.left = x;
        //this.map._slider.domNode.style.top = y;
    },
    setCurrentTool: function(tool) {
        if(this.currentTool != null) {
            this.lastTool = this.currentTool;
            this.currentTool.deactivate();
            if(this.currentTool == tool) {
                this.currentTool = null;
                this.applyCursor();
                return;
            }
        }
        this.currentTool = tool;
        
        if(this.currentTool != null) {
            this.currentTool.activate();
        }
        this.applyCursor();
    },
    applyCursor: function() {
        if(this.currentTool != null) {
            this.map.container.style.cursor = "url(" + this.currentTool.toolbarItemConfig.cursor + ")";
        }
        else {
            this.map.container.style.cursor = "";
        }
    },
    onMapClick: function(evt) {
        if(this.currentTool != null) {
            this.currentTool.currentEvent = evt;
            switch(this.currentTool.toolbarItemConfig.toolAction) {
                case toolAction.toolActionNone:
                    break;
                case toolAction.toolActionPoint:
                    this.currentTool.onToolAction(evt, evt.mapPoint);
                    break;
                default:
                    alert('Unknown tool action: ' + this.currentTool.toolAction);
            }
        }
        this.applyCursor();
    },
    afterResize: function() {
        //this function exists in order to allow other clients to respond to the resize event AFTER the map size has changed.
    },
    getUpperRightDockingPoint: function(width) {
        var mapPosition = dojo.coords(dojo.byId(this.mapDivId));
        var x = mapPosition.w - width + mapPosition.l;
        var y = mapPosition.y;
        return new esri.geometry.Point(x, y, null);
    },
    getCenterDockingPoint: function(width, height) {
        /*var mapPosition = dojo.coords(dojo.byId(this.mapDivId));
        var x = (mapPosition.w/2) + (width/2);
        var y = (mapPosition.h/2) + (height/2);
        return new esri.geometry.Point(x, y, null);*/
        
        //var mapPosition = this.map._pos;
        var mapPosition = dojo.coords(dojo.byId(this.mapDivId));
        var x = (mapPosition.w/2) - (width/2);
        var y = (mapPosition.h/2) - (height/2);
        return new esri.geometry.Point(x, y, null);
    },
    addToolEventListener: function(toolName, toolEventName, onToolEventFunction, propogateEvent) {
        var listeners = this.toolEventListeners[toolName];
        if(!listeners) {
            listeners = new Array();
            this.toolEventListeners[toolName] = listeners;
        }
        var listener = {
            "toolEventName": toolEventName,
            "clientFunction":onToolEventFunction,
            "propogateEvent":propogateEvent
        };
        listeners[listeners.length] = listener;
    },
    updateMapImageExportStatus: function() {
        var layerCount = 0;
        for(var layer in this.currentMapRequests) {
            if(this.currentMapRequests[layer] == true) {
                layerCount++;
            }
        }
        alert(layerCount);
    },
    getToolEventListenerFunctions: function(toolName, toolEventName) {
        var listeners = this.toolEventListeners[toolName];
        if(listeners == null) {
            return null;
        }
        
        var functions = new Array();
        for(var index = 0; index < listeners.length; index++) {
            if(listeners[index].toolEventName == toolEventName) {
                functions[functions.length] = listeners[index].clientFunction;
            }
        }
        return functions;
    },
    getIdentifyOptions: function(layerName) {
        if(!this.mapApplicationConfig.identifyOptions) {
            return null;
        }
        
        for(var index = 0; index < this.mapApplicationConfig.identifyOptions.length; index++) {
            if(this.mapApplicationConfig.identifyOptions[index].layerName == layerName) {
                return this.mapApplicationConfig.identifyOptions[index];
            }
        }
        return null;
    },
    getMapContainer: function() {
        var id = this.mapDivId + '_root';
        return dojo.byId(id);
    },
    findMapServiceConfig: function(layerName) {
        var mapServices = this.mapApplicationConfig.mapServices;
        for(var index = 0; index < mapServices.length; index++) {
            if(mapServices[index].layers) {
                for(var index2 = 0; index2 < mapServices[index].layers.length; index2++) {
                    if(mapServices[index].layers[index2].name == layerName) {
                        return mapServices[index];
                    }
                }
            }
        }
        
        //check to see if the layerName contains the map service name
        if(layerName.indexOf(".") > -1) {
            //sample layer name:
            //MEDOT_Layers_Dynamic.MEDOT.CompRteSys
            var array = layerName.split(".");
            if(array.length > 1) {
                layerName = "";
                for(var index = 1; index < array.length; index++) {
                    if(index > 1) {
                        layerName += ".";
                    }
                    layerName += array[index];
                }
                return this.findMapServiceConfig(layerName);
            }
        }
        
        //the map service may be a tiled map service...
        for(var index = 0; index < mapServices.length; index++) {
            if(mapServices[index].name == layerName) {
                return mapServices[index];
            }
        }
        
        return null;
    },
    findMapService: function(layerName) {
        var mapService = null;
        var mdotMapService = this.findMdotMapServiceByLayerName(layerName);
        if(mdotMapService) {
            mapService = mdotMapService.esriMapServiceLayer;
        }
        /*var mapServiceConfig = this.findMapServiceConfig(layerName);
        if(mapServiceConfig != null) {
            mapService = this.map.getLayer(mapServiceConfig.name);
        }*/
        return mapService;
    },
    findLayer: function(layerName) {
        var mapService = this.findMapServiceConfig(layerName);
        var layer = null;
        if(mapService == null || !mapService.layers) {
            return null;
        }
        
        for(var index = 0; index < mapService.layers.length; index++) {
            if(mapService.layers[index].name == layerName) {
                layer = mapService.layers[index];
                break;
            }
        }
        
        if(layer == null) {
            if(layerName.indexOf(mapService.name) == 0 && layerName.length > (mapService.name.length + 1)) {
                layerName = layerName.substring(mapService.name.length + 1);
                for(var index = 0; index < mapService.layers.length; index++) {
                    if(mapService.layers[index].name == layerName) {
                        layer = mapService.layers[index];
                        break;
                    }
                }
            }
        }
        return layer;
    },
    findMdotMapService: function(mapServiceName) {
        var mapService = null;
        for(var index = 0; index < this.mapServices.length; index++) {
            if(this.mapServices[index].name == mapServiceName) {
                mapService = this.mapServices[index];
                break;
            }
        }
        return mapService;
    },
    findMdotMapServiceByLayerName: function(layerName) {
        var mapService = this.findMapServiceConfig(layerName);
        if(!mapService) {
            return null;
        }
        return this.findMdotMapService(mapService.name);
    },
    findLayerInfo: function(layerName, esriMapService) {
        if(!esriMapService) {
            esriMapService = this.findMapService(layerName);
        }
        
        if(!esriMapService) {
            alert('Failed to find layerInfo for ' + layerName);
            return null;
        }
        
        for(var index = 0; index < esriMapService.layerInfos.length; index++) {
            if(esriMapService.layerInfos[index].name == layerName) {
                return esriMapService.layerInfos[index];
            }
        }
        
        if(layerName.indexOf(".") > -1) {
            var array = layerName.split(".");
            if(array.length > 1) {
                layerName = "";
                for(var index = 1; index < array.length; index++) {
                    if(index > 1) {
                        layerName += ".";
                    }
                    layerName += array[index];
                }
                return this.findLayerInfo(layerName);
            }
        }
        
        return null;
    },
    findVisibleLayerInfo: function(layerName) {
        /*var layerInfo = this.findLayerInfo(layerName);
        if(layerInfo == null) {
            return null;
        }
        
        if(layerInfo.subLayerIds) {
        
        }
        */
        
        //TODO - ESRI's API does not have a method to provide detailed information about a layer
        //in a dynamic map service i.e. min scale, max scale, fields, etc.
        //need to work around this...
        return null;
        
    },
    findLayerConfigOrMapServiceConfig: function(layerName) {
        var mapService = this.findMapServiceConfig(layerName);
        if(mapService == null) {
            return null;
        }
        
        if(mapService.mapServiceType == mapServiceType.mapServiceTypeTiled) {
            return mapService;
        }
        else {
            var layer = this.findLayer(layerName);
            return layer;
        }
    },
    findField: function(layer, fieldName) {
        if(layer != null && layer.fields) {
            for(var index = 0; index < layer.fields.length; index++) {
                if(layer.fields[index].name == fieldName) {
                    return layer.fields[index];
                }
            }
        }
        return null;
    },
    getCustomDataSource: function(dataSourceName) {
        var dataSource = this.customDataSources[dataSourceName];
        if(!dataSource)
            dataSource = this.createCustomDataSource(dataSourceName);
        return dataSource;
    },
    findCustomDataSource: function(dataSourceName) {
        if(this.mapApplicationConfig.customDataSources) {
            for(var index = 0; index < this.mapApplicationConfig.customDataSources.length; index++) {
                if(this.mapApplicationConfig.customDataSources[index].name == dataSourceName) {
                    return this.mapApplicationConfig.customDataSources[index];
                }
            }
        }
        return null;
    },
    createCustomDataSource: function(dataSourceName) {
        var dataSourceConfig = this.findCustomDataSource(dataSourceName);
        if(dataSourceConfig == null) {
            return null;
        }
        
        var customDataSource = eval('new ' + dataSourceConfig.javaScriptClassName + '()');
        customDataSource.load(this, dataSourceConfig);
        this.customDataSources[dataSourceName] = customDataSource;
        return customDataSource;
    },
    setLayerVisibility: function(layerName, bVisible) {
        var mapService = this.findMapService(layerName);
        if(mapService == null) {
            return;
        }
        
        var layerInfo = this.findLayerInfo(layerName);
        if(layerInfo == null) {
            return;
        }
        
        var layerIds = new Array();
        layerIds[0] = layerInfo.id;
        mapService.setVisibleLayers(layerIds);
        
        if(!mapService.visible) {
            mapService.show();
        }
    },
    setVisibleLayers: function(visibleLayers, hiddenLayers) {
        var visibleMapServices = [];
        var hiddenMapServices = [];
        
        if(hiddenLayers) {
            for(var index = 0; index < hiddenLayers.length; index++) {
                var mapServiceConfig = this.findMapServiceConfig(hiddenLayers[index]);
                if(mapServiceConfig) {
                    hiddenMapServices[mapServiceConfig.name] = mapServiceConfig;
                }
            }
        }
        
        if(visibleLayers) {
            for(var index = 0; index < visibleLayers.length; index++) {
                var mapServiceConfig = this.findMapServiceConfig(visibleLayers[index]);
                if(mapServiceConfig) {
                    visibleMapServices[mapServiceConfig.name] = mapServiceConfig;
                }
            }            
        }
        
        for(var mapServiceName in hiddenMapServices) {
            if(visibleMapServices[mapServiceName]) {
                continue;
            }
            else {
                var mapService = this.findMdotMapService(mapServiceName);
                if(mapService && mapService.esriMapServiceLayer) {
                    mapService.esriMapServiceLayer.hide();
                }
            }
        }
        
        if(visibleLayers) {
            visibleMapServices = [];
            for(var index = 0; index < visibleLayers.length; index++) {
                var layerInfo = this.findLayerInfo(visibleLayers[index]);
                if(!layerInfo) {
                    continue;
                }
                
                var mapService = this.findMdotMapServiceByLayerName(visibleLayers[index]);
                if(!mapService) {
                    continue;
                }
                
                var layerIds = visibleMapServices[mapService.name];
                if(layerIds) {
                    layerIds[layerIds.length] = layerInfo.id;
                }
                else {
                    visibleMapServices[mapService.name] = [layerInfo.id];
                }
            }
            
            for(var mapServiceName in visibleMapServices) {
                var mapService = this.findMdotMapService(mapServiceName);
                if(mapService && mapService.esriMapServiceLayer) {
                    mapService.esriMapServiceLayer.setVisibleLayers(visibleMapServices[mapService.name]);
                    mapService.esriMapServiceLayer.show();
                }
            }
        }
    },
    isDataVisible: function(layerName) {
        var mapService = this.findMapServiceConfig(layerName);
        if(mapService == null) {
            return false;
        }
        
        var esriMapService = this.findMapService(mapService.name);
        if(!esriMapService || !esriMapService.visible) {
            return false;
        }
        
        if(mapService.mapServiceType == mapServiceType.mapServiceTypeTiled) {
            return esriMapService.visible;
        }
        else {
            var layer = this.findLayer(layerName);
            if(layer == null) {
                return false;
            }
            return this.isLayerVisible(layerName);
        }
    },
    isLayerVisible: function(layerName) {
        var layerInfo = this.findLayerInfo(layerName);
        if(layerInfo == null) {
            return false;
        }
        
        var layer = this.findMapService(layerName);
        if(this.esri12) {
            if(layer == null || !layer.visibleLayers) {
                return false;
            }
            
            for(var index = 0; index < layer.visibleLayers.length; index++) {
                if(layer.visibleLayers[index] == layerInfo.id) {
                    return true;
                }
            }
        }
        else {
            if(layer == null || !layer._layerIds) { //TODO - this is using a private variable in ESRI's framework...
                return false;
            }
        
            for(var index = 0; index < layer._layerIds.length; index++) {
                if(layer._layerIds[index] == layerInfo.id) {
                    return true;
                }
            }
        }
        
        
        return false;
    },
    setExtent: function(minx, miny, maxx, maxy) {
        //This function exists for Automation - i.e. Embedding a map in a web page or as a popup...
        var extent = new esri.geometry.Extent(minx, miny, maxx, maxy, this.map.spatialReference);
        this.map.setExtent(extent);
    },
    setExtent2: function(extent) {
        if(this.mapApplicationConfig.mapServices && this.mapApplicationConfig.mapServices.length) {
            var mapDiv = dojo.byId(this.mapDivId);
            if(mapDiv) {
                var coords = dojo.coords(mapDiv);
                var scale = mdot.mapping.framework.Util.getScale(extent, coords.w, coords.h);
                extent = mdot.mapping.framework.Util.getExtentFromScale2(extent.getCenter(), coords.w, coords.h, scale);

                var layer = this.map.getLayer(this.mapApplicationConfig.mapServices[0].name);
                if(layer.scales) {
                    var scaleIndex = -1;
                    for(var index = 0; index < layer.scales.length; index++) {
                        if(layer.scales[index] < scale && index > 0) {
                            scaleIndex = index - 1;
                            extent = mdot.mapping.framework.Util.getExtentFromScale2(extent.getCenter(), coords.w, coords.h, layer.scales[index - 1]);
                            break;
                        }
                    }
                }
            }
        }
        this.map.setExtent(extent);
    },
    queryByFeatureValue: function(layerName, fieldName, queryValue, pResultSetDisplayType, pSelectionDisplayType, pZoomToSelectionType) {
        var identifyOptions = this.getIdentifyOptions(layerName);
        if(identifyOptions == null) {
            alert('Failed to find identify options for ' + layerName);
            return;
        }
        
        pResultSetDisplayType = mdot.mapping.framework.Util.getData(pResultSetDisplayType, resultSetDisplayType.resultSetDisplayTypeNone);
        pSelectionDisplayType = mdot.mapping.framework.Util.getData(pSelectionDisplayType, selectionDisplayType.selectionDisplayTypeNone);
        pZoomToSelectionType = mdot.mapping.framework.Util.getData(pZoomToSelectionType, resultSetDisplayType.zoomToSelectionTypeNone);
        
        var originalResultSetDisplayType = identifyOptions.resultSetDisplayType;
        var originalSelectionDisplayType = identifyOptions.selectionDisplayType;
        var originalZoomToSelectionType = identifyOptions.zoomToSelectionType;
        
        identifyOptions.resultSetDisplayType = pResultSetDisplayType;
        identifyOptions.selectionDisplayType = pSelectionDisplayType;
        identifyOptions.zoomToSelectionType = pZoomToSelectionType;
        
        var ref = this;
        mdot.mapping.framework.QueryEngine.attributeQuery(ref, 
                                                          fieldName, 
                                                          queryValue, 
                                                          identifyOptions,
                                                          null,
                                                          function(resultSet) {
            //only zooming to, no need to use ResultSetDisplay object...
            if(pResultSetDisplayType == resultSetDisplayType.resultSetDisplayTypeNone && pSelectionDisplayType == selectionDisplayType.selectionDisplayTypeNone) {
                mdot.mapping.framework.Util.setExtent(resultSet.features, ref.map);
            }
            else {
                var resultSetDisplayDialog = mdot.mapping.framework.ResultSetDisplay.getInstance();
                resultSetDisplayDialog.hide();
                
                var width = resultSet.identifyOptions.resultSetDisplayWidth;
                var height = resultSet.identifyOptions.resultSetDisplayHeight;
                resultSetDisplayDialog.show(ref.map, resultSet, pResultSetDisplayType, width, height);
            }
            identifyOptions.resultSetDisplayType = identifyOptions.originalResultSetDisplayType;
            identifyOptions.selectionDisplayType = identifyOptions.originalSelectionDisplayType;
            identifyOptions.zoomToSelectionType = identifyOptions.zoomToSelectionType;
        });
    },   
    queryByWhereClause: function(layerName, whereClause, resultSetDisplayType, selectionDisplayType, zoomToSelectionType) {
        
    },
    find: function(layerName, fieldName, value, statusDialogConfig, successHandler, errorHandler) {
        var findOptions = this.getIdentifyOptions(layerName);
        if(findOptions == null) {
            alert('Failed to find identify options for ' + layerName + '!');
            return;
        }
        mdot.mapping.framework.QueryEngine.attributeQuery(this,
                                                          fieldName,
                                                          value,
                                                          findOptions,
                                                          statusDialogConfig,
                                                          successHandler,
                                                          errorHandler);
    }
});
//end MapApplication.js

//begin OverviewMap.js
dojo.declare("mdot.mapping.framework.OverviewMap", null,
{
    constructor: function(pMapApp, overviewMapConfig) {
        this.overviewMapConfig = overviewMapConfig;
        this.rectangleGraphic = null;
        this.pointGraphic = null; 
        this.mapApplication = pMapApp;
        this.overviewMap = null;
        this.currentExtent = pMapApp.map.extent;
        this.detached = !(!overviewMapConfig.mapDivId);
        this.overviewMapId = this.createOverviewWindow();
        this.isVisible = this.detached;
        
        //the ESRI framework does some weird things with the map if the container is not visible during initialization...
        this.show();
        
        var initialExtent = pMapApp.extent;
        this.overviewMap = new esri.Map(this.overviewMapId,{extent: initialExtent,slider:false,nav:false}); 
        
        for(var index = 0; index < this.overviewMapConfig.mapServices.length; index++) {
            var mapServiceConfig = pMapApp.findMapServiceConfig(this.overviewMapConfig.mapServices[index]);
            if(mapServiceConfig) {
                if(mapServiceConfig.mapServiceType == mapServiceType.mapServiceTypeTiled) {
                    var layer = new esri.layers.ArcGISTiledMapServiceLayer(mapServiceConfig.url, {
                        id:mapServiceConfig.name + "_OV",
                        visible:true,
                        opacity:mapServiceConfig.opacity ? mapServiceConfig.opacity : 1.0
                    });
                    this.overviewMap.addLayer(layer);
                }
                else {
                    alert('Overview Map: ' + this.overviewMapConfig.mapServices[index] + ' is not a tiled map service!');
                }
            }
            else {
                alert('Overview Map: Failed to find map service for ' + this.overviewMapConfig.mapServices[index]);
            }
        }
        //this.overviewMap.setExtent(pMapApp.extent);
        this.overviewMap.disableMapNavigation();
        this.hide();
        
        var ref = this;
        dojo.connect(pMapApp.map, "onExtentChange", function(extent, delta, levelChange, lod) {
            ref.onMapExtentChanged(extent, delta, levelChange, lod);
        });
        
        if(!this.overviewMapConfig.mapClickDisabled) {
            dojo.connect(this.overviewMap, "onClick", function(evt) {
                var center = evt.mapPoint;
                var mapExtent = ref.mapApplication.map.extent;
                ref.mapApplication.map.setExtent(mapExtent.centerAt(center));
            });
        }
        
        dojo.connect(pMapApp, "afterResize", function() {
            ref.afterMapResized();
        });
    },
    createOverviewWindow: function() {
        if(this.detached) {
            return this.overviewMapConfig.mapDivId;
        }
        
        var id = "OverviewMap_" + new Date().getTime();
        var ref = this;
        
        var mapDiv = dojo.byId(this.mapApplication.mapDivId);
        var box = dojo.coords(mapDiv, true);
        var ul = this.mapApplication.map.position;
        var w = this.mapApplication.map.width;
        var h = this.mapApplication.map.height;
        

        var div = document.createElement('div');        
        div.id = id + '_Closed';
        div.style.display = "none";
        div.style.position = "absolute";
        div.style.left = (box.l + (w - this.overviewMapConfig.openImage.width) + 1) + "px";
        div.style.top = (box.t + (h - this.overviewMapConfig.openImage.height) + 1) + "px";
        div.style.zIndex = 99;
        
        var html = '';   
        html += '<img id="' + id + '_openButton" src="' + this.overviewMapConfig.openImage.url + '" width="' + this.overviewMapConfig.openImage.width + '" height="' + this.overviewMapConfig.openImage.height + '" />';
        div.innerHTML = html;
        //mapDiv.parentNode.appendChild(div);
        //document.body.appendChild(div);
        this.mapApplication.map.container.appendChild(div);
        
        div = document.createElement('div');
        var borderSize = 0;
        if(this.overviewMapConfig.border) {
            div.style.border = this.overviewMapConfig.border;
            //TODO - extract this property out!!!
            borderSize = 2;
        }
        
        div.id = id + '_Opened';
        div.style.display = "none";
        div.style.position = "absolute";
        div.style.width = this.overviewMapConfig.width;
        div.style.height = this.overviewMapConfig.height;
        div.style.left = (box.l + (w - this.overviewMapConfig.width) - borderSize) + "px";
        div.style.top = (box.t + (h - this.overviewMapConfig.height) - borderSize) + "px";
        div.style.zIndex = 99;
        
        html = '';
        
        var bgcolor = '';
        if(this.overviewMapConfig.backgroundColor) {
            bgcolor = ' background-color:' + this.overviewMapConfig.backgroundColor + ';';
        }
        
        html += '<div id="' + id + '" style="width:100%;height:100%;position:relative;left:0;top:0;background-color:#EBF0FF;"></div>';
        html += '<img id="' + id + '_closeButton" src="' + this.overviewMapConfig.closeImage.url + '" width="' + this.overviewMapConfig.closeImage.width + '" height="' + this.overviewMapConfig.closeImage.height + '" style="position:absolute;left:0;top:0;" />';
        div.innerHTML = html;
        //document.body.appendChild(div);
        //mapDiv.parentNode.appendChild(div);
        this.mapApplication.map.container.appendChild(div);
        
        
        var openImage = document.getElementById(id + '_openButton');
        dojo.connect(openImage, "onclick", function() {
            ref.show();
        });
        
        var closeImage = document.getElementById(id + '_closeButton');
        dojo.connect(closeImage, "onclick", function() {
            ref.hide();
        });
        
        return id;
    },
    afterMapResized: function() {
        if(this.detached) {
            return;
        }
        
        var id = this.overviewMapId;
        var box = dojo.coords(this.mapApplication.mapDivId);
        //var w = box.w - box.x;
        //var h = box.h + box.y;
        
        var w = this.mapApplication.map.width;
        var h = this.mapApplication.map.height;
        
        var div = dojo.byId(id + '_Closed');
        div.style.left = w - this.overviewMapConfig.openImage.width; + box.x;
        div.style.top = h - this.overviewMapConfig.openImage.height + box.y;
        
        div = dojo.byId(id + '_Opened');
        div.style.left = w - this.overviewMapConfig.width;
        div.style.top = h - this.overviewMapConfig.height;
        
        this.overviewMap.reposition();
        this.overviewMap.resize();
    },
    show: function() {
        if(this.detached) {
            return;
        }
        
        var id = this.overviewMapId;
        var div = document.getElementById(id + '_Closed');
        div.style.display = "none";
        
        div = document.getElementById(id + '_Opened');
        div.style.display = "block";
        this.isVisible = true;
        
        if(this.overviewMap) {
            this.overviewMap.reposition();
            this.overviewMap.resize();
        }
        
        this.showMapExtent(this.currentExtent);
    },
    hide: function() {
        if(this.detached) {
            return;
        }
        
        var id = this.overviewMapId;
        var div = document.getElementById(id + '_Opened');
        div.style.display = "none";
            
        div = document.getElementById(id + '_Closed');
        div.style.display = "block";
        this.isVisible = false;
    },
    onMapExtentChanged: function(extent, delta, levelChange, lod) {
        this.currentExtent = extent;
        if(!this.isVisible) {
            return;
        }
        this.showMapExtent(extent);
    },
    showMapExtent: function(extent) {
        if(!extent || !this.overviewMap || !this.isVisible) {
            return;
        }
        
        if(!extent.spatialReference) {
            return;
        }
        
        var screenExtent = null;
        try {
            screenExtent = mdot.mapping.framework.Util.toScreen(extent, this.overviewMap);
        }
        catch(e) {
            return;
        }
        
        var bShowMarker = false;
        if(screenExtent.getWidth() < this.overviewMapConfig.minWidth || screenExtent.getHeight() < this.overviewMapConfig.minHeight) {
            bShowMarker = true;
        }
        
        if(!this.rectangleGraphic) {
            var symbol = eval(this.overviewMapConfig.fillSymbol);
            this.rectangleGraphic = new esri.Graphic(extent, symbol);
            this.overviewMap.graphics.add(this.rectangleGraphic);
        }
        else {
            this.rectangleGraphic.setGeometry(extent);
        }
        if(bShowMarker) {
            this.rectangleGraphic.hide();
        }
        else {
            var ul = new esri.geometry.Point(this.overviewMap.extent.xmin, this.overviewMap.extent.ymax);
            var lr = new esri.geometry.Point(this.overviewMap.extent.xmax, this.overviewMap.extent.ymin);
            if(extent.contains(ul) && extent.contains(lr))
                this.rectangleGraphic.hide();
            else
                this.rectangleGraphic.show();
        }
        
        
        if(!this.pointGraphic) {
            var symbol = eval(this.overviewMapConfig.markerSymbol);
            this.pointGraphic = new esri.Graphic(extent.getCenter(), symbol);
            this.overviewMap.graphics.add(this.pointGraphic);
        }
        else {
            this.pointGraphic.setGeometry(extent.getCenter());
        }
        if(bShowMarker) {        
            this.pointGraphic.show();
        }
        else {
            this.pointGraphic.hide();
        }        
    }
});
//end OverviewMap.js

//begin QueryEngine.js
dojo.provide("mdot.mapping.framework.QueryEngine");
dojo.mixin(mdot.mapping.framework.QueryEngine, {
    spatialQuery: function(pMapApp, evt, geometry, identifyOptions, statusDialogConfig, resultSetHandler) {
        var layerName = identifyOptions.layerName;
        if(!layerName) {
            alert('spatialQuery: layerName is not defined!');
            return;
        }
        var mdotLayer = pMapApp.findLayer(layerName);
        if(mdotLayer == null && identifyOptions.identifyLayerName) {
            mdotLayer = pMapApp.findLayer(identifyOptions.identifyLayerName);
        }
        if(mdotLayer == null) {
            alert('Failed to find layer in configuration!');
            return;
        }
        
        var mapService = pMapApp.findMapService(layerName);
        if(mapService == null && identifyOptions.identifyLayerName) {
            mapService = pMapApp.findMapService(identifyOptions.identifyLayerName);
        }
        
        if(mapService == null) {
            alert('Failed to find map service in configuation!');
            return;
        }
        
        if(mapService.declaredClass == "esri.layers.ArcGISTiledMapServiceLayer") {
            if(identifyOptions.identifyLayerName && identifyOptions.identifyLayerName == mapService.name) {
                alert("Map service is a tiled map service!");
                return;
            }
            else {
                mapService = pMapApp.findMapService(identifyOptions.identifyLayerName);
                if(!mapService) {
                    alert("Failed to find a dynamic map service named " + identifyOptions.identifyLayerName);
                    return;
                }
            }
        }
        
        var layerInfo = pMapApp.findLayerInfo(mdot.mapping.framework.Util.getString(identifyOptions.identifyLayerName, layerName), mapService);
        if(layerInfo == null) {
            alert('Failed to find LayerInfo object for layer!');
            return;
        }
        
        var statusDialog = null;
        if(statusDialogConfig) {
            statusDialogConfig.initialMessage = "Searching " + mdotLayer.label;
            statusDialog = new mdot.mapping.framework.StatusDialog(pMapApp, statusDialogConfig);
        }
        
        var queryTask = new esri.tasks.QueryTask(mapService.url + "/" + layerInfo.id);
        var query = new esri.tasks.Query();
        
        var whereClause = identifyOptions.whereClause;
        if(whereClause) {
            query.where = whereClause;
        }
        
        var subfields = this.getSubFields(identifyOptions, mdotLayer);
        if(subfields != null && subfields.length > 0) {
            query.outFields = new Array();
            for(var index = 0; index < subfields.length; index++) {
                query.outFields[index] = subfields[index];
            }
        }
        
        query.geometry = geometry;
        query.returnGeometry  = identifyOptions.returnGeometry;
        
        queryTask.execute(query, function(featureSet) {
            if(statusDialog) {
                statusDialog.kill();
            }
            try {
                var resultSet = {
                    "features": featureSet.features,
                    "mdotLayer": mdotLayer,
                    "clientEvent": evt,
                    "queryGeometry": query.geometry,
                    "identifyOptions": identifyOptions,
                    "fields":subfields
                };
            
                resultSetHandler(resultSet);
            }
            catch(e) {
                var msg = '';
                for(var prop in e) {
                    msg += prop + ': ' + e[prop] + '\n';
                }
                alert('An error has occurred:\n' + msg);
                //alert('An error has occurred:\n' + e.message);
            }
        });
    },
    attributeQuery: function(pMapApp, queryField, queryValue, findOptions, statusDialogConfig, resultSetHandler) {
        var layerName = findOptions.layerName;
        var mdotLayer = pMapApp.findLayer(layerName);
        if(mdotLayer == null) {
            alert('Failed to find layer in configuration!');
            return;
        }
        
        var mapService = pMapApp.findMapService(layerName);
        if(mapService == null) {
            alert('Failed to find map service for layer "' + layerName + '"!');
            return;
        }
        
        var identifyLayerId = mdot.mapping.framework.Util.getString(findOptions.identifyLayerName, findOptions.layerName);
        var layerInfo = pMapApp.findLayerInfo(identifyLayerId, mapService);
        if(layerInfo == null) {
            alert('Failed to find layer info for layer "' + identifyLayerId + '"!');
            return;
        }
        
        var statusDialog = null;
        if(statusDialogConfig != null) {
            statusDialogConfig.initialMessage = "Searching " + mdotLayer.label;
            statusDialog = new mdot.mapping.framework.StatusDialog(pMapApp, statusDialogConfig);
        }
        
        var subfields = this.getSubFields(findOptions, mdotLayer);
        
        var ref = this;
        var findTask = new esri.tasks.FindTask(mapService.url);
        var findParams = new esri.tasks.FindParameters();
        findParams.returnGeometry = findOptions.returnGeometry;
        findParams.layerIds = [layerInfo.id];
        findParams.searchFields = [queryField];
        findParams.searchText = queryValue;
        findParams.contains = false;
        
        findTask.execute(findParams, function(findResult) {
            if(statusDialog) {
                statusDialog.kill();
            }        
            var resultSet = {
                "features": [],
                "mdotLayer": mdotLayer,
                "clientEvent": null,
                "queryGeometry": null,
                "findParams": findParams,
                "identifyOptions": findOptions,
                "fields":subfields
            };
            
            for(var index = 0; index < findResult.length; index++) {
                resultSet.features[index] = findResult[index].feature;
            }
            
            //the esri.tasks.FindParameters does not have a subFields concept like the esri.tasks.Query does.
            //need to scrub the attributes...
            ref.scrubResultSet(resultSet, findOptions, mdotLayer);
            
            resultSetHandler(resultSet);
        });
    },
    scrubResultSet: function(resultSet, findOptions, mdotLayer) {
        var sSubfields = findOptions.subfields;
        var subfields = new Array();
        var layerFields = mdotLayer.fields;
        var bHasSubfields = false;
        if(sSubfields == null || sSubfields == "*") {
            //user wants all fields in the layer...
            if(mdotLayer.fields != null) {
                for(var index = 0; index < mdotLayer.fields.length; index++) {
                    //subfields[subfields.length] = mdotLayer.fields[index].name;
                    //subfields[mdotLayer.fields[index].name] = mdotLayer.fields[index].label;
                    subfields[mdotLayer.fields[index].name] = true;
                    bHasSubfields = true;
                }
            }
        }
        else {
            var tempSubfields = sSubfields.split(",");
            if(tempSubfields != null && tempSubfields.length > 0) {
                for(var index = 0; index < tempSubfields.length; index++) {
                    subfields[tempSubfields[index]] = true;
                    bHasSubfields = true;
                }
            }
        }
            
        if(bHasSubfields) {
            for(var index = 0; index < resultSet.features.length; index++) {
                var newAttributes = [];
                for(var prop in subfields) {
                    //newAttributes[subfields[prop]] = resultSet.features[index].attributes[prop];
                    if(subfields[prop]) {
                        newAttributes[prop] = resultSet.features[index].attributes[prop];
                    }
                }
                resultSet.features[index].attributes = newAttributes;
            }
        }
    },
    geocode: function(pMapApp, geocodeServerUrl, street, city, geocodeOptions, statusDialogConfig, onAddressToLocationsCompleteHandler) {
        var locator = new esri.tasks.Locator(geocodeServerUrl);
        var address = {
           "Street":street,
           "Zone":city
        };
        
        var statusDialog = null;
        if(statusDialogConfig) {
            statusDialog = new mdot.mapping.framework.StatusDialog(pMapApp, statusDialogConfig);
        }
        
        locator.addressToLocations(address, ["Loc_name"], function(addressCandidates) {
            if(statusDialog) {
                statusDialog.kill();
            }
            var features = new Array();
            var maxCount = geocodeOptions ? (geocodeOptions.showFirstResultOnly ? Math.min(1,addressCandidates.length) : addressCandidates.length) : addressCandidates.length;
            for(var index = 0; index < maxCount; index++) {
                var attributes = addressCandidates[index].attributes;
                if(!attributes) {
                    attributes = new Array();
                }
                attributes["address"] = addressCandidates[index].address;
                attributes["score"] = addressCandidates[index].score;
                
                features[index] = new esri.Graphic(addressCandidates[index].location, null, attributes);
            }
            
            if(!geocodeOptions) {
                geocodeOptions = {};
            }
            
            var resultSet = {
                "features":features,
                "clientEvent":null,
                "queryGeometry":null,
                "mdotLayer": {
                   "label":"Geocoding Results"
                },
                "identifyOptions": geocodeOptions
            };
            onAddressToLocationsCompleteHandler(resultSet);
        });
    },
    getSubFields: function(identifyOptions, mdotLayer) {
        var sSubfields = identifyOptions.subfields;
        var subfields = [];
        if(sSubfields == null || sSubfields == "*") {
            //user wants all fields in the layer...
            if(mdotLayer.fields != null) {
                for(var index = 0; index < mdotLayer.fields.length; index++) {
                    subfields[subfields.length] = mdotLayer.fields[index].name;
                }
            }
        }
        else {
            subfields = sSubfields.split(",");
        }
        return subfields;
    }
});
//end QueryEngine.js

//begin ResultSetDisplay.js
dojo.provide("mdot.mapping.framework.ResultSetDisplay");
dojo.mixin(mdot.mapping.framework.ResultSetDisplay, {
    getInstance: function() {
        if(!this.ref) {
            this.ref = this;
        }
        return this.ref;
    },
    show: function(map, resultSet, pResultSetDisplayType, width, height, dockingPoint) {
        this.map = map;
        this._resultSetDisplayType = pResultSetDisplayType;
        this.width = mdot.mapping.framework.Util.getData(width, 250);
        this.height = mdot.mapping.framework.Util.getData(height, 400);
        this.graphics = new Array();    
        this.resultSet = resultSet;
        this.dockingPoint = dockingPoint;
        this.onExtentChangeHandle = null;
        this.defaultScaleForZoom = 4000;
        this.userClickGraphic = null;
        
        if(resultSet.queryGeometry && resultSet.identifyOptions.showUserClick && resultSet.identifyOptions.userClickSymbol) {
            var symbol = eval(this.resultSet.identifyOptions.userClickSymbol);
            this.userClickGraphic = new esri.Graphic(resultSet.queryGeometry, symbol);
        }
        
        //"showUserClick":true,
        //       "userClickSymbol":"new esri.symbol.SimpleMarkerSymbol(esri.symbol.SimpleMarkerSymbol.STYLE_DIAMOND, 20, new esri.symbol.SimpleLineSymbol(esri.symbol.SimpleLineSymbol.STYLE_SOLID, new dojo.Color([0,0,0]), 1), new dojo.Color([255,255,0,0.5]))"
        
        
        
        if(resultSet.features == null || resultSet.features.length == 0) {
            if(resultSet.identifyOptions.displayMessageForNoData && resultSet.identifyOptions.displayMessageForNoData != "") {
                alert(resultSet.identifyOptions.displayMessageForNoData);
            }
            return;
        }
        
        var pZoomToSelectionType = mdot.mapping.framework.Util.getData(resultSet.identifyOptions.zoomToSelectionType, zoomToSelectionType.zoomToSelectionTypeNone);
        if(pZoomToSelectionType == zoomToSelectionType.zoomToSelectionTypeAll || pZoomToSelectionType == zoomToSelectionType.zoomToSelectionTypeBoth) {
            var ref = this;
            this.onExtentChangeHandle = dojo.connect(this.map, "onExtentChange", function() {
                ref.continueProcessing();
            });    
            mdot.mapping.framework.Util.setExtent(resultSet.features, this.map, this.defaultScaleForZoom);
        }
        else {
            this.continueProcessing();
        }
    },
    continueProcessing: function() {  
        if(this.onExtentChangeHandle) {
            dojo.disconnect(this.onExtentChangeHandle);
            this.onExtentChangeHandle = null;
        }
        
        var arrayOfHtmlPerFeature = this.getHtml(this.resultSet);
        switch(this._resultSetDisplayType) {
            case resultSetDisplayType.resultSetDisplayTypeNone:
                //Do not display attributes
                //TODO - check to see if need to add graphic to map...
                break;
            case resultSetDisplayType.resultSetDisplayTypeList:
                this.displayResultSetAsList(this.resultSet, arrayOfHtmlPerFeature);
                break;
            case resultSetDisplayType.resultSetDisplayTypeInfoWindow:
                this.displayResultSetAsInfoWindow(this.resultSet, arrayOfHtmlPerFeature);
                break;
            case resultSetDisplayType.resultSetDisplayTypeAccordian:
                this.displayResultSetAsAccordian(this.resultSet, arrayOfHtmlPerFeature);
                break;
            case resultSetDisplayType.resultSetDisplayTypeTab:
                this.displayResultSetAsTab(this.resultSet, arrayOfHtmlPerFeature);
                break;
        }
        
        if(this.resultSet.identifyOptions.selectionDisplayType && this.resultSet.identifyOptions.selectionDisplayType == selectionDisplayType.selectionDisplayTypeAllFeatures) {
            for(var index = 0; index < this.resultSet.features.length; index++) {
                this.displayGraphic(index, false);
            }
        }
    },
    hide: function() {
        var id = "ResultSetDisplay.dialog";
        if(dijit.byId(id)) {
            var dialog = dijit.byId(id);
            dialog.close(); //this will also clear the graphics...
            //dialog.destroyRecursive(false);
        }
    },
    displayResultSetAsList: function(resultSet, arrayOfHtmlPerFeature) {
        var html = '<div style="width:' + (this.width - 16) + ';height:' + (this.height - 16) + ';overflow:auto">';
        for(var index = 0; index < arrayOfHtmlPerFeature.length; index++) {
            if(index > 0) {
                html += '<hr/>';
            }
            html += arrayOfHtmlPerFeature[index];
        }
        html += '</div>';
        this.createFloatingPane(resultSet, html);
    },
    displayResultSetAsInfoWindow: function(resultSet, arrayOfHtmlPerFeature) {
        var html = '';
        for(var index = 0; index < arrayOfHtmlPerFeature.length; index++) {
            if(index > 0) {
                html += '<hr/>';
            }
            html += arrayOfHtmlPerFeature[index];
        }
        
        var infoWindow = this.map.infoWindow;
        infoWindow.setTitle(resultSet.mdotLayer.label);
        infoWindow.setContent(html);
        var displayLocation = this.getDisplayLocation(resultSet);
        infoWindow.anchor = "ANCHOR_UPPERRIGHT";
        infoWindow.resize(300, 200);
        infoWindow.show(displayLocation, this.map.getInfoWindowAnchor(displayLocation));
    },
    displayResultSetAsAccordian: function(resultSet, arrayOfHtmlPerFeature) {
        resultSet.latlon = null;
        if(resultSet.latlon) {
            var container = new dijit.layout.AccordionContainer({
                'id':'IdentifyResultDisplayAccordionPane'
            }, null);
            
            var layerContainers = new dijit.layout.AccordionContainer({
                'id':'IdentifyResultDisplayAccordionPaneLayer',
                'selected':true
            }, null);
            
            var layerPane = new dijit.layout.AccordionPane({
                'title':resultSet.mdotLayer.label,
                'id':'IdentifyResultDisplayAccordionPaneLayerPane'
            }, null);
            
            for(var index = 0; index < arrayOfHtmlPerFeature.length; index++) {
                var title = this.getLabel(resultSet.features[index], resultSet.identifyOptions);
                
                var pane = new dijit.layout.AccordionPane({
                    'title':title,
                    'id':'IdentifyResultDisplayAccordionPaneLayerPane' + index,
                    'selected':index == 0
                }, null);
                pane.setContent(arrayOfHtmlPerFeature[index]);
                layerContainers.addChild(pane);
            }
            
            container.startup();
            container.addChild(layerPane);
            this.createFloatingPane2(resultSet, container.domNode);
            layerPane.setContent(layerContainers);
            layerContainers.startup();
        }
        else {
            var html = '<div id="IdentifyResultDisplayAccordionPane" dojoType="dijit.layout.AccordionContainer" duration="200" style="width: 100%; height: 100%; overflow: hidden">';
            for(var index = 0; index < arrayOfHtmlPerFeature.length; index++) {
                var title = this.getLabel(resultSet.features[index], resultSet.identifyOptions);
                html += '<div dojoType="dijit.layout.AccordionPane" ' + (index == 0 ? 'selected="true"' : '') + ' title="' + title + '">';
                html += arrayOfHtmlPerFeature[index];
                html += '</div>';
            }
            html += '</div>';    
            this.createFloatingPane(resultSet, html);
        }
        
        if(resultSet.identifyOptions.selectionDisplayType && resultSet.identifyOptions.selectionDisplayType == selectionDisplayType.selectionDisplayTypeSingleFeature) {
            this.displayGraphic(0, true);
            
            var ref = this;
            var IdentifyResultDisplayAccordionPane = dijit.byId('IdentifyResultDisplayAccordionPane');
            dojo.connect(IdentifyResultDisplayAccordionPane, "selectChild", function() {
                var pages = IdentifyResultDisplayAccordionPane.getChildren();
                for(var index = 0; index < pages.length; index++) {
                    if(pages[index] == IdentifyResultDisplayAccordionPane.selectedChildWidget) {
                        ref.displayGraphic(index, true);
                        break;
                    }
                }
            });
        }        
    },
    displayResultSetAsTab: function(resultSet, arrayOfHtmlPerFeature) {
        var html = '<div jsId="IdentifyResultDisplayTabPane" dojoType="dijit.layout.TabContainer" duration="200" style="width:100%;height:100%;">';
        for(var index = 0; index < arrayOfHtmlPerFeature.length; index++) {
            var title = this.getLabel(resultSet.features[index], resultSet.identifyOptions);
            html += '<div dojoType="dijit.layout.ContentPane" ' + (index == 0 ? 'selected="true"' : '') + ' title="' + title + '">';            
            html += arrayOfHtmlPerFeature[index];
            html += '</div>';
        }
        html += '</div>';
        this.createFloatingPane(resultSet, html);
        
        if(resultSet.identifyOptions.selectionDisplayType && resultSet.identifyOptions.selectionDisplayType == selectionDisplayType.selectionDisplayTypeSingleFeature) {
            this.displayGraphic(0, true);
            
            var ref = this;
            dojo.connect(IdentifyResultDisplayTabPane, "selectChild", function() {
                var tabs = IdentifyResultDisplayTabPane.getChildren();
                for(var index = 0; index < tabs.length; index++) {
                    if(tabs[index] == IdentifyResultDisplayTabPane.selectedChildWidget) {
                        ref.displayGraphic(index, true);
                        break;
                    }
                }
            });
        }
    },
    createFloatingPane: function(resultSet, innerContent) {
        var displayLocation = this.getDisplayLocation(resultSet);
        var x = displayLocation.x;
        var y = displayLocation.y;
        var width = this.width;
        var height = this.height;
        var label = resultSet.title ? resultSet.title : resultSet.mdotLayer.label;
        
        //alert(x + ', ' + y + ', ' + width + ', ' + height + ', ' + label);
        
        var id = "ResultSetDisplay.dialog";
        if (!dijit.byId(id)){
            var ref = this;
            var containerId = id + ".container";
            var container = dijit.byId(id);
            if(!dijit.byId(id)) {
                container = document.createElement("div");
                container.id = id + ".container";
                container.name = container.id;
                container.className = "resultSetDisplayContainer";
                //container.style.textAlign = "right";
                //container.style.verticalAlign = "top";
                //container.style.width = width;
                //container.style.height = height;                
                document.body.appendChild(container);
            }
            
            var dialog = new dojox.layout.FloatingPane({
                                        title: label,
                                        id: id,
                                        href: null,
                                        closeable: true,
                                        resizable: true,
                                        duration: 0,
                                        hasShadow: true,
                                        dockable: true}, container);
            dialog.closeNode.className = "dijitDialogCloseIcon";
            dialog.focusNode.className = "dijitDialogTitleBar";
            dialog.titleNode.className = "dijitDialogTitle";
            dialog.domNode.className = "dijitDialog";
                    
            dialog.domNode.style.position = "absolute";
            dialog.domNode.style.width = width;
            dialog.domNode.style.height = height;
            
            if(this.dockingPoint) {
                dialog.domNode.style.left = this.dockingPoint.x;
                dialog.domNode.style.top = this.dockingPoint.y;
            }
            else {
                if(esri.version && esri.version >= 1.3) {
                    var ul = this.map.position;
                    dialog.domNode.style.left = this.map.width - width + ul.x;
                    dialog.domNode.style.top = ul.y;
                }
                else {
                    //TODO - this is using a private member variable of ESRI's map object...
                    var mapPosition = this.map._pos;
                    dialog.domNode.style.left = mapPosition.w - width + mapPosition.x;
                    dialog.domNode.style.top = mapPosition.y;
                }
            }
            
            dialog.setContent(innerContent);
            dialog.startup();
        }
        else {
            var dialog = dijit.byId(id);
            dialog.show();
        }
        
        //dijit.placeOnScreen(dialog.domNode, {x: 10000, y: 0}, ["TR"], false);
        
        var ref = this;
        dojo.connect(dialog, "close", function() {
            ref.clearGraphics();
        });
        
        return dialog;
    },
    createFloatingPane2: function(resultSet, innerContent) {
        var displayLocation = this.getDisplayLocation(resultSet);
        var x = displayLocation.x;
        var y = displayLocation.y;
        var width = this.width;
        var height = this.height;
        var latlon = (Math.round(resultSet.latlon.x * 100) / 100) + ', ' + (Math.round(resultSet.latlon.y * 100) / 100);
        var label = 'Identify Results (' + latlon + ')';
        
        var id = "ResultSetDisplay.dialog";
        if (!dijit.byId(id)){
            var ref = this;
            var containerId = id + ".container";
            var container = dijit.byId(id);
            if(!dijit.byId(id)) {
                container = document.createElement("div");
                container.id = id + ".container";
                container.name = container.id;
                container.className = "resultSetDisplayContainer";
                //container.style.textAlign = "right";
                //container.style.verticalAlign = "top";
                //container.style.width = width;
                //container.style.height = height;                
                document.body.appendChild(container);
            }
            
            var dialog = new dojox.layout.FloatingPane({
                                        title: label,
                                        id: id,
                                        href: null,
                                        closeable: true,
                                        resizable: true,
                                        duration: 0,
                                        hasShadow: true,
                                        dockable: true}, container);
            dialog.closeNode.className = "dijitDialogCloseIcon";
            dialog.focusNode.className = "dijitDialogTitleBar";
            dialog.titleNode.className = "dijitDialogTitle";
            dialog.domNode.className = "dijitDialog";
                    
            dialog.domNode.style.position = "absolute";
            dialog.domNode.style.width = width;
            dialog.domNode.style.height = height;
            
            if(this.dockingPoint) {
                dialog.domNode.style.left = this.dockingPoint.x;
                dialog.domNode.style.top = this.dockingPoint.y;
            }
            else {
                //TODO - this is using a private member variable of ESRI's map object...
                var mapPosition = this.map._pos;
                dialog.domNode.style.left = mapPosition.w - width + mapPosition.x;
                dialog.domNode.style.top = mapPosition.y;
            }
            
            dialog.setContent(innerContent);
            dialog.startup();
        }
        else {
            var dialog = dijit.byId(id);
            dialog.show();
        }
        
        //dijit.placeOnScreen(dialog.domNode, {x: 10000, y: 0}, ["TR"], false);
        
        var ref = this;
        dojo.connect(dialog, "close", function() {
            ref.clearGraphics();
        });
        
        return dialog;
    },    
    getFieldDisplayLabel: function(mdotLayer, fieldName) {
        if(mdotLayer.subfields) {
            for(var index = 0; index < mdotLayer.subfields.length; index++) {
                if(mdotLayer.subfields[index].name == fieldName) {
                    return mdotLayer.subfields[index].label;
                }
            }
        }
        
        if(mdotLayer.fields) {
            for(var index = 0; index < mdotLayer.fields.length; index++) {
                if(mdotLayer.fields[index].name == fieldName) {
                    return mdotLayer.fields[index].label;
                }
            }
        }        
        return fieldName;
    },    
    getLabel: function(feature, identifyOptions) {
        if(this.resultSet.customResultSetDisplayHandler && this.resultSet.customResultSetDisplayHandler.getCustomResultSetDisplayLabel) {
            for(var index = 0; index < this.resultSet.features.length; index++) {
                if(this.resultSet.features[index] == feature) {
                    return this.resultSet.customResultSetDisplayHandler.getCustomResultSetDisplayLabel(this.resultSet, index);
                }
            }
        }
        
        if(feature == null || feature.attributes == null || identifyOptions == null || !identifyOptions.labelFieldName) {
            return "No label";
        }
        else {
            for(var attribute in feature.attributes) {
                if(attribute == identifyOptions.labelFieldName) {
                    return feature.attributes[attribute];
                }
            }
        }
        return "Failed to find label";
    },
    getHtml: function(resultSet) {
        if(resultSet.customResultSetDisplayHandler && resultSet.customResultSetDisplayHandler.getCustomResultSetDisplayHtml) {
            var arrayOfHtml = [];
            arrayOfHtml[0] = resultSet.customResultSetDisplayHandler.getCustomResultSetDisplayHtml(this);
            return arrayOfHtml;
        }
    
    
        var features = resultSet.features;
        var mdotLayer = resultSet.mdotLayer;
        var geometry = resultSet.queryGeometry;
        var identifyOptions = resultSet.identifyOptions;
        var bMouseOver = (resultSet.identifyOptions.selectionDisplayType && resultSet.identifyOptions.selectionDisplayType == selectionDisplayType.selectionDisplayTypeSingleFeature) &&
                         (!identifyOptions.resultSetDisplayType || (identifyOptions.resultSetDisplayType == resultSetDisplayType.resultSetDisplayTypeList || identifyOptions.resultSetDisplayType == resultSetDisplayType.resultSetDisplayTypeInfoWindow));
        
        var arrayOfHtml = new Array();
        var bHideDefaultIdentifyHtml = false;
        var bHasAdditionalIdentifyHtml = false;
        
        var identifyResultCssClassName = "identifyResult";
        var identifyLabelCssClassName = "identifyLabel";
        var identifyValueCssClassName = "identifyValue";
        
        if(identifyOptions) {
            identifyResultCssClassName = mdot.mapping.framework.Util.getData(identifyOptions.identifyResultCssClassName, identifyResultCssClassName);
            identifyLabelCssClassName = mdot.mapping.framework.Util.getData(identifyOptions.identifyLabelCssClassName, identifyLabelCssClassName);
            identifyValueCssClassName = mdot.mapping.framework.Util.getData(identifyOptions.identifyValueCssClassName, identifyValueCssClassName);
            
            bHideDefaultIdentifyHtml = mdot.mapping.framework.Util.getData(identifyOptions.hideDefaultIdentifyHtml, false);
            bHasAdditionalIdentifyHtml = mdot.mapping.framework.Util.getData(identifyOptions.additionalIdentifyHtml, "").length > 0;
        }
        
        for(var index = 0; index < features.length; index++) {
            var html = '';
            if(!bHideDefaultIdentifyHtml) {
                var onmouseover = '';
                var onmouseout = '';
                
                if(bMouseOver) {
                    onmouseover = ' onmouseover="mdot.mapping.framework.ResultSetDisplay.getInstance().displayGraphic(' + index + ', false);"';
                    onmouseout = ' onmouseout="mdot.mapping.framework.ResultSetDisplay.getInstance().clearGraphic(' + index + ');"';
                }
                var html = '<table cellspacing="0" class="' + identifyResultCssClassName + '"' + onmouseover + onmouseout + '>';
                
                if(resultSet.fields) {
                    for(var fieldIndex = 0; fieldIndex < resultSet.fields.length; fieldIndex++) {
                        html += this.getFeatureHtml(features[index], resultSet.fields[fieldIndex], mdotLayer, identifyLabelCssClassName, identifyValueCssClassName);
                    }
                }
                else {
                    for(var attribute in features[index].attributes) {
                        html += this.getFeatureHtml(features[index], attribute, mdotLayer, identifyLabelCssClassName, identifyValueCssClassName);
                    }
                }
                html += '</table>';
            }
            if(bHasAdditionalIdentifyHtml) {
                var additionalHtml = identifyOptions.additionalIdentifyHtml;                
                additionalHtml = mdot.mapping.framework.Util.scrubFeature(features[index], additionalHtml, index);
                html += additionalHtml;
            }
            arrayOfHtml[arrayOfHtml.length] = html;
        }
        return arrayOfHtml;
    },
    getFeatureHtml: function(feature, attribute, mdotLayer, identifyLabelCssClassName, identifyValueCssClassName) {
        var html = '';
        
        if(this.resultSet.customResultSetDisplayHandler && this.resultSet.customResultSetDisplayHandler.getCustomResultSetDisplayMdotLayer) {
            var tempLayer = this.resultSet.customResultSetDisplayHandler.getCustomResultSetDisplayMdotLayer(this.resultSet, feature);
            if(tempLayer) {
                mdotLayer = tempLayer;
            }
        }
        
        if(!this.canDisplayField(mdotLayer, attribute)) {
            return html;
        }
        
        html += '<tr><td class="' + identifyLabelCssClassName + '">' + this.getFieldDisplayLabel(mdotLayer, attribute); +  ':</td>';
        
        var value = feature.attributes[attribute];
        if(value && typeof(value) == 'string') {
            var tempValue = value.toLowerCase();
            var httpIndex = tempValue.indexOf('http');
            if(httpIndex > -1) {
                var urlValue = '';
                var urlLabel = '';
                if(httpIndex == 0) {
                    urlValue = value;
                    urlLabel = '[url]';
                }
                else {
                    var endIndex = tempValue.indexOf('"', httpIndex);
                    if(endIndex > -1) {
                        urlValue = value.substring(httpIndex, endIndex);
                        
                        var startIndex = tempValue.indexOf('>', endIndex);
                        if(startIndex > -1) {
                            endIndex = tempValue.indexOf('<', startIndex);
                            if(endIndex > -1) {
                                urlLabel = value.substring(startIndex + 1, endIndex);
                            }
                        }
                    }
                }
                
                if(urlValue != '') {
                    value = '<a href="#" onclick="javascript:window.open(\'' + urlValue + '\');return false;">' + urlLabel + '</a';
                }
            }
        }
        if(!value) {
            value = '&lt;Null&gt;'
        }
        html += '<td class="' + identifyValueCssClassName + '">' + value + '</td></tr>';
        return html;
    },
    canDisplayField: function(mdotLayer, fieldName) {
        if(!mdotLayer || !fieldName || !mdotLayer.fields) {
            return true;
        }
        
        for(var index = 0; index < mdotLayer.fields.length; index++) {
            if(mdotLayer.fields[index].name == fieldName) {
                if(mdotLayer.fields[index].hide) {
                    return false;
                }
                else {
                    return true;
                }
            }
        }
        
        return true;
    },
    clearResultSet: function() {
        this.clearGraphics();
        var id = "ResultSetDisplay.dialog";
        if(dijit.byId(id)) {
            dijit.byId(id).close();
        }
    },
    clearGraphics: function() {
        if(this.userClickGraphic) {
            this.map.graphics.remove(this.userClickGraphic);
        }
        
        if(this.graphics) {
            for(var index = 0; index < this.graphics.length; index++) {
                if(this.graphics[index] != null) {
                    this.map.graphics.remove(this.graphics[index]);
                }
            }
        }
        this.graphics = new Array();
    },
    displayGraphic: function(index, canZoomToFeature) {
        if(this.userClickGraphic) {
            this.map.graphics.remove(this.userClickGraphic);
        }
        if(this.resultSet.identifyOptions.selectionDisplayType == selectionDisplayType.selectionDisplayTypeSingleFeature) {
            //remove all other graphics from the map...
            for(var index2 = 0; index2 < this.graphics.length; index2++) {
                if(this.graphics[index2] && index2 != index) {
                    this.map.graphics.remove(this.graphics[index2]);
                }
            }
        }
            
        var graphic = this.graphics[index];
        if(!graphic) {
            var selectionSymbol = null;
            
            if(this.resultSet.customResultSetDisplayHandler && this.resultSet.customResultSetDisplayHandler.getCustomResultSetDisplaySymbol) {
                selectionSymbol = this.resultSet.customResultSetDisplayHandler.getCustomResultSetDisplaySymbol(this.resultSet, index);
            }
            else {
                selectionSymbol = eval(this.resultSet.identifyOptions.selectionSymbol);
            }
            
            graphic = this.resultSet.features[index];
            graphic.symbol = selectionSymbol;
            this.graphics[index] = graphic;
        }
        this.map.graphics.add(graphic);
        
        if(this.userClickGraphic) {
            this.map.graphics.add(this.userClickGraphic);
        }
        
        if(canZoomToFeature && this.resultSet.identifyOptions.zoomToSelectionType == zoomToSelectionType.zoomToSelectionTypeSingle || this.resultSet.identifyOptions.zoomToSelectionType == zoomToSelectionType.zoomToSelectionTypeBoth) {
            this.zoomToGraphic[index];
        }
    },
    zoomToGraphic: function(index) {
        var graphic = this.resultSet.features[index];
        mdot.mapping.framework.Util.setExtent([graphic], this.map, this.defaultScaleForZoom);
    },
    clearGraphic: function(index) {
        this.map.graphics.remove(this.graphics[index]);
        this.graphics[index] = null;
    },
    getDisplayLocation: function(resultSet) {
        if(resultSet.clientEvent) {
            //resultSet was generated via a click on the screen.
            //return the user's click location.
            return resultSet.clientEvent.screenPoint;
        }
        else {
            if(this.dockingPoint) {
                return this.dockingPoint;
            }
            else {
                //resultSet was generated from an attribute query.
                //get the extent of the features and return the center of the extent in screen coordintates.
                var extent = mdot.mapping.framework.Util.getExtent(resultSet.features);
                var center = this.map.toScreen(extent.getCenter());
                return center;
            }
        }
    },
    defaultDisplayHandler: function(map, resultSet, displayLocation) {
        this.hide();
        var pResultSetDisplayType = mdot.mapping.framework.Util.getData(resultSet.identifyOptions.resultSetDisplayType, resultSetDisplayType.resultSetDisplayTypeList);
        var width = resultSet.identifyOptions.resultSetDisplayWidth;
        var height = resultSet.identifyOptions.resultSetDisplayHeight;
        this.show(map, resultSet, pResultSetDisplayType, width, height, displayLocation);
    }
});
//end ResultSetDisplay.js

//begin StatusDialog.js
var g_progressBarCount = 0;
dojo.declare("mdot.mapping.framework.StatusDialog", null, {
    constructor: function(mapApp, statusDialogConfig) {
        var ref = this;
        this.id = "StatusDialog_" + new Date().getTime();
        this.messageId = this.id + "_Message";
        this.progressBarId = this.id + "_ProgressBar_" + g_progressBarCount++;
        var id = this.id;
        
        var title = statusDialogConfig.title;
        var initialMessage = statusDialogConfig.initialMessage;
        var width = statusDialogConfig.width;
        var height = statusDialogConfig.height;
        var useProgressBar = statusDialogConfig.useProgressBar;
        var maxProgressBarValue = statusDialogConfig.maxProgressBarValue;
        var progressBarWidth = statusDialogConfig.progressBarWidth;
        var messageClassName = mdot.mapping.framework.Util.getString(statusDialogConfig.messageClassName, 'statusDialogMessage');
        
        if (!dijit.byId(id)){
            var containerId = id + ".container";
            var container = dijit.byId(containerId);
            if(!dijit.byId(containerId)) {
                container = document.createElement("div");
                container.id = containerId;
                container.name = container.id;
                document.body.appendChild(container);
            }
            
            width = parseInt(mdot.mapping.framework.Util.getData(width, "500"));
            height = parseInt(mdot.mapping.framework.Util.getData(height, "350"));
            var point = mapApp.getCenterDockingPoint(width, height);
            var dialog = new dojox.layout.FloatingPane({
                                        title: title,
                                        id: this.id,
                                        href: null,
                                        closeable: true,
                                        resizable: true,
                                        duration: 0,
                                        hasShadow: true,
                                        dockable: false}, container);
            //dialog.closeNode.className = "dijitDialogCloseIcon";
            dialog.focusNode.className = "dijitDialogTitleBar";
            dialog.titleNode.className = "dijitDialogTitle";
            dialog.domNode.className = "dijitDialog";
                    
            dialog.domNode.style.position = "absolute";
            dialog.domNode.style.width = width;
            dialog.domNode.style.height = height;
            dialog.domNode.style.left = point.x;
            dialog.domNode.style.top = point.y;
            
            var html = '';
            html += '<div>';
            html += '<table style="width:100%;height:100%;"><tr valign="middle"><td align="center">';
            html += '<span class="' + messageClassName + '" id="' + this.messageId + '">';
            if(initialMessage) {
                html += initialMessage;
            }
            html += '</span><br/>';
            
            if(useProgressBar) {            
                html += '<div dojoType="dijit.ProgressBar" style="width:' + progressBarWidth + 'px;" id="' + this.progressBarId + '" maximum="' + maxProgressBarValue + '" progress="0"></div>';
            }
            
            html += '</td></tr></table>';
            html += '</div>';
            
            dialog.setContent(html);
            dialog.startup();
        }
        else {
            var dialog = dijit.byId(id);
            dialog.show();
        }
    },
    setMessage: function(msg) {
        var label = dojo.byId(this.messageId);
        if(label) {
            label.innerHTML = msg;
        }
    },
    incrementProgressBar: function() {
        var progressBar = dijit.byId(this.progressBarId);
        if(progressBar) {
            var currentProgress = progressBar.progress;
            progressBar.update({ progress: currentProgress + 1 });
        }
    },
    kill: function() {
        var dialog = dijit.byId(this.id);
        if(dialog) {
            dialog.destroyRecursive();
        }
    }
});
//end StatusDialog.js

//begin MapService.js
dojo.declare("mdot.mapping.framework.MapService", null, {
    constructor: function(mapApplication, mapServiceConfig, onMapServiceLoadedHandler) {
        this.esriMapServiceLayer = null;
        this.mdotMapService = mapServiceConfig;
        this.name = mapServiceConfig ? mapServiceConfig.name : "no map service config!";
        this.legend = null;
        this.url = mapServiceConfig.url;
        this._visibleLayerIds = []; //array of layer info IDs...
        
        if(mapServiceConfig.mapServiceType == mapServiceType.mapServiceTypeTiled) {
            this.esriMapServiceLayer = new esri.layers.ArcGISTiledMapServiceLayer(mapServiceConfig.url, {
                id:mapServiceConfig.name,
                visible:mapServiceConfig.visible,
                opacity:mapServiceConfig.opacity ? mapServiceConfig.opacity : 1.0
            });
            onMapServiceLoadedHandler(this.esriMapServiceLayer, this);
        }
        else {
            this.esriMapServiceLayer = new esri.layers.ArcGISDynamicMapServiceLayer(mapServiceConfig.url, {
                id:mapServiceConfig.name,
                visible:mapServiceConfig.visible,
                opacity:mapServiceConfig.opacity ? mapServiceConfig.opacity : 1.0
            }); 
            
            if(!this.esriMapServiceLayer.loaded) { //IE workaround...
                var ref = this;
                dojo.connect(this.esriMapServiceLayer, "onLoad", function(layer) {                    
                    ref.esriMapServiceLayer = layer;
                    ref.loadMapServiceLayers(mapApplication, onMapServiceLoadedHandler);
                });
            }
            else {
                this.loadMapServiceLayers(mapApplication, onMapServiceLoadedHandler);
            }
        }
    },
    isDynamicMapService: function() {
        return this.esriMapServiceLayer != null && this.esriMapServiceLayer.declaredClass == "esri.layers.ArcGISDynamicMapServiceLayer";    
    },
    loadMapServiceLayers: function(mapApplication, onMapServiceLoadedHandler) {
        if(!this.isDynamicMapService()) {
            onMapServiceLoadedHandler(this.esriMapServiceLayer, this);
            return;
        }
        var visibleLayerIds = new Array();
        for(var index = 0; index < this.mdotMapService.layers.length; index++) {
            var layerInfo = null;
            
            if(this.mdotMapService.layers[index].visible || this.mdotMapService.layers[index].whereClause) {
                layerInfo = this.getLayerInfo(this.mdotMapService.layers[index].name);
            }
            
            if(!layerInfo) {
                continue;
            }
            
            if(this.mdotMapService.layers[index].visible) {
                visibleLayerIds[visibleLayerIds.length] = layerInfo.id;
            }
            
            if(this.mdotMapService.layers[index].whereClause) {
                var layerDefinitions = [];
                if(layerInfo.subLayerIds) {
                    for(var index2 = 0; index2 < layerInfo.subLayerIds.length; index2++) {
                        layerDefinitions[layerInfo.subLayerIds[index2]] = this.mdotMapService.layers[index].whereClause;
                    }
                }
                else {
                    layerDefinitions[layerInfo.id] = this.mdotMapService.layers[index].whereClause;
                }
                this.esriMapServiceLayer.setLayerDefinitions(layerDefinitions);
            }
        }
        
        if(visibleLayerIds.length > 0) {
            this.esriMapServiceLayer.setVisibleLayers(visibleLayerIds);
        }
        this._visibleLayerIds = visibleLayerIds;
        
        if(this.mdotMapService.layerDefinitions) {
            this.esriMapServiceLayer.setLayerDefinitions(this.mdotMapService.layerDefinitions);
        }
        
        if(!this.mdotMapService.legend || !this.mdotMapService.legend.load) {
            
        }
        else if(this.mdotMapService.legend && this.mdotMapService.legend.layers) {
            var layerIds = "";
            for(var index = 0; index < this.mdotMapService.legend.layers.length; index++) {
                var layerInfo  = this.getLayerInfo(this.mdotMapService.legend.layers[index].legendLayer);
                if(layerInfo != null) {
                    if(layerIds != "") {
                        layerIds += ",";
                    }
                    layerIds += layerInfo.id;
                }
            }
            
            var url = this.mdotMapService.legend.url;
            url = mdot.mapping.framework.Util.scrubString("layerIds", layerIds, url);
            
            var ref = this;
            mdot.mapping.framework.Util.ajaxRequest(url, function(legend) {
                ref.legend = legend;
            });
        }
        
        var ref = this;
        dojo.connect(this.esriMapServiceLayer, "setVisibleLayers", function(ids) {
            ref.onVisibleLayersChanged(this, ids);
        });
        
        dojo.connect(this.esriMapServiceLayer, "show", function() {
            ref.onMapServiceVisibilityChanged(ref.mdotMapService, ref.getVisibleLayerNames(), true);
        });
        
        dojo.connect(this.esriMapServiceLayer, "hide", function() {
            ref.onMapServiceVisibilityChanged(ref.mdotMapService, ref.getVisibleLayerNames(), false);
        });
        
        onMapServiceLoadedHandler(this.esriMapServiceLayer, this);
    },
    onVisibleLayersChanged: function(layer, visibleLayerIds) {
        //first find all of the layers that are being turned off...
        var layersBeingTurnedOff = [];
        for(var index = 0; index < this._visibleLayerIds.length; index++) {
            var bLayerStillOn = false;
            for(var index2 = 0; index2 < visibleLayerIds.length; index2++) {
                if(this._visibleLayerIds[index] == visibleLayerIds[index2]) {
                    bLayerStillOn = true;
                    break;
                }
            }
            
            if(!bLayerStillOn) {
                layersBeingTurnedOff[layersBeingTurnedOff.length] = this._visibleLayerIds[index];
            }
        }
        
        //then find all of the layers that are being turned on
        var layersBeingTurnedOn = [];
        for(var index = 0; index < visibleLayerIds.length; index++) {
            var bAlreadyOn = false;
            for(var index2 = 0; index2 < this._visibleLayerIds.length; index2++) {
                if(visibleLayerIds[index] == this._visibleLayerIds[index2]) {
                    bAlreadyOn = true;
                    break;
                }
            }
            
            if(!bAlreadyOn) {
                layersBeingTurnedOn[layersBeingTurnedOn.length] = visibleLayerIds[index];
            }
        }
        
        this._visibleLayerIds = visibleLayerIds;
        
        for(var index = 0; index < layersBeingTurnedOff.length; index++) {
            this.onLayerVisibilityChanged(layer, this.getLayerInfoById(layersBeingTurnedOff[index]).name, false);
        }
        
        for(var index = 0; index < layersBeingTurnedOn.length; index++) {
            this.onLayerVisibilityChanged(layer, this.getLayerInfoById(layersBeingTurnedOn[index]).name, true);
        }
    },
    onLayerVisibilityChanged: function(mapService, layerName, bVisible) {
        //this function exists for clients who want to listen to the layer info visibility change event...
    },
    onMapServiceVisibilityChanged: function(mapService, visibleLayerNames, bVisible) {
        //this function exists for clients who want to listen to the map service visibility change event...
    },
    getLegendLayerConfig: function(layerName) {
        var legendLayerConfig = null;
        
        if(this.mdotMapService.legend && this.mdotMapService.legend.layers) {
            for(var index = 0; index < this.mdotMapService.legend.layers.length; index++) {
                if(this.mdotMapService.legend.layers[index].name == layerName) {
                    legendLayerConfig = this.mdotMapService.legend.layers[index];
                    break;
                }
            }
        }
        return legendLayerConfig;
    },
    getLegendImageUrl: function(mapApplication, layerName, successHandler, errorHandler) {
        this.getLegendForLayer(mapApplication, layerName,
            function(legend) {
                var legendImageUrl = "";
                if(legend && legend.legendLayers && legend.legendLayers.length > 0) {
                    legendImageUrl = legend.legendLayers[0].legendItems[0].url;
                }
                successHandler(legendImageUrl);            
            },
            errorHandler);
    },
    getLegendForLayer: function(mapApplication, layerName, successHandler, errorHandler) {
        if(this.mdotMapService.legend && this.mdotMapService.legend.layers) {
            var layerIds = "";
            for(var index = 0; index < this.mdotMapService.legend.layers.length; index++) {
                if(this.mdotMapService.legend.layers[index].name == layerName) {
                    var legendLayerNames = this.mdotMapService.legend.layers[index].legendLayer.split(',');
                    for(var index2 = 0; index2 < legendLayerNames.length; index2++) {
                        var layerInfo  = this.getLayerInfo(legendLayerNames[index2]);
                        if(layerInfo != null) {
                            if(layerIds != "") {
                                layerIds += ",";
                            }
                            layerIds += layerInfo.id;
                        }
                    }
                    break;
                }
            }
            
            var url = this.mdotMapService.legend.url;
            url = mdot.mapping.framework.Util.scrubString("layerIds", layerIds, url);
            mdot.mapping.framework.Util.ajaxRequest(url, successHandler, errorHandler);
        }        
    },
    onMapServiceLayersLoaded: function(source, esriMapService) {
        //source.esriMapService = esriMapService;
    },
    getLegendItems: function(layerName) {
        if(!this.isDynamicMapService() || this.legend == null) {
            return null;
        }
        
        if(this.mdotMapService.legend && this.mdotMapService.legend.layers) {
            var layerIds = "";
            for(var index = 0; index < this.mdotMapService.legend.layers.length; index++) {
                if(this.mdotMapService.legend.layers[index].name == layerName) {
                    for(var index2 = 0; index2 < this.legend.legendLayers.length; index2++) {
                        if(this.legend.legendLayers[index2].name == this.mdotMapService.legend.layers[index].legendLayer) {
                            return this.legend.legendLayers[index2].legendItems;
                        }
                    }
                }
            }
        }
        return null;
    },
    getLayerInfo: function(layerName) {
        if(!this.isDynamicMapService()) {
            return null;
        }
        
        for(var index = 0; index < this.esriMapServiceLayer.layerInfos.length; index++) {
            if(this.esriMapServiceLayer.layerInfos[index].name == layerName) {
                return this.esriMapServiceLayer.layerInfos[index];
            }
        }
        
        return null;
    },
    getLayerInfoById: function(layerInfoId) {
        if(!this.isDynamicMapService()) {
            return null;
        }
        
        for(var index = 0; index < this.esriMapServiceLayer.layerInfos.length; index++) {
            if(this.esriMapServiceLayer.layerInfos[index].id == layerInfoId) {
                return this.esriMapServiceLayer.layerInfos[index];
            }
        }
        
        return null;
    },
    getVisibleLayerNames: function() {
        var layerNames = [];
        for(var index = 0; index < this._visibleLayerIds.length; index++) {
            var layerInfo = this.getLayerInfoById(this._visibleLayerIds[index]);
            var layerName = "";
            if(layerInfo != null) {
                layerName = layerInfo.name;
            }
            layerNames[layerNames.length] = layerName;
        }
        return layerNames;
    },
    getVisibleLayerIds: function() {
        return this._visibleLayerIds;
    },
    hasVisibleLayer: function() {
        return this._visibleLayerIds != null && this._visibleLayerIds.length > 0;
    }
});

//end MapService.js

//begin Toolbar.js
dojo.declare("mdot.mapping.framework.Toolbar", null,
{
    constructor: function(mapApplication) {
        this.mapApplication = mapApplication;
        this.toolbarItems = new Array();
    },
    load: function() {
        if(!this.mapApplication.mapApplicationConfig.toolbar || !this.mapApplication.mapApplicationConfig.toolbar.toolbarItems) {
            return;
        }
        
        var toolbarItems = this.mapApplication.mapApplicationConfig.toolbar.toolbarItems;
        for(var index = 0; index < toolbarItems.length; index++) {
            var toolbarItemConfig = toolbarItems[index];
            var name = toolbarItemConfig.javaScriptClassName;
            var ctor = 'new ' + name + '(this)';
            
            try {
                var toolbarObject = eval(ctor);
                this.toolbarItems[this.toolbarItems.length] = toolbarObject;
            }
            catch(e) {
                continue;
            }
            
            if(toolbarItemConfig.customLoadFunction) {
                var f = eval(toolbarItemConfig.customLoadFunction);
                f(customLoadFunction);
            }
            else {
                this.toolbarItems[this.toolbarItems.length-1].load(toolbarItemConfig);
            }
        }
        
        for(var index = 0; index < this.toolbarItems.length; index++) {
            this.toolbarItems[index].onToolbarLoaded();
        }
    },
    add: function(toolbarItem, toolbarItemConfig) {
        var bHasParentId = (toolbarItemConfig && toolbarItemConfig.parentId) ? true : false;
        var parentElement = bHasParentId ? dojo.byId(toolbarItemConfig.parentId) : null;
        if(parentElement != null) {
            if(dojo.isString(toolbarItem)) {
                parentElement.innerHTML += toolbarItem;
            }
            else {
                parentElement.appendChild(toolbarItem);
            }            
        }
        else {
            //alert('Failed to add toolbar item!'); 
        }
    },
    findToolbarItem: function(name) {
        for(var index = 0; index < this.toolbarItems.length; index++) {
            if(this.toolbarItems[index].toolbarItemConfig.name == name) {
                return this.toolbarItems[index];
            }
        }
        return null;
    }
});

//end Toolbar.js

//begin ToolbarItem.js
//helper object for client applications.
var __toolbarItems = new Array();

dojo.declare("mdot.mapping.framework.ToolbarItem", null, {
    constructor: function(toolbar) {
        this.toolbar = toolbar;
        this.enabled = true;
        this.hidden = false;
        this.customSettings = new Array();
        this.toolbarItemConfig = null;
    },
    load: function(toolbarItemConfig) {
        this.toolbarItemConfig = toolbarItemConfig;
        __toolbarItems[this.toolbarItemConfig.name] = this;
        if(toolbarItemConfig.customSettings) {
            for(var index = 0; index < toolbarItemConfig.customSettings.length; index++) {
                this.customSettings[toolbarItemConfig.customSettings[index].name] = toolbarItemConfig.customSettings[index].value;
            }
        }
        this.onToolbarItemLoaded();
    },
    onToolbarItemLoaded: function() {},
    onToolbarLoaded: function() {},
    setEnabled: function(enabled) {
        this.enabled = enabled;
        this.updateAppearance();
    }, 
    getMap: function() {
        return this.toolbar.mapApplication.map;
    },
    getApp: function() {
        return this.toolbar.mapApplication;
    }
});
//end ToolbarItem

//begin Command.js
dojo.declare("mdot.mapping.framework.Command", mdot.mapping.framework.ToolbarItem, {
    constructor: function(toolbar) {
        this.checked = false;   
        this.img = null;
        this.isOnMouseOver = false;
        this.defaultImageUrl = null;       
        this.defaultImageUrlHover = null;
        this.checkedImageUrl = null;
        this.disabledImageUrl = null;
        this.isDropDownButton = false;
        this.dropDownButtonInnerHtml = null;
        this.dropDownButtonOnLoadFunction = null;
        this.dropDownButtonOnExecuteFunction = null;
        
    },
    load: function(toolbarItemConfig) {
        this.inherited(arguments);
        if(toolbarItemConfig.hidden) {
            return;
        }
        
        var ref = this;
        
        if(toolbarItemConfig.parentId) {
            var pButtonType = mdot.mapping.framework.Util.getData(toolbarItemConfig.buttonType, buttonType.buttonTypeDefault, buttonType.buttonTypeDefault);
            switch(pButtonType) {
                case buttonType.buttonTypeDefault:
                    this.defaultImageUrl = toolbarItemConfig.defaultImageUrl;
                    this.defaultImageUrlHover = toolbarItemConfig.defaultImageUrlHover;
                    this.checkedImageUrl = toolbarItemConfig.checkedImageUrl;
                    this.disabledImageUrl = toolbarItemConfig.disabledImageUrl;
                
                    this.img = document.createElement('img');
                    this.img.ID = toolbarItemConfig.name;
                    this.img.name = toolbarItemConfig.name;
                    this.img.title = toolbarItemConfig.label;
                    this.updateAppearance();                    
                    
                    dojo.connect(this.img, "onmouseover", function(){ref.onButtonMouseOver();});
                    dojo.connect(this.img, "onmouseout", function(){ref.onButtonMouseOut();});
                    dojo.connect(this.img, "onmousedown", function(){ref.onButtonMouseDown();});
                    dojo.connect(this.img, "onmouseup", function(){ref.onButtonMouseUp();});
                    
                    if(toolbarItemConfig.addLabel) {
                        var label = document.createElement('span');
                        label.innerHTML = toolbarItemConfig.label;
                        label.className = toolbarItemConfig.cssClassName;
                        this.toolbar.add(label, toolbarItemConfig);
                    }                    
                    this.toolbar.add(this.img, toolbarItemConfig);
                    break;
                case buttonType.buttonTypeSimple:
                    var onClickFunction = null;
                    if(this.isTool) {
                        onClickFunction = function() {
                            ref.getApp().setCurrentTool(ref);
                        };
                    }
                    else {
                        onClickFunction = mdot.mapping.framework.Util.getData(this.customSettings["onClickFunction"], "alert('" + toolbarItemConfig.name + " does not have the property onClickFunction properly set!')");
                    }
                    
                    var button = document.createElement('button');
                    button.id = toolbarItemConfig.name + '_button';
                    button.innerHTML = toolbarItemConfig.label;
                    button.onclick = typeof(onClickFunction) == 'string' ? function() {eval(onClickFunction)} : onClickFunction;
                    this.toolbar.add(button, toolbarItemConfig);
                    break;
                case buttonType.buttonTypeDropDown:
                    //Required custom settings:
                    //dropDownCommand: JavaScript Class name for object that implements AbstractDropDownCommand
                    var dropDownCommandClassName = this.customSettings["dropDownCommand"];
                    var dropDownCommand = eval("new "+ dropDownCommandClassName + "()");
                    if(!dropDownCommand) {
                        alert('Failed to create an instance of ' + dropDownCommandClassName + '!');
                        return;
                    }
                    
                    var content = document.createElement('div');
                    var innerContent = dropDownCommand.getTooltipDialogContent(ref, content);
                    if(dojo.isString(innerContent)) {
                        content.innerHTML = innerContent;
                    }
                    else {
                        content.appendChild(innerContent);
                    }
                    
                    var id = toolbarItemConfig.name + '.Dialog';
                    this.dropDownDialog = new dijit.TooltipDialog({
                        id: id,
                        preventCache:true,
                        refreshOnShow:true
                        }, content);
                    dropDownCommand.afterContentAdded();
                        
                    dojo.connect(ref.dropDownDialog, "onOpen", function() {
                        content = document.createElement('div');
                        innerContent = dropDownCommand.getTooltipDialogContent(ref, content);
                        if(dojo.isString(innerContent)) {
                            content.innerHTML = innerContent;
                        }
                        else {
                            content.appendChild(innerContent);
                        }
                        ref.dropDownDialog.containerNode.innerHTML = '';
                        ref.dropDownDialog.containerNode.appendChild(content);
                        dropDownCommand.afterContentAdded();
                    });
                    
                    var label = toolbarItemConfig.label ? toolbarItemConfig.label : toolbarItemConfig.name;
                    this.dropDownButton = new dijit.form.DropDownButton({
                        id: id + '.Button',
                        label: label,
                        dropDown: ref.dropDownDialog});
                    this.toolbar.add(this.dropDownButton.domNode, toolbarItemConfig);
                    dropDownCommand.afterDropDownButtonAdded(this.dropDownButton);
                    break;
            }
        }
    },
    updateAppearance: function() {
        if(this.img) {
            if(this.checked) {
                this.img.src = this.checkedImageUrl;
            }
            else if(!this.enabled) {
                this.img.src = this.disabledImageUrl;
            }
            else {
                this.img.src = this.isOnMouseOver ? this.defaultImageUrlHover : this.defaultImageUrl;
            }
        }
    },
    execute: function() {
        if(this.toolbarItemConfig.onClickFunction) {
            eval(this.toolbarItemConfig.onClickFunction);
        }
        else {
            var msg = this.declaredClass + ' has not implemented "execute"!';
            alert(msg);
        }
    }, 
    onButtonMouseOver: function() {
        if(!this.isOnMouseOver) {
            this.isOnMouseOver = true;
            this.updateAppearance();
        }
    },  
    onButtonMouseOut: function() {
        this.isOnMouseOver = false;
        this.updateAppearance();
    },  
    onButtonMouseDown: function() {
        if(!this.enabled) {
            return;
        }
        this.updateAppearance();
    }, 
    onButtonMouseUp: function() {
        if(!this.enabled) {
            return;
        }
        this.execute();
        this.updateAppearance();
    },
    onBuddyControlChanged: function(comboBox) {
        var value = comboBox.getSelectedValue();
        this.setEnabled(!(!value || value == ''));
    }
});
//end Command.js

//begin Tool.js
dojo.declare("mdot.mapping.framework.Tool", mdot.mapping.framework.Command, {
    constructor: function(toolbar) {
        this.currentEvent = null; //current mouse event on the map...
        this.isTool = true;
    },
    execute: function() {
        this.getApp().setCurrentTool(this);
    },
    deactivate: function() {
        this.checked = false;
        this.updateAppearance();
    },
    activate: function() {
        this.checked = true;
        this.updateAppearance();
    },
    setEnabled: function(enabled) {
        this.enabled = enabled;
        if(!this.enabled) {
            if(this.getApp().currentTool == this) {
                this.getApp().setCurrentTool(null);
            }
        }
        this.updateAppearance();
    },
    onToolAction: function(geometry) {
        var msg = 'Tool: ' + this.declaredClass + ' has not implemented onToolAction.\n' + geometry.toString();
        alert(msg);
    }
}); 
//end Tool.js

//begin IdentifyTool.js
dojo.declare("mdot.mapping.framework.IdentifyTool", mdot.mapping.framework.Tool, {
    constructor: function(toolbar) {
        this.currentResultSet = null;
    },
    deactivate: function() {
        //override the deactivate method to close the result set display dialog, if it is opened
        var resultSetDisplayDialog = mdot.mapping.framework.ResultSetDisplay.getInstance();
        resultSetDisplayDialog.hide();
        this.inherited(arguments);
    },
    getIdentifyOptions: function(layerName) {
        return this.getApp().getIdentifyOptions(layerName);
    },
    getSubFields: function(layerName) {    
        var identifyOptions = this.getIdentifyOptions(layerName);
        if(identifyOptions == null) {
            return null;
        }
        
        var subfields = new Array();
        for(var index = 0; index < identifyOptions.subfields.length; index++) {
            subfields[subfields.length] = identifyOptions.subfields[index].name;
        }
        return subfields;
    },
    getQueryGeometry: function(geometry, identifyOptions) {
        var queryGeometry = geometry;
        switch(this.toolbarItemConfig.toolAction) {
            case toolAction.toolActionPoint:
                var tolerance = identifyOptions.tolerance;
                if(tolerance != null) {
                    //create an envelope for the geometry...
                    tolerance = parseInt(tolerance);
                    queryGeometry = mdot.mapping.framework.Util.pointToEnvelope(geometry, tolerance, this.getMap());
                }        
                break;
        }
        return queryGeometry;
    },
    onToolAction: function(evt, geometry) {
        var resultSetDisplayDialog = mdot.mapping.framework.ResultSetDisplay.getInstance();
        resultSetDisplayDialog.hide();
        
        var identifySource = this.toolbarItemConfig.identifySource;
        if(!identifySource) {
            //this.identifyAll(evt, geometry, 0, new Array());
            return;
        }
        
        var layerName = null;
        var control = this.toolbar.findToolbarItem(identifySource);
        if(control == null) {
            //try to get a layer instead...
            var testLayer = this.getApp().findLayer(identifySource);
            if(testLayer == null) {
                //check to see if this is a custom data source...
                var customDataSourceConfig = this.getApp().findCustomDataSource(identifySource);
                if(customDataSourceConfig) {
                    var customDataSource = this.getApp().createCustomDataSource(identifySource);
                    if(customDataSource) {
                        customDataSource.onIdentify(evt, geometry);
                        return;
                    }
                }
                else {
                    alert('Failed to find control named ' + identifySource + '.');
                    return;
                }
            }
            else {
                layerName = identifySource;
            }
        }
        else {
            if(!control.getValue) {
                alert(identifySource + ' does not implement "getValue()"');
                return;
            }
            else {
                layerName = control.getValue();
            }
        }
        
        //check to see if this is a custom data source...
        var customDataSourceConfig = this.getApp().findCustomDataSource(layerName);
        if(customDataSourceConfig) {
            var customDataSource = this.getApp().createCustomDataSource(layerName);
            if(customDataSource) {
                customDataSource.onIdentify(evt, geometry);
                return;
            }
        }
        
        var identifyOptions = this.getIdentifyOptions(layerName);
        if(identifyOptions == null) {
            alert(this.toolbarItemConfig + ' does not have "identifyOptions" properly configured!');
            return;
        }
        
        var ref = this;
        var statusDialogConfig = this.customSettings["statusDialog"];
        mdot.mapping.framework.QueryEngine.spatialQuery(this.getApp(), 
                                                        evt, 
                                                        this.getQueryGeometry(geometry, identifyOptions), 
                                                        identifyOptions,
                                                        statusDialogConfig,
                                                        function(resultSet) {
                                                            ref.onIdentify(resultSet);
                                                        });
    },
    onIdentify: function(resultSet) {
        this.currentResultSet = resultSet;
        var functions = this.getApp().getToolEventListenerFunctions(this.toolbarItemConfig.name, "onIdentify");
        if(functions != null && functions.length > 0) {
            for(var index = 0; index < functions.length; index++) {
                functions[index](resultSet);
            }
            return;
        }
        
        if(this.toolbarItemConfig.onIdentify) {
            this.toolbarItemConfig.onIdentify(resultSet);
            return;
        }
        
        this.displayIdentifyResults(resultSet);
    },
    onIdentifyMultiple: function(resultSets) {
        var functions = this.getApp().getToolEventListenerFunctions(this.toolbarItemConfig.name, "onIdentifyMultiple");
        if(functions != null && functions.length > 0) {
            for(var index = 0; index < functions.length; index++) {
                functions[index](resultSets);
            }
        }
        else {
            alert('TODO\nResult Set:\n' + resultSets.length);
        }
    },
    displayIdentifyResults: function(resultSet) {
        if(resultSet && resultSet.clientEvent && resultSet.clientEvent.mapPoint && this.getApp().mapApplicationConfig.geometryServiceUrl) {
            var ref = this;
            var geometryService = new esri.tasks.GeometryService(this.getApp().mapApplicationConfig.geometryServiceUrl);
            var outputSpatialReference = new esri.SpatialReference({"wkid" : 4326});
            var graphics = [];
            graphics[0] = new esri.Graphic(resultSet.clientEvent.mapPoint);
            
            geometryService.project(graphics, outputSpatialReference, function(projectedGraphics) {
                if(projectedGraphics.length > 0) {
                    resultSet.latlon = projectedGraphics[0].geometry;
                }
                mdot.mapping.framework.ResultSetDisplay.getInstance().defaultDisplayHandler(ref.getMap(), resultSet);
            });
        }
        else {
            mdot.mapping.framework.ResultSetDisplay.getInstance().defaultDisplayHandler(this.getMap(), resultSet);
        }
    }
});    
//end IdentifyTool.js

dojo.declare("mdot.mapping.framework.MultiLayerIdentifyDataSource", null, {
    constructor: function() {
        this.mapApplication = null;
        this.resultSet = null;
        this.geometry = null;
        this.displayOptions = null;
        this.displayLocation = null;
        this.layers = null;
        //TODO - throw this into config file and add a variable in enums class
        this.identifyType = 2; //0 - identify all layers, 1 - identify topmost layer, 2- identify visible layers
        this.errorMessage = null;
        this.statusDialogConfig = null;
        this.customDataSourceConfig = null;
        this.symbols = [];
        this.labels = [];
    },
    load: function(mapApplication, customDataSourceConfig) {
        this.mapApplication = mapApplication;
        this.customDataSourceConfig = customDataSourceConfig;
        
        if(customDataSourceConfig && customDataSourceConfig.customSettings) {
            for(var index = 0; index < customDataSourceConfig.customSettings.length; index++) {
                switch(customDataSourceConfig.customSettings[index].name) {
                    case "displayOptions":
                        this.displayOptions = customDataSourceConfig.customSettings[index].value;
                        break;
                    case "layers":
                        this.layers = customDataSourceConfig.customSettings[index].value;
                        break;
                    case "errorMessage":
                        this.errorMessage = customDataSourceConfig.customSettings[index].value;
                        break;
                    case "statusDialog":
                        this.statusDialogConfig = customDataSourceConfig.customSettings[index].value;
                        break;
                }
            }
        }
        
        if(this.layers) {
            for(var index = 0; index < this.layers.length; index++) {
                var symbol = eval(this.layers[index].selectionSymbol);
                this.symbols[this.layers[index].identifyLayerName] = symbol;
                this.labels[this.layers[index].identifyLayerName] = this.layers[index].labelFieldName;
            }
        }
    },
    getQueryGeometry: function(geometry, identifyOptions) {
        var queryGeometry = geometry;
        var tolerance = identifyOptions.tolerance;
        if(tolerance != null) {
            //create an envelope for the geometry...
            tolerance = parseInt(tolerance);
            queryGeometry = mdot.mapping.framework.Util.pointToEnvelope(geometry, tolerance, this.mapApplication.map);
        }
        return queryGeometry;
    },
    onIdentify: function(evt, geometry) {
        //var resultSetDisplayDialog = mdot.mapping.framework.ResultSetDisplay.getInstance();
        //resultSetDisplayDialog.hide();
        
        var identifyLayers = [];
        for(var index = 0; index < this.layers.length; index++) {
            /*var identifyLayer = this.layers[index].layerName;
            if(this.layers[index].identifyLayerName) {
                identifyLayer = this.layers[index].identifyLayerName;
            }*/
            
            switch(this.identifyType) {
                case 2:
                    if(this.mapApplication.isLayerVisible(this.layers[index].layerName)) {
                        //layerNames[layerNames.length] = identifyLayer;
                        identifyLayers[identifyLayers.length] = this.layers[index];
                    }
                    break;
            }
        }
        
        if(identifyLayers.length == 0) {
            if(this.errorMessage) {
                alert(this.errorMessage);
            }
            return;
        }
        
        this.evt = evt;
        this.geometry = this.getQueryGeometry(geometry, this.displayOptions);
        this.resultSet = {
           "title":this.customDataSourceConfig.label,
           "features": [],
           "mdotLayer":null,
           "clientEvent": evt,
           "queryGeometry": this.geometry,
           "identifyOptions": this.displayOptions,
           "customResultSetDisplayHandler":this
        };
        this.identify(0, identifyLayers);
        
    },
    identify: function(layerIndex, identifyLayers) {
        if(layerIndex >= identifyLayers.length) {
            this.onIdentifyComplete();
            return;
        }
        var ref = this;
        var layerName = identifyLayers[layerIndex].layerName;
        var identifyLayerName = identifyLayers[layerIndex].identifyLayerName;
        var mdotLayer = this.mapApplication.findLayer(layerName);
        var layerLabel = mdotLayer ? mdotLayer.label : layerName;
        if(!layerLabel) {
            layerLabel = layerName;
        }
        this.resultSet.mdotLayer = mdotLayer;
        
        this.displayOptions.layerName = layerName;
        this.displayOptions.identifyLayerName = identifyLayerName;
        mdot.mapping.framework.QueryEngine.spatialQuery(this.mapApplication, 
                                                        this.evt, 
                                                        this.geometry, 
                                                        this.displayOptions,
                                                        this.statusDialogConfig,
                                                        function(resultSet) {
                                                           if(resultSet && resultSet.features) {
                                                               for(var index = 0; index < resultSet.features.length; index++) {
                                                                    resultSet.features[index].layerName = layerName;
                                                                    resultSet.features[index].identifyLayerName = identifyLayerName;
                                                                    resultSet.features[index].layerLabel = layerLabel;
                                                                    ref.resultSet.features[ref.resultSet.features.length] = resultSet.features[index];
                                                               }
                                                           }
                                                           ref.identify(layerIndex + 1, identifyLayers);
                                                       });
        
    },
    onIdentifyComplete: function() {
        if(this.customDataSourceConfig.onIdentify) {
            var f = eval(this.customDataSourceConfig.onIdentify);
            f(this.resultSet);
            return;
        }
        else {
            mdot.mapping.framework.ResultSetDisplay.getInstance().defaultDisplayHandler(this.mapApplication.map, this.resultSet, this.displayLocation);
        }
    },
    getCustomResultSetDisplayMdotLayer: function(resultSet, feature) {
        if(feature) {
            return this.mapApplication.findLayer(feature.layerName);
        }
        return null;
    },
    getCustomResultSetDisplaySymbol: function(resultSet, featureIndex) {
        if(resultSet.features && featureIndex > -1 && featureIndex < resultSet.features.length) {
            return this.symbols[resultSet.features[featureIndex].identifyLayerName];
        }
    },
    getCustomResultSetDisplayLabel: function(resultSet, featureIndex) {
        if(resultSet.features && featureIndex > -1 && featureIndex < resultSet.features.length) {
            var labelFieldName = this.labels[resultSet.features[featureIndex].identifyLayerName];
            var value = resultSet.features[featureIndex].attributes[labelFieldName];
            return resultSet.features[featureIndex].layerLabel + ' - ' + value;
        }
        else {
            return "No label";
        }
    }
});
//end MultiLayerIdentifyDataSource.js
