    if (typeof caliper == 'undefined')
        var caliper = {};

    if ( typeof caliper.select == "undefined" ) 
        caliper.select = {};    

    if ( typeof caliper.select.handler == "undefined" ) 
        caliper.select.handler = {};    
    
    if ( typeof caliper.select.util == "undefined" ) 
        caliper.select.util = {};   

    //select tool title and balloon help
    caliper.select.toolTitle   = "Select Map Features";
    caliper.select.toolBalloon = "By location: select the current layer, and then one of the tool buttons, e.g. 'Select by Circle', "+
                                 "then click and drag a circle on the map, and then choose the 'Add to Selection' (+) button. "+
                                 "By condition: Type a condition, such as 'ID > 100 & ID < 200', then hit the 'Add to Selection' (+) button.";


    caliper.select.LOCATION = 1;
    caliper.select.QUERY = 2;
    caliper.select.LOCATION_WIDTH = 250;
    caliper.select.QUERY_WIDTH = 250;
    caliper.select.LOCATION_HEIGHT = 130;
    caliper.select.QUERY_HEIGHT = 195;
    
    caliper.select.SELECT_WINDOW_HEIGHT = 500;
    caliper.select.SELECT_WINDOW_WIDTH = 510;
    
    caliper.select.DUMMY_FIELD = "Choose a field...";
    caliper.select.DUMMY_OPERATOR = "Operators...";
    caliper.select.DUMMY_VALUE = "Values...";
    
    caliper.select.CHECK_EDIT_COLUMN = 1;
    
    caliper.select.operators = new Array("+", "-", "*", "/", "=", "<>", "<", "<=", ">=", ">", "between", "like", "contains", "and", "or");
                                        //you may un-comment the following lines to show all functions
                                         //"format(,)", "left(,)", "len()", "lower()", "lpad(,)", "position(,)", "proper()", "right(,)", "rpad(,)", "string()",
                                         //"substring(,,)", "substitute(,,,)", "trim()", "upper()", "value()", "word(,)", "abs()", "acos()", "acosh()", "asin()",
                                         //"asinh()", "atan()", "atanh()", "atan2(,)", "ceil()", "cos()", "cosh()", "exp()", "factorial()", "floor()", "log()",
                                         //"log10()", "max(,)", "min(,)", "mod(,)", "pow(,)", "round(,)", "sign()", "sin()", "sinh()", "sqrt()", "tan()", "tanh()");

    caliper.select.Action = null;
    caliper.select.currentLayer = null;
    
    caliper.select.setIsEmpty = true;

    caliper.select.textAlign = "left";
    
    caliper.select.recordsValues = {};
    
    //*********************
    //Button click handler 
    //*********************
    caliper.select.hideSelectWindow = function() {
        CCUtil.hideToolbox({toolboxID: "SelectWindow", iconPath:"graphics/iconSelectWindow.png", iconPrompt:"Show Selected Records"});
        caliper.select.onClickSelectApply('Clear');
        if (caliper.map.shapeToolContainer) caliper.map.shapeToolContainer.clearAll();
        };
            
    caliper.select.hideSelectTool = function() {
        CCUtil.hideToolbox({toolboxID: "SelectBox", iconPath:"graphics/iconSelect.png", 
                            iconPrompt:"Show Map Feature Select Tool",
                            onMinimizeFunction: caliper.select.hideSelectToolPostprocess,
                            onIconClickFunction:caliper.select.showSelectToolPostprocess  });
        };
        
    caliper.select.hideSelectToolPostprocess = function() {
        jQuery("#SelectWindow").css("visibility", "hidden");
        caliper.select.toggleSelectingMethod(true);
        };
            
    caliper.select.showSelectToolPostprocess = function () {
        caliper.select.toggleSelectingMethod();
        
        };
        
    caliper.select.clickButtonDistance = function() {
        if (caliper.map.command != 'distance')
            jQuery("div.listener").trigger("MSG_clearTools");   
            
        caliper.map.command = 'distance';
        caliper.map.mouseUpHandler = "caliper.select.clickImageHandler(caliper.map.command)";
        caliper.map.selectButton(caliper.map.command);

        caliper.select.util.setItemsStatus(caliper.map.command);
        };
        
    caliper.select.clickButtonSelectCircle = function() {
        if (caliper.map.command != 'select_circle' && caliper.map.command != 'move_circle' )
            jQuery("div.listener").trigger("MSG_clearTools");   
            
        caliper.map.command = 'select_circle';
        caliper.map.mouseUpHandler = "caliper.select.clickImageHandler(caliper.map.command)";
        caliper.map.selectButton(caliper.map.command);

        caliper.select.util.setItemsStatus(caliper.map.command);
        };
        
    caliper.select.clickButtonMoveCircle = function() {
        if (caliper.map.command != 'select_circle' && caliper.map.command != 'move_circle' )
            jQuery("div.listener").trigger("MSG_clearTools");   
            
        caliper.map.command = 'move_circle';
        caliper.map.mouseUpHandler = "caliper.select.clickImageHandler(caliper.map.command)";
        caliper.map.selectButton(caliper.map.command);

        caliper.select.util.setItemsStatus(caliper.map.command);
        };
        
    caliper.select.clickButtonSelectPoint = function() {
        if (caliper.map.command != 'select_point')
            jQuery("div.listener").trigger("MSG_clearTools");   
            
        caliper.map.command = 'select_point';
        caliper.map.mouseUpHandler = "caliper.select.clickImageHandler(caliper.map.command)";
        caliper.map.selectButton(caliper.map.command);

        caliper.select.util.setItemsStatus(caliper.map.command);
        };
        
    caliper.select.clickButtonSelectLasso = function() {
        if (caliper.map.command != 'select_lasso')
            jQuery("div.listener").trigger("MSG_clearTools");   
            
        caliper.map.command = 'select_lasso';
        caliper.map.mouseUpHandler = "caliper.select.clickImageHandler(caliper.map.command)";
        caliper.map.selectButton(caliper.map.command);

        caliper.select.util.setItemsStatus(caliper.map.command);
        };
        
    caliper.select.onClickSelectClear = function() {
        jQuery("div.listener").trigger("MSG_clearTools");   
        
        caliper.select.util.setItemsStatus("clear");
        };
    
    caliper.select.onClickSelectApply = function(selection_action) {  
        var selectingString = null;
        var request = caliper.map.getArguments();
        var layerConfigFile;
    
        if (Array.indexOf(["Add","Drop", "Clear", "Zoom", "ShowHide"], selection_action) < 0) return;
        
        if (Array.indexOf(["Zoom", "ShowHide"], selection_action) >= 0 && caliper.select.setIsEmpty) return;
        
        var currentLayer = jQuery("#SelectControl_LayerList");
        var queryString = jQuery("#SelectControl_query_string");
        
        if (currentLayer[0].value == null || currentLayer[0].value == "") {
            alert("onClickSelectApply Current layer is not defined.");
            return;
            }
        
        if (Array.indexOf(["Clear", "Zoom", "ShowHide"], selection_action) >= 0) 
            request.Command = "Set Apply";

        if (typeof(selection_action) == 'undefined' || selection_action == null)
            selection_action = "Add";
        request.SelectingAction = selection_action;
                
        caliper.select.Action = selection_action;
                
        
        //request.SelectingAction = selection_action;
        
        layerConfigFile = currentLayer[0].value;
        
        request.CurrentLayerConfig = layerConfigFile;
        request.SelectionMethod = "Intersecting";
        
        if (caliper.select.selectMode == caliper.select.LOCATION && caliper.map.shapeToolContainer) {        
            if (caliper.map.command == "distance" || !currentLayer[0]) return;

            selectingString = caliper.map.shapeToolContainer.generateSelectingString();
            if (selectingString == "" && Array.indexOf(["Clear", "Zoom", "ShowHide"], selection_action) < 0) return;
            
            //show progress indicator (up to 15 seconds)    
            caliper.map.showProgressbar(15);

            //request.SelectingString = selectingString;
            if (request.Command.search(/circle/) > -1)
                request.Rect = selectingString;
            else if (request.Command.search(/point/) > -1)
                request.SelectingPoints = selectingString;
            else if (request.Command.search(/lasso/) > -1)
                request.LassoPoints = selectingString;
            
            caliper.mapService.DoMethod("SelectionTools.ApplySelecting", request, "MapControl.config" , "SelectControl" , caliper.select.handler.onCompleteSelectApply);
            }
        else if (caliper.select.selectMode == caliper.select.QUERY && queryString[0] && queryString[0].value != "") {
            //show progress indicator (up to 15 seconds)    
            caliper.map.showProgressbar(15);

            request.Command = "Set Apply";
            request.SelectingQuery = queryString[0].value;
            request.SelectByQuery = true;

            caliper.mapService.DoMethod("SelectionTools.ApplySelecting", request, "MapControl.config" , "SelectControl" , caliper.select.handler.onCompleteSelectApply);

            }
        };
    
    caliper.select.zoomToFeature = function(id) {
        var request = caliper.map.getArguments();

        request.ID = id;
        caliper.mapService.DoMethod("MapService.ZoomToRow", request, "MapControl.config" , "SelectControl" , caliper.select.handler.onComplateZoom);
        };
                
           
    caliper.select.clickImageHandler = function(command) {

        };
             
    caliper.select.clickChangeRadius = function() {
        var radius = jQuery ("#SelectControl_Distance");
        var THRESHOLD = 0.1;
        
        if (radius[0] && caliper.map.shapeToolContainer && caliper.map.shapeToolContainer.circle) {
            var r1 = parseFloat(radius[0].value);
            var adjusted_radius = caliper.map.shapeToolContainer.circle.update({r:r1, unit:"map_unit", mapScope: caliper.map.map_scope});
            
            //check if the desired radius is accepted
            var requestedRadius = parseFloat(radius[0].value);
            if (requestedRadius - adjusted_radius > THRESHOLD)
                alert("Selecting circle can not exceed the map boundary. Circle radius changed to "+adjusted_radius);
                
            if (adjusted_radius != null) radius[0].value = adjusted_radius;
            }
        };
      
    //interpret a carriage-return hit as the same as hiting the Set button, rather than a whole page reload
    caliper.select.testKey = function(evt) {
        var CARRIAGE_RETURN = 13; //key code for carriage return
        var hitReturn = false;

        if (dojo.isIE) 
        {
            if (window.event.keyCode == CARRIAGE_RETURN) hitReturn = true; 
        }
        else 
            if (evt.keyCode == CARRIAGE_RETURN) hitReturn = true; 

        if (hitReturn) {
            caliper.select.clickChangeRadius();
            return false;
            }
            
        return true;
        };
          
          
    caliper.select.toggleSelectingMethod = function(hideSelectTool) {
        if (caliper.select.selectMode == caliper.select.LOCATION) {

            jQuery('#SelectControl_distance_span').show();
            jQuery('#SelectControl_field_span').hide();
            jQuery('#SelectControl_field_span').css("height",1);
            jQuery('#SelectControl_spacer').css("height",20);
            jQuery('#SelectTable').css("width",caliper.select.LOCATION_WIDTH);
            jQuery('#SelectTable').css("height",caliper.select.LOCATION_HEIGHT);
            }
         else {
            jQuery('#SelectControl_distance_span').hide();
            if (hideSelectTool) {
                jQuery('#SelectControl_field_span').hide();
                }
            else {
                jQuery('#SelectControl_field_span').show();
                }
                
            jQuery('#SelectControl_field_span').css("height",60);
            jQuery('#SelectControl_spacer').css("height",31);
            jQuery('#SelectTable').css("width",caliper.select.QUERY_WIDTH);

            if (dojo.isIE) {
                jQuery('#SelectControl_query_string').attr("rows",4);
                }
            else jQuery('#SelectTable').css("height",caliper.select.QUERY_HEIGHT);

            if (!hideSelectTool) caliper.select.updateFields();
            }

        jQuery("div.listener").trigger("MSG_updateToolboxPosition",null);    
        };          

    //get number of selected features in current selection set,
    caliper.select.getSelectedFeatureNumbers = function() {
        var request = CCUtil.getGisdkProperties();
        request.SelectingAction = "Init";
        request.SelectionMethod = "Intersecting";
        request.CurrentLayerConfig = caliper.select.currentLayer;
         
        caliper.mapService.DoMethod("SelectionTools.ApplySelecting", request, "MapControl.config" , "SelectControl" , caliper.select.util.updateDbox);
        };
        
    //get list of fields of the current layer
    caliper.select.updateFields = function() {
        var currentLayer = jQuery("#SelectControl_LayerList");
        var queryString = jQuery("#SelectControl_query_string");
        var request = CCUtil.getGisdkProperties();
        
        if (caliper.select.selectMode == caliper.select.LOCATION) return;

        caliper.select.currentLayer = currentLayer.attr("value");    

        if (caliper.select.currentLayer == null || caliper.select.currentLayer == "") {
            alert("updateFields Current layer is not defined.");
            return;
            }
            
        request.CurrentLayerConfig = caliper.select.currentLayer;
        caliper.mapService.DoMethod("SelectionTools.GetLayerFields", request, "MapControl.config" , "SelectControl" , caliper.select.handler.onCompleteLayerFields);
        
        if (typeof(queryString[0]) == 'undefined') return;
        queryString[0].value = "";
        };
    
    //get list of pre-defined values current layer-field
    caliper.select.updateFieldValues = function(fieldIndex) {
        var currentLayer = jQuery("#SelectControl_LayerList");
        var request = CCUtil.getGisdkProperties();
        
        if (caliper.select.selectMode == caliper.select.LOCATION) return;

        caliper.select.currentLayer = currentLayer.attr("value");    
        
        if (caliper.select.currentLayer == null || caliper.select.currentLayer == "") {
            alert("updateFieldValues Current layer is not defined.");
            return;
            }

        if (typeof(fieldIndex) == 'NaN' || fieldIndex < 0 || currentLayer[0].value.toUpperCase().indexOf(".CONFIG") < 0) return;
        
        request.CurrentLayerConfig = caliper.select.currentLayer;
        request.CurrentFieldIndex = fieldIndex-1;
        
        caliper.mapService.DoMethod("SelectionTools.GetLayerFields", request, "MapControl.config" , "SelectControl" , caliper.select.handler.onCompleteFieldValues);
        
        };
    
    //insert field name to query string
    caliper.select.insertFieldToQuery = function() {
        var fieldList = jQuery("#SelectControl_FieldList");
        var queryString = jQuery("#SelectControl_query_string");

        if (typeof(queryString[0]) == 'undefined') return;
        if (fieldList[0].value == caliper.select.DUMMY_FIELD) return;  //"Choose a field..."
        
        if (fieldList[0].value == null || fieldList[0].value == "") {
            alert("No field name selected.");
            return;
            }
            
        queryString[0].value = queryString[0].value + " " + fieldList[0].value;        
        queryString[0].value = queryString[0].value.trim();
        queryString[0].focus();

        caliper.select.updateFieldValues(fieldList[0].selectedIndex);
        
        fieldList[0].options[0].text = " "+fieldList[0].value;
        fieldList[0].selectedIndex = 0;
        };
        
    //insert operator/function to query string
    caliper.select.insertOperatorToQuery = function() {
        var operatorList = jQuery("#SelectControl_OperatorList");
        var queryString = jQuery("#SelectControl_query_string");

        if (typeof(queryString[0]) == 'undefined') return;
        if (operatorList[0].value == caliper.select.DUMMY_OPERATOR) return;  //"Operators..."
        
        if (operatorList[0].value == null || operatorList[0].value == "") {
            return;
            }
            
        queryString[0].value = queryString[0].value + " " + operatorList[0].value;        
        queryString[0].value = queryString[0].value.trim();
        queryString[0].focus();
        };

    //insert field value to query string
    caliper.select.insertFieldValueToQuery = function() {
        var valueList = jQuery("#SelectControl_ValueList");
        var queryString = jQuery("#SelectControl_query_string");

        if (typeof(queryString[0]) == 'undefined') return;
        if (valueList[0].value == null || valueList[0].value == "" || valueList[0].value == caliper.select.DUMMY_VALUE) return;  //"Values..."
        
        queryString[0].value = queryString[0].value + " " + valueList[0].value;        
        queryString[0].value = queryString[0].value.trim();
        queryString[0].focus();

        valueList[0].options[0].text = " "+valueList[0].value;
        valueList[0].selectedIndex = 0;
        };
        
        
    caliper.select.startToolboxDragging = function() {
        if (CCUtil) CCUtil.startToolboxDragging("SelectBox");
        };
        
    caliper.select.startWindowDragging = function() {
        if (CCUtil) CCUtil.startToolboxDragging("SelectWindow");
        };
        
    //*********************
    //Message handler
    //*********************
    caliper.select.handler.updateDistance = function(event, arg) {
        var distance = 0;
        
        if (typeof arg == 'undefined' || arg == null) return;
        
        if (arg.distance_pixel && caliper.map.map_scope && caliper.map.map_width) {

            var scopeParts = caliper.map.map_scope.split(" ");
            if (scopeParts.length != 5) return;
            
            distance = Math.round(arg.distance_pixel * scopeParts[2] / caliper.map.map_width * 100) / 100;
            
            var distanceValue = jQuery("#SelectControl_Distance");
            if (typeof distanceValue[0] != 'undefined') distanceValue[0].value = distance;
            }
        else if (arg.area ) {
            if (CCUtil.getGisdkProperties("MapUnitsAbbr") == "km" && arg.area_sqkm) alert("Area = "+Math.round(arg.area_sqkm*100)/100 + " sq km");
            else alert("Area = "+Math.round(arg.area*100)/100 + " sq "+CCUtil.getGisdkProperties("MapUnitsAbbr"));
            }
        };
    
    caliper.select.handler.updateLayerList = function (event, arg) {
        var request = CCUtil.getGisdkProperties();
        request.NoRecursive = true;
        request.ControlName = "SelectControl";
        
        caliper.mapService.LoadConfig( "SelectControl.config", request, caliper.select.handler.onCompleteInit);	
        
        //close select window
        //caliper.select.hideSelectWindow();

        var queryString = jQuery("#SelectControl_query_string");
        if (typeof(queryString[0]) == 'undefined') return;
        queryString[0].value = "";
        };
            
            
    caliper.select.updateSelectWindow = function(e, ui) {    
        if (ui.helper) {
            var winHeight = ui.helper.style.height;
            var winWidth  = ui.helper.style.width;
            
            jQuery('#SelectInnerWrapper').css("height",winHeight);
            jQuery('#SelectInnerWrapper').css("width",winWidth);
            
            }
        };
        
    caliper.select.handler.tabClick = function(event,target) {
        if (target.id.indexOf("Location") >= 0)
            caliper.select.selectMode = caliper.select.LOCATION;
         else 
            caliper.select.selectMode = caliper.select.QUERY;
            
        caliper.select.toggleSelectingMethod();    
        };
        
    //*********************
    //Map service handler
    //*********************
    caliper.select.handler.onCompleteInit = function(args) {
        
        var stop_here = true;
        
        // console.log("entering onCompleteInit with args " + typeof args);
        
        if (args == null) return;
        
        var layerlist_popdown = document.getElementById ("SelectControl_LayerList");
        var i, opt_len;
        var layerName, layerDisplayName, layerFieldFile;
        var layerStatusArray, layerStatus;
        var layerDef = args.Layers;
        var layerConfigFile;
        
        layerStatusArray = CCUtil.getGisdkProperties("LayerStatus");
        
        if (layerDef == null) return;
        
        var layerNames = layerDef["Layer Name"];
        var layerDisplayNames = layerDef["Layer Display Name"];
        var layerFieldFiles = layerDef["Data Source Parameters"];

        if (layerFieldFiles == null) return;
        
        for (i=0; i<layerFieldFiles.length; i++) {
            layerConfigFile = layerFieldFiles[i];
            
            if (layerConfigFile == "null" || layerConfigFile == "" || layerConfigFile == null) 
                layerFieldFiles[i] = layerNames[i];
            }
    
        if (layerlist_popdown) {
            if (dojo.isIE) layerlist_popdown.options.innerHTML = "";
            else layerlist_popdown.options.length = 0;
           
            for (i=0; i<layerNames.length; i++)
                {    
                layerName = layerNames[i];

                layerStatus = eval("layerStatusArray[\""+layerName+"\"]");
                if (typeof(layerStatus) == "undefined" || layerStatus == null) continue;

                layerDisplayName = layerDisplayNames[i];
                layerFieldFile = layerFieldFiles[i];

                if (layerDisplayName == "") layerDisplayName = layerName;
                
                opt_len = layerlist_popdown.options.length;
                layerlist_popdown.options[opt_len] = new Option(layerDisplayName, layerFieldFile);
                }
                
            caliper.select.currentLayer = layerlist_popdown.value;    
            }
            
        if (CCUtil.getGisdkProperties("MapUnitsAbbr") != null) 
            jQuery("#SelectControl_mapUnit").html(CCUtil.getGisdkProperties("MapUnitsAbbr"));
          
        
        //get number of features in current selection set
        caliper.select.getSelectedFeatureNumbers();
            
        //get layer field list
        caliper.select.updateFields();
        
    
        };
        
    caliper.select.handler.onCompleteLayerFields = function(arg) {
        var fieldlist_popdown = document.getElementById ("SelectControl_FieldList");
        var i, opt_len;
        var fieldName;

        if (typeof arg == 'undefined' || arg == null) return;
        if (arg.Message != 'OK') {
            alert(arg.Message);
            return false;
            }
           
        if (arg.LayerFields && fieldlist_popdown) {
            if (dojo.isIE) fieldlist_popdown.options.innerHTML = "";
            else fieldlist_popdown.options.length = 0;

            fieldlist_popdown.options[0] = new Option(caliper.select.DUMMY_FIELD, caliper.select.DUMMY_FIELD);
           
            for (i=0; i<arg.LayerFields.length; i++)
                {    
                fieldName = arg.LayerFields[i];

                opt_len = fieldlist_popdown.options.length;
                fieldlist_popdown.options[opt_len] = new Option(fieldName, fieldName);
                }
            }
            
        };

    caliper.select.handler.onCompleteFieldValues = function(arg) {
        var valuelist_popdown = document.getElementById ("SelectControl_ValueList");
        var i, opt_len, valueParts;
        var valueText;

        if (typeof arg == 'undefined' || arg == null) return;
        if (arg.Message != 'OK') {
            alert(arg.Message);
            return false;
            }
           
        if (valuelist_popdown) {
            if (dojo.isIE) valuelist_popdown.options.innerHTML = "";
            else valuelist_popdown.options.length = 0;

            valuelist_popdown.options[0] = new Option(caliper.select.DUMMY_VALUE, caliper.select.DUMMY_VALUE);
            
            if (arg.ColumnValues) {
                valueParts = arg.ColumnValues.split(",");
               
                for (i=0; i<valueParts.length; i++)
                    {    
                    valueText = valueParts[i].trim();

                    opt_len = valuelist_popdown.options.length;
                    valuelist_popdown.options[opt_len] = new Option(valueText, valueText);
                    }
                } // if (arg.ColumnValues)
            }
            
        };
        
    caliper.select.handler.onCompleteSelectApply = function(arg) {
        if (arg) {
            if (arg.Message != "OK") 
                alert(arg.Message);
            else {
                caliper.select.util.updateDbox(arg);
                
                caliper.select.util.generateSelectionTable(arg);
                
                arg.Command = "Select";
                //broadcast the updateMap message so mapControl will handle
                jQuery("div.listener").trigger("MSG_updateMap", new Array(arg));
                    
                if (caliper.map.shapeToolContainer) caliper.map.shapeToolContainer.show();
                
//debug:measure time
CCUtil.stopStopwatch();                
                }
            }

            caliper.map.hideProgressbar();            
        };
        
    caliper.select.handler.onComplateZoom = function(arg) {
        if (arg == null) return;
        
        if (arg.Message != "OK") alert(arg.Message);
        else
            jQuery("div.listener").trigger("MSG_updateMap", new Array(arg));    
        };

    
    caliper.select.handler.updatePosition = function() {
        if (!CCUtil.isDocked("SelectControl")) return;
        
        jQuery("#SelectBox").css("left",0);
        jQuery("#SelectBox").css("top", CCUtil.getControlPosition("SelectControl"));
        };
            
    caliper.select.checkToolboxDocking = function() {
        if (CCUtil.checkDocking({top:jQuery("#SelectBox").attr("offsetTop"), left:jQuery("#SelectBox").attr("offsetLeft"), ControlName:"SelectControl"})) {
            jQuery("#SelectBox .title_bar").each(function() {
                this.className = "title_bar_dock";
                });
            jQuery("#SelectBox .title_bar_minimizer").each(function() {
                this.className = "title_bar_minimizer_dock";
                });
            }
        else {
            jQuery("#SelectBox .title_bar_dock").each(function() {
                this.className = "title_bar";
                });
            jQuery("#SelectBox .title_bar_minimizer_dock").each(function() {
                this.className = "title_bar_minimizer";
                });
            }
        };             
            
    //*********************
    //Utility
    //*********************
    caliper.select.util.setItemsStatus = function(command) {
        if (typeof command == 'undefined' || command == null) return;
        
        var distanceText = jQuery("#SelectControl_distanceText");
        var distanceValue = jQuery("#SelectControl_Distance");
        var setButton = jQuery("#SelectControl_Set");
        
        switch (command) {
            case 'distance':
                if (typeof distanceText[0] != 'undefined') {
                    distanceText[0].disabled = false;
                    distanceText[0].innerHTML = "&nbsp;&nbsp;&nbsp;Distance";
                    }
                if (typeof distanceValue[0] != 'undefined') 
                    distanceValue[0].disabled = false;
                if (typeof setButton[0] != 'undefined') 
                    setButton[0].disabled = true;
                break;
                
            case 'select_circle':
            case 'move_circle':
                if (typeof distanceText[0] != 'undefined') {
                    distanceText[0].disabled = false;
                    distanceText[0].innerHTML = "&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Radius";
                    }
                if (typeof distanceValue[0] != 'undefined') 
                    distanceValue[0].disabled = false;
                if (typeof setButton[0] != 'undefined') 
                    setButton[0].disabled = false;
                break;
            default:
                if (typeof distanceText[0] != 'undefined') 
                    distanceText[0].disabled = true;
                if (typeof distanceValue[0] != 'undefined') 
                    distanceValue[0].disabled = true;
                if (typeof setButton[0] != 'undefined') 
                    setButton[0].disabled = true;
                break;
            }
            
        
        };

    if ( typeof str_replace == "undefined" ) 
    {
       // utilities: string functions
       str_replace = function(search_regex, replacement, input_string)
       {
            var obj = new String(input_string);
            return obj.replace(search_regex, replacement);
       }
    }

    // 
    caliper.select.util.generateTotalRow = function(title,totals)
    {
        var html = "";
        if (totals) 
            {
            html = html + "<tr align='" + caliper.select.textAlign +"' ><td class='info_field' width='1%'>" + title + "</td>"; 
            
            if (caliper.select.editableFieldPresent) html = html + "<td class='editable_field'>&nbsp;&nbsp;</td>";
            
            for (k=1;k<totals.length;k++) 
                {
                    var val = totals[k];
                    if (val || (val == 0))
                    {
                        if (val.toString().indexOf(".") >= 0)
                            val = val.toFixed(3);
                    }
                    else
                    { 
                        val = "--";
                    }
                    html = html + "<td class='info_value_summary' >" + val + "</td>";
                }
            html = html + "</tr>";
            }
        return html;
    }

    //
    caliper.select.util.generateSelectionTable = function(arg) {
        var i, j, k;
        var SelectionTableObj, FieldNameHeader, FieldNameHeaderSummary, FieldNameHeaderNoSummary;
        var layerInfo, layerName, layerValues, field, values, aggregates;
        var SelectionContainer = jQuery("#selection_contents");
        var currentLayer = jQuery("#SelectControl_LayerList");
        var editableFieldDefs = null;
    
        if (arg == null) {
            if (SelectionContainer[0]) SelectionContainer[0].innerHTML = "";
            return;
            }
  
        if (caliper.select.Action == "Zoom" || caliper.select.Action == "ShowHide") return;
         
        if (arg.MaxReached == 1 ) return; //simply skip if user wants to add more records to an already full selection set
        
        if (arg.ExceedMax == 1) {
            var maxLimit = arg.MaxSelectRecords;
            if (maxLimit == null) maxLimit = 300; //un-likely
            
            alert("The selection set exceeds the maximum number of permitted records. Only the first " + maxLimit + " records are displayed.");
            }
          
        //Left or Right align
        if (arg.RightAlign && arg.RightAlign.toUpperCase() == "YES") 
            caliper.select.textAlign = "right";
            
        //check if any field is editable, and get field type if editable
        editableFieldDefs = caliper.select.edit.checkEditable(arg);
        
        //
        //arg.Layers is returned from GISDK if not error occured
        //Layers = [layer1, layer2,...layern];
        //layer1 = {
        //  layer1.LayerName,         actual name of layer
        //  layer1.LayerDisplayName,  name that user wants to display (optional)
        //  layer1.Columns,           list of fields to get values
        //  layer1.ColumnDisplay,     list of fields to get values
        //  layer1.Rows               array of list of field values
        //  }
        //
        if (arg.Layers && arg.Layers[0]) { 
            layerInfo = arg.Layers[0];

            layerName = layerInfo.LayerName;
            
            //layer display name is what displaying in Current Layer popdown menu
            if (currentLayer[0]) {
                var layerList; 

                if (dojo.isIE) layerList = currentLayer[0].children;
                else layerList = currentLayer[0].childNodes;
                
                for (i=0; i<layerList.length; i++) {
                    if (layerList[i].selected) {
                        layerName = layerList[i].text;
                        break;
                        }
                    }
                }
                
            SelectionTableObj = "<font class='font_black_bold'>No features found</font>";
                
            if (layerInfo.Rows) { //if value for this layer exists
                SelectionTableObj = "<font class='font_black_bold'>" + layerName;
                if (layerInfo.NumRows != null) 
                    SelectionTableObj = SelectionTableObj + " (" + layerInfo.NumRows + " features found)";

                SelectionTableObj = SelectionTableObj + "</font><br/>";
         
                // Totals
                var SummaryTable = caliper.select.util.generateTotalRow("Tot"  , layerInfo.Totals);
                SummaryTable = SummaryTable + caliper.select.util.generateTotalRow("Min"     , layerInfo.Min);
                SummaryTable = SummaryTable + caliper.select.util.generateTotalRow("Max"     , layerInfo.Max);
                SummaryTable = SummaryTable + caliper.select.util.generateTotalRow("Avg" , layerInfo.Average);

                //field names
                FieldNameHeaderSummary =  "<table width='100%' id='summary_records' border='0'>";
                FieldNameHeaderNoSummary =  "<table width='100%' class='sortable' id='selected_records' border='0'>";

                FieldNameHeader = "<tr align='" + caliper.select.textAlign +"' >";
                

                for (j=0; j<layerInfo.Columns.length; j++) {
                    field = layerInfo.ColumnDisplay[j];
                    
                    //first field is always ID, and it's used for zooming to the feature
                    if (j == 0) field = "&nbsp;";
                    else if (field == null || field.trim() == "") field = layerInfo.Columns[j];
                    
                    FieldNameHeader = FieldNameHeader + "<td  class='info_field'>" + field + "</td>";
                    
////                    if (j == 0 && caliper.select.editableFieldPresent)
////                        //add Edit field
////                        FieldNameHeader = FieldNameHeader + "<td  id='edit_values' class='editable_field' width='1%'>&nbsp;&nbsp;</td>";
                    }
                FieldNameHeader = FieldNameHeader + "</tr>";

                SelectionTableObj = SelectionTableObj + FieldNameHeaderNoSummary+ FieldNameHeader;
                   
                //field values
                var fieldClass = "info_value";
                var id, fieldName = null;
                var tempValuePerID, tempValuePerField;
                
                for (j=0; j<layerInfo.Rows.length; j++)  {
                    layerValues = layerInfo.Rows[j];
                    SelectionTableObj = SelectionTableObj + "<tr align='" + caliper.select.textAlign +"' >";
                    
                    id = null;
                    
                    for (k=0; k<layerValues.length; k++) {
                        fieldClass = "info_value";
                        fieldName = null;
                        
                        if (k == 0) { 
                            SelectionTableObj = SelectionTableObj + "<td class='info_link' width='20px'>"+
                                                "<a href='#' title='take me there' onclick=\"javascript:caliper.select.zoomToFeature("+layerValues[k]+");\"><img id='" +layerValues[k]+ "' src='graphics/aazoomto.gif' border='0'></a></td>";
////                            if (caliper.select.editableFieldPresent)                    
////                                SelectionTableObj = SelectionTableObj + "<td  align='left' class='editable_field' width='1%'><input gisdk_id='"+layerValues[k]+"' id='SelectControl_check_" + layerValues[k] + "' type='checkbox'  onClick='caliper.select.edit.onCheckRecord(this);' class='editable_field'></td>";
                            id = layerValues[k];
                            }                    
                        else {
                            if (caliper.select.editableFieldPresent && editableFieldDefs && editableFieldDefs[k] != null) {
                                fieldClass = "editable_field";
                                
                                //store field values for Reset use
                                fieldName = layerInfo.Columns[k];
                                if (id > 0 && fieldName) {
                                    tempValuePerID = caliper.select.recordsValues[id];
                                    if (typeof(tempValuePerID) == 'undefined') tempValuePerID = {};
                                    tempValuePerID[fieldName] = layerValues[k];
                                    caliper.select.recordsValues[id] = tempValuePerID;
                                    }
                                
                                }
                                
                            if (typeof(layerValues[k]) == "string" && layerValues[k].search(/http:/) > -1)
                                SelectionTableObj = SelectionTableObj + "<td  class='"+fieldClass+"'><a target=\"new_window\" href=\"" + layerValues[k]  + "\">" + layerValues[k] + "</a></td>";
                            else  if (layerValues[k] != null) 
                                SelectionTableObj = SelectionTableObj + "<td  class='"+fieldClass+"' >" + layerValues[k] + "</td>";
                                
                            else 
                                SelectionTableObj = SelectionTableObj + "<td  class='"+fieldClass+"'>&nbsp;</td>";
                            }
                        }
                    SelectionTableObj = SelectionTableObj + "</tr>";
                    }
                } //if (layerInfo.Rows)
                
            jQuery('#Selection_Excel_Img').attr("title", "Save Table to Excel");
            jQuery('#Selection_Excel_Img').click(caliper.map.clickSaveExcel);
            jQuery('#Selection_Excel_Img').attr("src", "graphics/aaexcel1.gif");
            } //if (arg.Layers && arg.Layers[0]) { 
        else {
            SelectionTableObj =  "<font class='font_black_bold'>No records found</font><br/>";
            jQuery('#Selection_Excel_Img').attr("title", "");
            jQuery('#Selection_Excel_Img').unbind('click');
            jQuery('#Selection_Excel_Img').attr("src", "graphics/aaexcel2.gif");
            }
        
        SelectionTableObj = SelectionTableObj + "</table>";
        if (arg.Layers) 
            SelectionTableObj = SelectionTableObj + "<table><tr><td width='75%'>&nbsp;</td><td class='info_value' align='right' width='200px'><input type='button' id='edit_apply' disabled onclick='caliper.select.edit.applyEdit();' value='Apply' />&nbsp;"+
                                                "<input type='button' id='edit_reset' disabled onclick='caliper.select.edit.resetEdit();' value='Reset' /></td></tr></table>";

        if (typeof(SummaryTable) != 'undefined' && SummaryTable.length > 6) {
            //add a summary tab
            SelectionTableObj = "<ul><li><a href='#selection_table'><span class='font_black_small'>Selection</span></a></li>" +
                                    "<li><a href='#summary_table'><span class='font_black_small'>Summary</span></a></li>" +
                                "</ul>" +
                                "<div id='selection_table'>" + SelectionTableObj + "</div>" +
                                "<div id='summary_table'>"+
                                    FieldNameHeaderSummary + FieldNameHeader + SummaryTable + "</table>"+
                                "</div>";
            }                
        

        
        if (SelectionContainer[0]) {
//            SelectionContainer[0].innerHTML = SelectionTableObj;
            SelectionContainer.html(SelectionTableObj);
            if (typeof(SummaryTable) != 'undefined' && SummaryTable.length > 6) jQuery("#selection_contents").tabs();
            }

        if (!arg.Layers) {
            jQuery('#SelectWindow').css("height",70);
            jQuery('#SelectWindow').css("width",caliper.select.SELECT_WINDOW_WIDTH);
            jQuery('#SelectInnerWrapper').css("height",70);
            jQuery('#SelectInnerWrapper').css("width",caliper.select.SELECT_WINDOW_WIDTH);

            return;
            }
            
        //make the selection table sortable
        ts_makeSortable(document.getElementById("selected_records"));

        //define click function of the Edit button
////        var editButton = jQuery("#selected_records #edit_values");
////        var editButtonHtml;
////        if (editButton[0]) {
////            editButtonHtml = "<img id='SelectControl_markUnmark' src='graphics/aaeditcheck1.gif' border='0' alt='Mark all records' onclick='javascript:caliper.select.edit.markUnmarkAll()' style='cursor:pointer;'>"+
////                             "<img src='graphics/aaedit1.png' border='0' alt='Edit marked records' onclick='javascript:caliper.select.edit.doEdit()' style='cursor:pointer;'>";
////            editButton.html(editButtonHtml);
////            }
        
        
        jQuery("#selected_records .editable_field").each(function() {
            jQuery(this).click(caliper.select.edit.switchToEditable);
            });    
        

        
        var selectWindowHeight = dojo.isIE ? SelectionContainer[0].offsetHeight + 50 : 20 * layerInfo.Rows.length + 120;
        var selectWindowWidth  = SelectionContainer[0].offsetWidth + 30;

        selectWindowHeight = Math.min(selectWindowHeight, caliper.select.SELECT_WINDOW_HEIGHT);

        
        if ( selectWindowWidth > caliper.select.SELECT_WINDOW_WIDTH + 30) {
            selectWindowWidth = caliper.select.SELECT_WINDOW_WIDTH;
            }


        jQuery('#SelectWindow').css("height",selectWindowHeight);
        jQuery('#SelectInnerWrapper').css("height",selectWindowHeight);
        jQuery('#SelectWindow').css("width",selectWindowWidth);
        jQuery('#SelectInnerWrapper').css("width",selectWindowWidth);
        
        
        if (jQuery("#SelectWindow").css("visibility") == "hidden" && caliper.select.Action && caliper.select.Action.toUpperCase() !== "CLEAR") 
            CCUtil.showToolbox("SelectWindow")

        };
        
    
    //Enable or disable ZoomToSelection and Hide/Show selection buttons
    //depending on whether the selection set is empty
    caliper.select.util.updateDbox = function(arg) {
        if (typeof(arg) == "undefined" || arg == null) return;
        
        if (typeof(arg.RecordsFound) != "undefined" && arg.RecordsFound > 0) {
            caliper.select.setIsEmpty = false;
            
            jQuery("#select_zoom_sets").attr("src", "graphics/aaselzoom1.gif");
            jQuery("#select_hide_sets").attr("src", "graphics/aaselhighlight1.gif");
            }
        else {
            caliper.select.setIsEmpty = true;
            
            jQuery("#select_zoom_sets").attr("src", "graphics/aaselzoom0.gif");
            jQuery("#select_hide_sets").attr("src", "graphics/aaselhighlight0.gif");
            }            
        };
           
    //*********************
    //Public method
    //*********************
    caliper.select.print = function() {
        var SelectionContainer = jQuery("#selection_contents");
        
        if (jQuery("#SelectWindow").css("visibility") == "hidden") return null;

        if (typeof (SelectionContainer[0]) != 'undefined') {
            var selectionRecordsOriginal = jQuery("#selection_contents").html();
            
            jQuery(".info_link").html(" ");  //filter out "take me there" strings
            jQuery("UL").html(" ");
            jQuery("#summary_records").html(" ");
            
            var selectionRecordsPrint = jQuery("#selection_contents").html();
            
            jQuery("#selection_contents").html(selectionRecordsOriginal); //reserve selecting records displayed in main window
            
            return selectionRecordsPrint;
            }
        };
        
    caliper.select.getControlPaneHeight = function () {
        if (jQuery("#SelectBox").css("visibility") == "hidden") return 0;
    
            if (caliper.select.selectMode == caliper.select.LOCATION) 
            return caliper.select.LOCATION_HEIGHT + 6;
        
        return caliper.select.QUERY_HEIGHT + 6;
        };

