
if (typeof caliper == 'undefined')
    var caliper = {};

if ( typeof caliper.map == "undefined" ) 
    caliper.map = {};   
    
if (typeof caliper.map.handler == "undefined" ) 
    caliper.map.handler = {};   

//Title and balloon help for map window and map toolbox
caliper.map.mapWindowTitle   = "Map Window ";
caliper.map.mapWindowBalloon = "To navigate this map, choose one of the zoom or pan tools and click on the map window.";
caliper.map.toolTitle        = "Navigate the Map";
caliper.map.toolBalloon      = "To change the map location, choose one of the zoom or pan tools and click and drag the cursor on the map. "+
                               "To edit the ZIP code territories, choose the select buttons and then click on the map.";
caliper.map.toolHelp         = "<UL><LI><img src='graphics/aainitialmap1.gif'> Click to set the map center and scale to their initial settings</LI>" +
                               "<LI><img src='graphics/aaprev1.gif'> Click to set the map center and scale back 1 step</LI>" +
                               "<LI><img src='graphics/aazmin1.gif'> Click to activate the tool, then click or drag a rectangle on map to zoom in</LI>" +    
                               "<LI><img src='graphics/aazmout1.gif'> Click to activate the tool, then click or drag a rectangle on map to zoom out</LI>" +    
                               "<LI><img src='graphics/aapan1.gif'> Click to activate the tool, then click or drag map to re-center</LI>" +
                               "<LI><img src='graphics/aaselpoint1.gif'> Click to activate the tool, then click map to select ZIP code territories. Edit the territory values at the <b>Edit ZIP Code Territories</b> window</LI>" +
                               "<LI><img src='graphics/aasellasso1.gif'> Click to activate the tool, then draw a lasso on map to select ZIP code territories. Edit the territory values at the <b>Edit ZIP Code Territories</b> window</LI>" +
                               "<LI><img src='graphics/aaprint1.gif'> Click to print the map, legend and ZIP code territory values</LI></UL>";    

caliper.Annotation = null;

caliper.map.SNAP_DISTANCE = 10;    //10 pixels
caliper.map.MAX_MAP_HISTORY = 20;  //maximum of previous maps stored in history

caliper.map.map_url = ""; 
caliper.map.map_legend_url = ""; 
caliper.map.map_scope = ""; 
caliper.map.map_scale = 10;

caliper.map.gisdk_tempfile_folder = "/TempMapFiles/" 

caliper.map.map_width = 0;  
caliper.map.map_height = 0;  

caliper.map.zoomLevels = new Array(2500, 5000, 10000,20000,50000,100000, 200000, 500000, 1000000);
caliper.map.zoomTargetScale = 10;

caliper.map.mapSizes = new Array(200,300,350,500,650);

caliper.map.command = 'zmin';

caliper.map.mapCenter = {x: 0, y: 0};

caliper.map.mapContainer = null; //container object on which the surface object and image object display
caliper.map.mapSurface = null;   //surface object to attach map image

caliper.map.shapeRect = null;    //rectangle scope defined by zoom and select tools, in the format of top_left_x | top_left_y | width | height
caliper.map.shapePan  = null;    //pan-shifting values, in the format of shift_x|shift_y
caliper.map.shapeCircle = null;  //circle specs create by select_circle tool, in the format of center_x | center_y | radius_x | radius_y

caliper.map.shapeToolContainer = null; //library of shape tools and methods: rect, circle, mark and laso
caliper.map.mouseUpHandler = null;     //handler function associated with individual tool, gets called on mouse-up event on map image object

caliper.map.updateMapCallbackMessages = null; //a list of call-back messages set by the caller of MSG_updateMap, they will be fired onup
                                              //successfully finished onCompleteUpdateMap

caliper.map.mapScopeHistory = [];  //stores the map scopes in chronical order

caliper.map.closeLasso = true;
caliper.map.circleSelected = false;

caliper.map.click_orig_x = 0;
caliper.map.click_orig_y = 0;
caliper.map.mouse_down_clicked = false;

caliper.map.windwo_for_print = null;

caliper.map.bookmarks = null;
caliper.map.legendVisible = true;

caliper.map.MAPWINDOWINITX = 262;  //x position of map window
caliper.map.IMAGEWIDTH = 650;
caliper.map.IMAGEHEIGHT = 650;

caliper.initMapForm = function () {
    //set map window and toolbox title and balloon help
    jQuery("#mapWindowTitle").html(caliper.map.mapWindowTitle);
    jQuery("#mapWindowBar").attr("title", caliper.map.mapWindowBalloon);
    jQuery("#mapToolTitle").html(caliper.map.toolTitle);
    jQuery("#mapToolBar").attr("title", caliper.map.toolBalloon);
    

    // preload toolbox button images
    jQuery('#mapToolBox .gisdk_buttons').each( function() { 
        var pimg = jQuery(this).attr("preload");
        var pstatus = jQuery(this).attr("gisdk_status");

        if (pimg && pimg.length > 5) jQuery(this).attr("src", pimg);
        if (pstatus && pstatus.length > 5) jQuery(this).attr("title", pstatus);
        });      

    //adjust map frame width
    jQuery("#mapWindow").css("width",caliper.map.map_width+5);
    
    //hide guiding image
    jQuery("#gisdk_map_image").css("visibility","hidden");
    jQuery("#gisdk_map_image").attr("height",1);
    jQuery("#gisdk_map_image").attr("width",1);
    
    //make map window draggable
    jQuery("#mapWindow").draggable({handle:'.title_bar', start: caliper.map.startMapDragging, stop:caliper.map.adjustZoomBarPosition});

    //make toolbox draggable
    jQuery("#mapToolBox").draggable({handle:'.title_bar', start: caliper.map.startToolboxDragging, stop:caliper.map.checkToolboxDocking});

    //make legend box draggable
    jQuery("#legendWindow").draggable({handle:'.title_bar'});

    jQuery("#zoomBar").slider({slide:caliper.map.onZoomBarMove, start: caliper.map.onZoomBarStart, stop:caliper.map.onZoomBarEnd});        
    
    jQuery("#HelpWindow").draggable({handle:'.title_bar'});
    jQuery('#HelpWindow').resizable({ autohide: false });
    
    //subscribe to listen to event messages
    jQuery("#mapWindow").bind("MSG_updateMap",  caliper.map.handler.redrawMap);
    jQuery("#mapWindow").bind("MSG_clearTools",  caliper.map.clearTools);
    jQuery("#mapWindow").bind("MSG_completeSelectingMap",  caliper.map.handler.closePrintWindow);
    jQuery("#mapWindow").bind("MSG_completeMapSurface",  caliper.map.handler.updatePosition);
    jQuery("#mapWindow").bind("MSG_updateToolboxPosition",  caliper.map.handler.updatePosition);

    //get pre-defined quick-zoom levels and map size steps
    caliper.mapService.LoadConfig( "MapControl.config", null, caliper.map.handler.onCompleteMapSettings);   
    updateIcons();
    
    CCUtil.dockToolbox("MapControl");
    
    //set default tool to zoomin
    caliper.map.clickButtonZoomin();
    };


caliper.map.getZoomValue = function(evt) {
    var CARRIAGE_RETURN = 13; //key code for carriage return
    var BACK_SPACE = 8; //key code for back-space
    var ALEFT=37, AUP=38, ARIGHT=39,ADOWN=40;
    var validKeys = [CARRIAGE_RETURN, BACK_SPACE, ALEFT, AUP,ARIGHT, ADOWN];
     
    var hitReturn = false;
    var zoomValue, zoomValueInt = -1;
    var keyCode = -1;

    zoomValue = jQuery("#zoomValue").attr("value");

    if (dojo.isIE) keyCode = window.event.keyCode;
    else keyCode = evt.keyCode;
    
    if (validKeys.indexOf(keyCode) < 0 && (keyCode < 48 || keyCode > 57)) {
        jQuery("#zoomValue").attr("value",zoomValue.substring(0, zoomValue.length -1));
        return; //must be between 0-9
        }
    if (keyCode == CARRIAGE_RETURN) hitReturn = true; 

    if (hitReturn) {
        var segments = zoomValue.split(":");
        if (segments.length > 1) zoomValue = segments[segments.length-1];
        zoomValueInt = parseInt(zoomValue);
        
        if (typeof(zoomValueInt) != "NaN" && zoomValueInt > 0) {
            
            caliper.map.zoomTargetScale = zoomValueInt;
            caliper.map.onZoomBarEnd(evt);            
            }
        }
    };
    
caliper.map.adjustZoomBarPosition = function() {
    var zoomBar = jQuery("#zoomBar");
    var height_shift = 40;
    
    if (zoomBar[0]) {
        var map_left = parseInt(jQuery("#mapWindow").css("left"));
        var map_top = parseInt(jQuery("#mapWindow").css("top"));

        jQuery("#zoomBar").css("left", map_left);
        jQuery("#zoomBar").css("top", map_top + caliper.map.map_height + height_shift);
        jQuery("#zoomValuePrefix").css("left", map_left + 225);
        jQuery("#zoomValuePrefix").css("top", map_top + caliper.map.map_height +height_shift + 15);
        jQuery("#zoomValue").css("left", map_left + 235);
        jQuery("#zoomValue").css("top", map_top + caliper.map.map_height +height_shift + 12);
        }
        
    if(typeof (caliper.map.zoomLevels) != "object") jQuery("#zoomBar").slider("disable");
    caliper.map.zoomLevels.sort(function(a,b){return a - b});
    };
    
caliper.map.setCommand = function (input_command) {
    caliper.map.command = input_command;
    };
  
/**
* Mouse_Down event handler: record mouse coordinate, create drawing object.
*/
caliper.map.onMouseDown = function(event) {
    var current_command = caliper.map.command;
    if (!current_command) return;

    caliper.map.mouse_down_clicked = true;

    if (dojo.isIE)
        {
        caliper.map.click_orig_x = event.x; 
        caliper.map.click_orig_y = event.y; 
        }
    else
        {
        caliper.map.click_orig_x = event.layerX; 
        caliper.map.click_orig_y = event.layerY; 

        if (CCUtil.isFF35 && typeof(event.target.offsetTop) != 'undefined')
            caliper.map.click_orig_y = caliper.map.click_orig_y - event.target.offsetTop;
        }

    switch (current_command) 
        {
        case 'select_rect':
        case 'zmin':
        case 'zmout':
            if (caliper.map.shapeToolContainer)
                caliper.map.shapeToolContainer.createRect({x:caliper.map.click_orig_x, y:caliper.map.click_orig_y, rect_shreshold: 2});

            break;
        case 'pan':

            break;
        
        case 'info':
            if (caliper.map.shapeToolContainer) {
                if (caliper.map.shapeToolContainer.existsMark())
                    caliper.map.shapeToolContainer.mark.update({x:caliper.map.click_orig_x, y:caliper.map.click_orig_y});
                else
                    caliper.map.shapeToolContainer.createMark({x:caliper.map.click_orig_x, y:caliper.map.click_orig_y});
                }
            break;
        case 'select_point':
            if (caliper.map.shapeToolContainer) {
                caliper.map.clearTools();
                caliper.map.shapeToolContainer.createMark({x:caliper.map.click_orig_x, y:caliper.map.click_orig_y});
                }
            break;
        case 'select_circle':       
            if (caliper.map.shapeToolContainer) {
                if (caliper.map.shapeToolContainer.circle)
                    caliper.map.shapeToolContainer.circle.destroy();
                    
                caliper.map.shapeToolContainer.createCircle({x:caliper.map.click_orig_x, y:caliper.map.click_orig_y});
                }
            break;
        case 'move_circle':     
            if (caliper.map.shapeToolContainer && caliper.map.shapeToolContainer.circle)
                caliper.map.circleSelected = caliper.map.shapeToolContainer.circle.select({x:caliper.map.click_orig_x, y:caliper.map.click_orig_y, method:'inside'});
            break;
            
        case 'select_lasso':
        case 'distance':
            var lasso_length=0;
            
            if (caliper.map.shapeToolContainer) {
                if (caliper.map.shapeToolContainer.lasso) {
                    caliper.map.shapeToolContainer.lasso.destroy();
                    caliper.map.shapeToolContainer.createLasso({x:caliper.map.click_orig_x, y:caliper.map.click_orig_y});
                    }
                else if (caliper.map.shapeToolContainer.lassoSegments) {
                    lasso_length = caliper.map.shapeToolContainer.lassoSegments.addNode({x:caliper.map.click_orig_x, y:caliper.map.click_orig_y});
                    var arguments = {distance_pixel: lasso_length};
                    jQuery("div.listener").trigger("MSG_updateDistance",new Array(arguments));  
                    }
                else
                    caliper.map.shapeToolContainer.createLasso({x:caliper.map.click_orig_x, y:caliper.map.click_orig_y});
                }

            break;
        } //switch current_command


    dojo.stopEvent(event);

    };

/**
* Mouse_DoubleClick event handler -  gets called in addition to onMouseDown
* double click to close selecting lasso or measuring tool
*/
caliper.map.onDoubleClick = function(event) {
    if (!caliper.map.mouse_down_clicked) return;

    if((caliper.map.command == 'select_lasso' || caliper.map.command == 'distance' ) && caliper.map.shapeToolContainer.lassoSegments)
        {
        var arg = {};
        if (caliper.map.command == 'select_lasso' )  arg.autoClose = true;
        else arg.autoClose = false;
        
        caliper.map.shapeToolContainer.completeLasso(caliper.map.shapeToolContainer.lassoSegments, arg);
        
        caliper.map.mouse_down_clicked = false;

        var measuringString = caliper.map.shapeToolContainer.generateSelectingString();
        var segments = measuringString.split("|");
        
        if (segments.length > 6) {
            if (caliper.map.command == "distance") {
                //X1 = Xn & Y1 = Yn: shape is closed, do Area calculation
                if (segments[0] == segments[segments.length -2] && segments[1] == segments[segments.length -1] ) {
                    var request = {};

                    request.LassoPoints = measuringString;
                    request.Command = caliper.map.command;
                    request.ImageWidth = caliper.map.map_width;
                    request.ImageHeight = caliper.map.map_height;
                    request.MapScope = caliper.map.map_scope;
                    request.MapFile = CCUtil.getGisdkProperties("MapFile"); 
                    caliper.mapService.DoMethod("MapService.MeasureDistanceAndArea", request, "MapControl.config" , "MapControl" , caliper.map.onCompleteMeasuring);
                    }
                }
            else
                caliper.select.onClickSelectApply("Add");
            
            } //if (segments.length > 6)
        }
        
//debug: measure time        
CCUtil.startStopwatch();        
        
    dojo.stopEvent(event);
    };


/**
* Mouse_Move event handler: update drawing object.
*/
caliper.map.onMouseMove = function(event) {
    if (!caliper.map.mouse_down_clicked) return;
    
    if (dojo.isIE)
        {
        current_x = event.x; 
        current_y = event.y; 
        }
    else
        {
        current_x = event.layerX; 
        current_y = event.layerY; 

        if (CCUtil.isFF35 && typeof(event.target.offsetTop) != 'undefined')
            current_y = current_y - event.target.offsetTop;
        }

    if (current_x < 0) current_x = 0;
    else if (current_x > caliper.map.map_width-1) current_x = caliper.map.map_width-1;
    if (current_y < 0) current_y = 0;
    else if (current_y > caliper.map.map_height-1) current_y = caliper.map.map_height-1;


    if(caliper.map.mouse_down_clicked)
        {

        rect_orig_x    = caliper.map.click_orig_x;
        rect_orig_y    = caliper.map.click_orig_y;
        
        switch (caliper.map.command) 
            {
            
            case 'select_rect':
            case "zmin":
            case "zmout":
                if (caliper.map.shapeToolContainer && caliper.map.shapeToolContainer.rect)
                    caliper.map.shapeToolContainer.rect.update({x:current_x, y:current_y });
                break;
                
            case 'pan':
                if ( current_x > caliper.map.map_width)
                    current_x = caliper.map.map_width;
                else if ( current_x < 0) 
                    current_x = 0;
                    
                if ( current_y > caliper.map.map_height)
                    current_y = caliper.map.map_height;
                else if (current_y < 0)
                    current_y = 0;
                        
                if (map_image_obj)
                    map_image_obj.setTransform(dojox.gfx.matrix.translate(current_x-caliper.map.click_orig_x, current_y-caliper.map.click_orig_y)); //clickw,clickh));
                break;      //PAN
            case 'select_circle':
                r1 = Math.floor(Math.sqrt((current_x-caliper.map.click_orig_x) * (current_x-caliper.map.click_orig_x) + (current_y-caliper.map.click_orig_y) * (current_y-caliper.map.click_orig_y)));
   
                if (caliper.map.shapeToolContainer && caliper.map.shapeToolContainer.circle) {
                    caliper.map.shapeToolContainer.circle.update({r:r1});
                    var arguments = {distance_pixel: r1};
                    jQuery("div.listener").trigger("MSG_updateDistance",new Array(arguments));  
                    }
                break;
            case 'move_circle':     
                if (caliper.map.shapeToolContainer && caliper.map.shapeToolContainer.circle && caliper.map.circleSelected)
                    caliper.map.shapeToolContainer.circle.move({dx:current_x-caliper.map.click_orig_x, dy:current_y-caliper.map.click_orig_y});
                break;
            case 'select_lasso':
            case 'distance':
                if (caliper.map.shapeToolContainer.lassoSegments) 
                    caliper.map.shapeToolContainer.lassoSegments.update({x:current_x, y:current_y});
                break;
            } //switch caliper.map.command

        } //if(caliper.map.mouse_down_clicked)

    dojo.stopEvent(event);
    };

//
//image coordinate values of mouse clicks that get set to hidden variables:
// zmin/zmout/info/select_by_rect/select_by_point:
//  caliper.map.shapeRect  -  string in the format of top_left_x | top_left_y | width | height
//
// pan:
//  caliper.map.shapePan   -  string in the format of shift_x | shift_y 
//
// circle:
//  caliper.map.shapeCircle-  String in the format of center_x | center_y | radius_x | radius_y
//
/**
* Mouse_Up event handler: generate drawing object shape, destroy drawing object, and send
* command and shape coordinates to web service.
*/
caliper.map.onMouseUp= function(event)
{
    var current_command = caliper.map.command;

    switch (current_command) 
        {
        case 'select_rect':
        case 'select_move_rect':
            break;
            
        case 'zmin':
        case 'zmout':
            if (caliper.map.shapeToolContainer && caliper.map.shapeToolContainer.rect) {
                caliper.map.shapeRect = caliper.map.shapeToolContainer.rect.toString();  //rectangle shape specification in the format of UL_x|UL_y|width|height
                caliper.map.shapeToolContainer.rect.destroy();
                }
            
            break;
        case 'pan':     
            var transform = map_image_obj.getTransform();
            var shift_x = 0, shift_y = 0;
            
            if (transform) {
                shift_x = transform.dx;
                shift_y = transform.dy;
                }
            
            if (shift_x == 0 && shift_y == 0) {
                shift_x = caliper.map.mapCenter.x - caliper.map.click_orig_x;
                shift_y = caliper.map.mapCenter.y - caliper.map.click_orig_y;
                }
                
            caliper.map.shapePan = shift_x+"|"+shift_y;    //x_shift|y_shift

            break;

        
        case 'info':
            if (caliper.map.shapeToolContainer.existsMark())
                caliper.map.shapeRect = caliper.map.shapeToolContainer.mark.toString() + "|0|0" ;

            break;
        case 'select_point':
            if (caliper.map.shapeToolContainer.existsMark()) {
                caliper.map.shapeRect = caliper.map.shapeToolContainer.mark.complete();
                caliper.map.shapeRect = caliper.map.shapeToolContainer.addMark(caliper.map.shapeRect = caliper.map.shapeToolContainer.mark);
                caliper.map.shapeRect = caliper.map.shapeToolContainer.mark.toString() + "|0|0" ;
                }
                
            caliper.select.onClickSelectApply("Add");
            break;
        case 'select_circle':
        case 'move_circle':     
            if (caliper.map.shapeToolContainer && caliper.map.shapeToolContainer.circle) {
                caliper.map.shapeToolContainer.circle.complete();
                caliper.map.shapeCircle = caliper.map.shapeToolContainer.circle.toString();
                }
            caliper.map.circleSelected = false;
            
            break;

        } //switch (current_command)
        
    if (current_command != 'select_lasso' && current_command != 'distance')
        caliper.map.mouse_down_clicked = false;
    dojo.stopEvent(event);

    if (current_command != 'dummy')
        {
   
        if (caliper.map.mouseUpHandler)
            eval(caliper.map.mouseUpHandler);    
        }
        
//debug: measure time        
CCUtil.startStopwatch();        
    return false;

};

caliper.map.adjustZoomBarLevel = function() {
    return;

    var i;

    if (caliper.map.map_scale >= caliper.map.zoomLevels[caliper.map.zoomLevels.length -1]) jQuery("#zoomBar").slider("value", 100);
    else {
        for (i=0; i<caliper.map.zoomLevels.length; i++) {
            if (caliper.map.map_scale <= caliper.map.zoomLevels[i]) {
                jQuery("#zoomBar").slider("value", parseInt(i/caliper.map.zoomLevels.length*100));
                break;
                }
            }
    
        }
        
    jQuery("#zoomValue").attr("value",caliper.map.map_scale);
    };
    
caliper.map.onZoomBarStart = function(event) {
    caliper.map.zoomTargetScale = caliper.map.map_scale;
    };
    

caliper.map.onZoomBarMove = function(event) {
    var i, position;
    var slideValue = jQuery("#zoomBar").slider("value");  
    var current_x, current_y;
    
    if (!event) return;
    
    current_x = event.clientX; 
    current_y = event.clientY; 

    position = parseInt(slideValue / 100 * caliper.map.zoomLevels.length);
    if (position >= caliper.map.zoomLevels.length) 
        caliper.map.zoomTargetScale = caliper.map.zoomLevels[caliper.map.zoomLevels.length -1];
    else caliper.map.zoomTargetScale = caliper.map.zoomLevels[position];
    
    jQuery("#zoomValue").attr("value",caliper.map.zoomTargetScale);
    };
    
caliper.map.onZoomBarEnd = function(event) {
    var args = [];
    
    if (event != null && ((event.originalEvent && event.originalEvent.type == "mouseup") || (event.type && event.type == "keyup"))) {
        args.Command = "redraw";
        if (event.originalEvent && event.originalEvent.type == "mouseup") 
            args.Command = "redraw_zoombar";
            
        args.MapScale = caliper.map.zoomTargetScale;
        caliper.map.clickImageHandler(args); 
        
        }
    };    
//
// button event handlers
//
caliper.map.clickBookmark = function() {
    jQuery('#mapBookmarkTool').css("visibility","visible");
    };
    
caliper.map.clickButtonRestore = function() {
    caliper.map.clearPreviousMapHistory();
    caliper.map.resetMap();
    };
    
caliper.map.clickButtonZoomin = function() {
    caliper.map.command = 'zmin';
    caliper.map.mouseUpHandler = "caliper.map.clickImageHandler({Command:caliper.map.command})";
    caliper.map.selectButton(caliper.map.command);

    caliper.map.clearTools();
    };
    
caliper.map.clickButtonZoomout = function() {
    caliper.map.command = 'zmout';
    caliper.map.mouseUpHandler = "caliper.map.clickImageHandler({Command:caliper.map.command})";
    caliper.map.selectButton(caliper.map.command);

    caliper.map.clearTools();
    };
    
caliper.map.clickButtonPan = function() {
    caliper.map.command = 'pan';
    caliper.map.mouseUpHandler = "caliper.map.clickImageHandler({Command:caliper.map.command})";
    caliper.map.selectButton(caliper.map.command);

    caliper.map.clearTools();
    };
    
caliper.map.clickButtonInfo = function() {
    caliper.map.command = 'info';
    caliper.map.mouseUpHandler = "caliper.map.clickImageHandler({Command:caliper.map.command})";
    caliper.map.selectButton(caliper.map.command);

    caliper.map.clearTools();
    };
    
    
    
 /**
  *  Highlight one of the buttons above the map and set the current action (zoom, pan, info, select, measure...)
  *  If action_name is null, then select the current button.
  *  @param {String} action_name
  */
caliper.map.selectButton = function(command_name) {
    
    var buttons = jQuery('.gisdk_buttons');
    var b, img, id, prefix;
    for (var i=0;i<buttons.length;i++)
    {
        b   = jQuery(buttons[i]);
        id  = b.attr("id");                     // id = "gisdk_action_name_button"
        img = b.attr("src");
        prefix = img.substring(0,img.length-5)  // translate "info1.gif" to "info"
        if (id.indexOf("_"+command_name+"_")>0)
        {
            // the button id matches "command_name"
            caliper.map.command = command_name;
            img = prefix + "2.gif";
            if (caliper.map.mapContainer) caliper.map.mapContainer.style.cursor = b.attr("gisdk_cursor");
        }
        else
        {
            // the button id is another button
            img = prefix + "1.gif";
        }
        b.attr("src",img);
        }
    };
    
   
   
/** 
 * reset the application - map image, map scope, map url, and send message to other
 * controls that a reset is in process
 */
caliper.map.resetMap = function() {
    caliper.map.clickImageHandler({Command:"resetMap"});
    };
    
/**
 * Collect current tool command and coordinates, map scope and map width/height, send them to server
 * to update map
 */
caliper.map.clickImageHandler = function(args) {

    var rect_value = caliper.map.shapeRect;
    var pan_value  = caliper.map.shapePan;
    var request = caliper.map.getArguments();

    var command = args.Command;
    var initScope = args.InitScope; 

    caliper.map.showProgressbar();    
    if (typeof command == 'undefined') command = "update_map";
    
    if (command) {
        //if (!rect_value && !pan_value) return;

        request.Command =  command;
        if (command == 'resetMap') {
            //passing a null as map scope so that the map will be displayed in its
            //initial scope
            request.MapScope = null;
            }
        else {
            request.Rect =  rect_value;
            request.PanShift = pan_value;
            }
        }
        
    if (typeof(initScope) != 'undefined' && initScope != null) 
        request.MapScope = initScope;
    else if (CCUtil.getGisdkProperties("NewMapScope") == "True"){ //map file is from a different folder
        request.MapScope = null;
        //clear NewMapScope flag
        CCUtil.setGisdkProperties({NewMapScope:null});
        }

    
    if (typeof(args.MapScale) != "undefined" && args.MapScale > 0) 
        request.MapScale = args.MapScale;
        
    request.ConfigFile = "MapControl.config";
        
    self.status = "Please wait...";

    if (command == 'info') {
        //broadcast the event message so that subscribed listeners will handle
        jQuery("div.listener").trigger("MSG_getInfo",new Array(request)); 
        }
    else
        caliper.mapService.DoMethod("MapService.RedrawMap", request, "MapControl.config", "MapControl", caliper.map.handler.onCompleteUpdateMap);
    };  


caliper.map.onCompleteMeasuring = function (arg) {
    if (arg.Message != "OK") {
        alert(arg.Message);
        return;
        }
    
    var arguments = {};
    arguments.area = arg.Area;
    arguments.area_sqkm = arg.AreaSqkm;
    
    jQuery("div.listener").trigger("MSG_updateDistance",new Array(arguments));  
        
    };
    
//build JSON object of map width, height, scope and command, and annotation 
caliper.map.getArguments = function() {
    var map_args = CCUtil.getGisdkProperties();
    
    //remove pass-once items
    map_args.ImageFile = null;
    map_args.BoundingBox = null;
    map_args.InitMap = null;
    map_args.InitScope = null;
    map_args.MapScale = null;
    map_args.ZoomLevel = null;
    
    map_args.Command = caliper.map.command;
    map_args.ImageWidth = caliper.map.map_width;
    map_args.ImageHeight =  caliper.map.map_height;
    map_args.MapScope = caliper.map.map_scope;

    if ((typeof(caliper.Annotation) == "object") && (caliper.Annotation != null )) {
        var lon = parseFloat(caliper.Annotation.Lon) * 1000000;
        var lat = parseFloat(caliper.Annotation.Lat) * 1000000;
        map_args.AnnotationCoord = new Array(lon,lat);
    }
    else
        map_args.AnnotationCoord = null;

    return map_args;
    };

caliper.map.clearTools = function() {
    if (caliper.map.shapeToolContainer)
        caliper.map.shapeToolContainer.clearAll();
    };


caliper.map.clearPreviousMapHistory = function() {
    var prevMapButton = jQuery("#gisdk_previous_button");
    var pimg = prevMapButton.attr("preload");

    if (pimg && pimg.length > 5) prevMapButton.attr("src", pimg);
    
    caliper.map.mapScopeHistory = [];
    };

caliper.map.addToPreviousMapHistory = function(scope_string) {
    var prevMapButton = jQuery("#gisdk_previous_button");
    var simg = prevMapButton.attr("active");

    if (simg && simg.length > 5) prevMapButton.attr("src", simg);

    if ( caliper.map.mapScopeHistory.length > caliper.map.MAX_MAP_HISTORY)
        caliper.map.mapScopeHistory.shift();  //removes the earliest scope object from the array

    caliper.map.mapScopeHistory.push(scope_string);
    };
    
caliper.map.clickBackToPreviousMap = function() {
    if (caliper.map.mapScopeHistory.length == 0) return;
    
    var request = caliper.map.getArguments();
    var prevMapButton = jQuery("#gisdk_previous_button");
    var simg = prevMapButton.attr("inactive");
    var mapScope = caliper.map.mapScopeHistory.pop();
    
    if (mapScope == caliper.map.map_scope ) {
        if (caliper.map.mapScopeHistory.length == 0) {
            prevMapButton.attr("src", simg);
            //save the scope of current map in hostory
            caliper.map.mapScopeHistory.push(mapScope);
            return;
            }
            
        //first time the Prev_Map button is clicked, the last scope in history object is the current map scope
        mapScope = caliper.map.mapScopeHistory.pop();
        }
        
    if (typeof(mapScope) == 'undefined' || mapScope == "") return;
    
    request.MapScope = mapScope;
    request.Command =  "prev_map";
    
    //set prev_map button image to be inactive
    if (caliper.map.mapScopeHistory.length == 0 && simg && simg.length > 5) {
        prevMapButton.attr("src", simg);
        //save the scope of current map in hostory
        caliper.map.mapScopeHistory.push(mapScope);
        }
        
    request.SkipMapHistory = true;

    caliper.map.showProgressbar();    
    
    caliper.mapService.DoMethod("MapService.RedrawMap", request, "MapControl.config", "MapControl", caliper.map.handler.onCompleteUpdateMap);
    };    

caliper.map.clickSaveExcel = function() {

    if (caliper.map.windwo_for_print && !caliper.map.windwo_for_print.closed) 
        caliper.map.windwo_for_print.close();
    
    caliper.map.windwo_for_print = window.open('PrintToExcel.aspx','PrintingWindow','width=800,resizable=yes,scrollbars=yes,toolbar=yes,location=yes,status=yes,menubar=yes');

    };
    
/**
 * Generate clear HTML table in the browser for printing.
 */
caliper.map.clickPrint = function() {
    var print_window;
    var window_contents;
    //var info_print_handler = caliper.info.print;
    var select_print_handler = caliper.select.print;


    if (caliper.map.windwo_for_print && !caliper.map.windwo_for_print.closed) 
        caliper.map.windwo_for_print.close();
    
    caliper.map.windwo_for_print = window.open('','PrintingWindow','width=800,resizable=yes,scrollbars=yes,toolbar=yes,location=yes,status=yes,menubar=yes');
    
    print_window = caliper.map.windwo_for_print;
        
    if (typeof(print_window) != "undefined" && print_window != null) {
        window_contents = "<link rel='stylesheet' href='styles.css' type='text/css'/>";
        
        window_contents = window_contents + "<table border=0 width=100%>";
  
        window_contents = window_contents + "<tr><td bgcolor='#ffff99' class='font_black_big' align='center' height='35'>" + CCUtil.getGisdkProperties("MapFile") + "</td></tr>";
        
        window_contents = window_contents + "<tr><td valign='top'><img src='" + caliper.map.map_url + "' border='1'><img src='" + caliper.map.map_legend_url + "' border='1'></td></tr>";

        if (typeof (info_print_handler) != 'undefined' && info_print_handler != null) {
            var info_contents = info_print_handler();
            
            if (info_contents != null) {
                window_contents = window_contents + "<tr><td align='center' bgcolor='#99ff99' class='font_black_bold'>Info records</td></tr>";
                window_contents = window_contents + "<tr><td>"+info_contents+"</td></tr>";
                }
            }

        if (typeof (select_print_handler) != 'undefined' && select_print_handler != null) {
            var select_contents = select_print_handler();
            
            if (select_contents != null) {
                window_contents = window_contents + "<tr><td align='center' bgcolor='#99ff99' class='font_black_bold'>Selection records</td></tr>";
                window_contents = window_contents + "<tr><td>"+select_contents+"</td></tr>";
                }
            }

        window_contents = window_contents + "</table>";
                       
        print_window.document.write(window_contents);
        print_window.document.close();
        }
        
    };    
    
caliper.map.startMapDragging = function() {
        if (CCUtil) CCUtil.startToolboxDragging("mapWindow");
    };
        
caliper.map.startToolboxDragging = function() {
        if (CCUtil) CCUtil.startToolboxDragging("mapToolBox");
    };
    
caliper.map.relocateIcon = function() {
    jQuery("#LegendIcon").css("top", CCUtil.getBrowserSize().height - 50);
    jQuery("#LegendIcon").css("left", 0);
    };
        
caliper.map.hideMapLegend = function() {
    jQuery("#legendWindow").css("visibility", "hidden");
    jQuery("#LegendIcon").css("visibility", "visible");
    caliper.map.legendVisible = false;
    caliper.map.relocateIcon();
    };
        
caliper.map.showMapLegend = function() {
    jQuery("#legendWindow").css("visibility", "visible");
    jQuery("#LegendIcon").css("visibility", "hidden");
    caliper.map.legendVisible = true;
    };
        

updateIcons = function() {
    jQuery("#MinIconContainer").css("top", CCUtil.getBrowserSize().height - 50);
    };    
    
    
    
/**
 ** handlers for services and messages
 **/    
/**
 * Get pre-defined quick-zoom levels. If the level array is not defined in MapControl.config, use the default one.
 */
caliper.map.handler.onCompleteMapSettings = function(arg) {
    var i, counter, zoomLevels;
    var LOW = 0, MID_LOW = 1, MEDIUM = 2, MID_HIGH = 3, HIGH=4;
    var height_shift = 10;
    
    caliper.map.map_width  = arg.ImageWidth;
    caliper.map.map_height = arg.ImageHeight;
    
    if (typeof(caliper.map.map_width) == 'undefined' || caliper.map.map_width == null || caliper.map.map_width <= 0)
        caliper.map.map_width = caliper.map.IMAGEWIDTH;
    if (typeof(caliper.map.map_height) == 'undefined' || caliper.map.map_height == null || caliper.map.map_height <= 0)
        caliper.map.map_height = caliper.map.IMAGEHEIGHT;
    
    if (typeof(arg.ZoomLevels) == "string") {
        zoomLevels = arg.ZoomLevels.split(",");

        if (zoomLevels.length == 1) //no parse
            zoomLevels = arg.ZoomLevels.split(" ");

        if (zoomLevels.length > 1) {
            caliper.map.zoomLevels = new Array(); //empty array  
            counter = 0;
                  
            for (i=0; i< zoomLevels.length; i++) {
                zoomLevels[i] = zoomLevels[i].trim();
                if (zoomLevels[i] != "" && zoomLevels[i] != null) {
                    caliper.map.zoomLevels[counter] = parseInt(zoomLevels[i]);
                    counter ++;
                    }
                }      
            } //if (zoomLevels.length > 1)
        } //if (typeof(arg.ZoomLevels) == "string")
        
    //adjust map image size according to screen resolution
    if (screen && typeof(arg.AdjustMapSize) == "string" && arg.AdjustMapSize.toUpperCase() == "YES" ) {
        if (screen.height >= 1024) {
            caliper.map.map_width  = caliper.map.mapSizes[HIGH]; //650
            caliper.map.map_height = caliper.map.mapSizes[HIGH];
            }
        else if (screen.height >= 768) {
            caliper.map.map_width  = caliper.map.mapSizes[MID_HIGH]; //500
            caliper.map.map_height = caliper.map.mapSizes[MID_HIGH];
            }
        else if (screen.height >= 600) {
            caliper.map.map_width  = caliper.map.mapSizes[MEDIUM]; //350
            caliper.map.map_height = caliper.map.mapSizes[MEDIUM];
            }
        else {
            caliper.map.map_width  = caliper.map.mapSizes[MID_LOW]; //300
            caliper.map.map_height = caliper.map.mapSizes[MID_LOW];
            }
        }    
    caliper.map.mapCenter = {x: caliper.map.map_width / 2, y: caliper.map.map_height / 2};
    
    caliper.map.mapContainer = dojo.byId("imgspan");

    if (CCUtil.BrowserDetect.browser == "Firefox" && CCUtil.BrowserDetect.version == 3)
        jQuery("#imgspan").css("position", "absolute");

    //create map image surface object on which map tools can draw rectangles, marks and circles
    caliper.map.mapSurface = dojox.gfx.createSurface(caliper.map.mapContainer,caliper.map.map_width , caliper.map.map_height);
    caliper.map.mapSurface.createRect({width: caliper.map.map_width, height: caliper.map.map_height});

    if (typeof (map_image_obj) != 'undefined') caliper.map.mapSurface.remove(map_image_obj);
    map_image_obj = null;

    map_image_obj = caliper.map.mapSurface.createImage({width: caliper.map.map_width, height: caliper.map.map_height, src: caliper.map.map_url});
    caliper.map.mapSurface.add(map_image_obj);

    var args = {
        "map_width":  caliper.map.map_width,
        "map_height": caliper.map.map_height,
        "surface":    caliper.map.mapSurface};
    CCUtil.init(args);
    caliper.map.shapeToolContainer = new CCUtil.selectionToolContainer({snapDist: caliper.map.SNAP_DISTANCE});


    if (!dojo.isIE) height_shift = 70;
    
    //adjust map frame width
    jQuery("#mapWindow").css("left", caliper.map.MAPWINDOWINITX);
    jQuery("#mapWindow").css("top", CCUtil.getControlPosition("MapControl"));
    jQuery("#mapWindow").css("width",caliper.map.map_width+5);
    jQuery("#mapWindow").css("height",caliper.map.map_height+height_shift);
    jQuery("#imgtable").css("height",caliper.map.map_height);
    
    jQuery("#mapToolBox").css("left",0);
    jQuery("#mapToolBox").css("top", CCUtil.getControlPosition("MapControl"));

    caliper.map.adjustZoomBarPosition();

    //initialize map parameters: map_url, map_scope
    if (typeof(caliper.chooseMap) == "undefined") {
        //set this callback message so that other controls (i.e. SelectControl) will be updated
        var arg = {};
        arg.callbackMessages = ["MSG_completeSelectingMap"];
        caliper.map.handler.redrawMap(null, arg);
        }

    //send message that the map image surface is ready
    jQuery("div.listener").trigger("MSG_completeMapSurface",null);  
    };

/**
 * gets called when other controls want to update map
 */
caliper.map.handler.redrawMap = function (event, arg)
    {
    if (arg == null) arg = {};
    
    caliper.map.updateMapCallbackMessages = arg.callbackMessages;

    if (arg.ImageFile) caliper.map.handler.onCompleteUpdateMap(arg);
    else 
        caliper.map.clickImageHandler(arg);
    };


/**
 * Update positions of map toolbox and legend pane
 */
caliper.map.handler.updatePosition = function() {
    var height_shift = dojo.isIE ? 103: 95;
    var width_shift  = dojo.isIE ? 8: 27;

////    jQuery("#legendWindow").css("left", caliper.map.MAPWINDOWINITX);
////    jQuery("#legendWindow").css("top", caliper.map.map_height + height_shift);
    jQuery("#legendWindow").css("left", caliper.map.MAPWINDOWINITX + caliper.map.map_width + width_shift);
    jQuery("#legendWindow").css("top", CCUtil.getControlPosition("MapControl"));

    if (!CCUtil.isDocked("MapControl")) return;

    jQuery("#mapToolBox").css("left",0);
    jQuery("#mapToolBox").css("top", CCUtil.getControlPosition("MapControl"));
    };
    
/**
 * After the toolbox is moved (dragged), check if it is in docking position, and change the toolbar color accordingly.
 * The actual position of the toolbox is adjusted by the MSG_updateToolboxPosition message sent from CCUtil.checkDocking()
 */
caliper.map.checkToolboxDocking = function() {
    if (CCUtil.checkDocking({top:jQuery("#mapToolBox").attr("offsetTop"), left:jQuery("#mapToolBox").attr("offsetLeft"), ControlName:"MapControl"})) 
        jQuery("#mapToolBox .title_bar").each(function() {
            this.className = "title_bar_dock";
            });
    else 
        jQuery("#mapToolBox .title_bar_dock").each(function() {
            this.className = "title_bar";
            });
    
    };            
    
/**
 * Update map image and legend image (if applicable), record current map scope and scale,
 * send messages to update other controls.
 */
caliper.map.handler.onCompleteUpdateMap = function(arg)
    {
    var targetMapWindow = null;
    var mapWidth, mapHeight;
    var imageSpanObj = null;
    var mapLegendObj = jQuery("#legendWindow #map_legend");
    var mapLegendWindow = jQuery("#legendWindow");
    var mapScaleDiv = jQuery("#mapScale");
    var mapScopeSegs, mapScopeWidth, mapScopeHeight;

    if (arg == null) return;
    if (arg.Message != "OK") {
        alert(arg.Message);
        return;
        }
       
    // store the last gisdk response in a global javascript object   
    if (arg) 
    {
        // update contents in gisdk_response
        CCUtil.setGisdkProperties(arg);
       
        if (arg.MapScope && (typeof (arg.SkipMapHistory) == 'undefined' || arg.SkipMapHistory == null)) 
            caliper.map.addToPreviousMapHistory(arg.MapScope);
        
        CCUtil.setGisdkProperties({SkipMapHistory: null});
            
    }

   if (arg.Annotation & typeof(arg.Annotation) == "array") { 
       caliper.Annotation = arg.Annotation;
   }

   if ( arg.MapFile && typeof(arg.MapFile) == "string")
    {
    var mapFile = arg.MapFile;

    //remove 'DATA\' prefix and '.map' suffix from mapFile string
    if (mapFile.substr(0,5).toUpperCase() == "DATA\\") 
        mapFile = mapFile.substr(5, mapFile.length -5);
    if (mapFile.substr(mapFile.length -4,4).toUpperCase() == ".MAP") 
        mapFile = mapFile.substr(0, mapFile.length -4);

    //replace '\' with ' - '
    mapFile = mapFile.replace(/\\/ig, " - ");
         
    jQuery("#map_name").html( mapFile );
    }
        
    if (arg && arg.ImageFile && caliper.map.mapSurface && map_image_obj)
        {
        //reset and recreate map image object
        caliper.map.map_url = caliper.map.gisdk_tempfile_folder + arg.ImageFile;
        caliper.map.map_scope = arg.MapScope;
        caliper.map.map_scale = arg.MapScale;
      
        caliper.map.mapSurface.remove(map_image_obj);
        map_image_obj = null;

        map_image_obj = caliper.map.mapSurface.createImage({width: caliper.map.map_width, height: caliper.map.map_height, src: caliper.map.map_url});
        caliper.map.mapSurface.add(map_image_obj);

        if (arg.Command != 'redraw_zoombar')  caliper.map.adjustZoomBarLevel();
        
        mapScopeSegs = arg.MapScope.split(" ");
        if (mapScopeSegs != null && mapScopeSegs.length == 5) {
            mapScopeWidth = Math.round(mapScopeSegs[2] * 100) / 100;
            mapScopeHeight = Math.round(mapScopeSegs[3] * 100) / 100;

            mapScaleDiv.html(" Scale: 1:"+arg.MapScale + " Center: Longitude "+mapScopeSegs[0]+" Latitude "+mapScopeSegs[1]+" size " +mapScopeWidth+" x "+mapScopeHeight+" " +mapScopeSegs[4]);
            }
        else
            mapScaleDiv.html(" Scale: 1:"+arg.MapScale + " Scope: "+arg.MapScope+"");
        
        //legend image
        if (arg.HideLegend || caliper.map.legendVisible == false) mapLegendWindow.css("visibility","Hidden");
        else if (typeof(arg.LegendFile) == 'undefined' || arg.LegendFile == null)
            mapLegendWindow.css("visibility","Hidden");
        else if (mapLegendObj[0]) {
            mapLegendWindow.css("visibility","visible");
            caliper.map.map_legend_url = caliper.map.gisdk_tempfile_folder + arg.LegendFile;
            mapLegendObj[0].src = caliper.map.map_legend_url;
            }
        
        //display map image object
        if (caliper.map.mapContainer) caliper.map.mapContainer.style.visibility="visible";
        
        //fire complete_updating_map message, controls may need to update themselves upon
        //the changes of the map (i.e. LayerControl needs to disable/enable layers in the list depending on
        //the display status of the layers
        jQuery("div.listener").trigger("MSG_completeUpdatingMap");

        //fire up callback messages if any
        if (caliper.map.updateMapCallbackMessages) {
            var message, i;
            for (i=0; i<caliper.map.updateMapCallbackMessages.length; i++) {
                message = caliper.map.updateMapCallbackMessages[i];
                jQuery("div.listener").trigger(message);
                }
                
            //clear the list so the call-backs won't be triggered over and over    
            caliper.map.updateMapCallbackMessages = null;
            }
        }

    caliper.map.hideProgressbar();            
        
    } ;

caliper.map.handler.closePrintWindow = function () {
    if (caliper.map.windwo_for_print && !caliper.map.windwo_for_print.closed) 
        caliper.map.windwo_for_print.close();

    };
     

/**
 ** Public functions
 **/    
 caliper.map.showProgressbar = function(timeout_limit) {
    if (typeof(timeout_limit) == 'undefined' || timeout_limit == null)
        timeout_limit = 3000; //3 seconds;
    else if (timeout_limit < 0 || timeout_limit > 30)
        timeout_limit = 15000; //15 seconds;
    else
        timeout_limit = timeout_limit * 1000;
        
    //turn on progress indicator, and set timer to turn if off after 15 seconds if it's not been hidden by
    //caliper.select.handler.onCompleteSelectApply(). 
    jQuery('#Progress_indicator').css("visibility", "visible");            
    setTimeout("caliper.map.hideProgressbar()", timeout_limit);
    };
    
 caliper.map.hideProgressbar = function() {
    jQuery('#Progress_indicator').css("visibility", "hidden");            
    };
    
caliper.map.getControlPaneHeight = function() {
    //height of map toolbox
    return 52;
    };    
    
caliper.map.displayHelp = function(contents) {
    jQuery("#helpContents").html(contents);
    jQuery("#HelpWindow").css("visibility", "visible");
    };
    
caliper.map.displayMaptoolHelp = function() {
    caliper.map.displayHelp(caliper.map.toolHelp);
    };    
    
caliper.map.closeHelpWindow = function() {
    jQuery("#HelpWindow").css("visibility", "hidden");
    };    