//Map.js
//Map Object
//  Handles the display of and user interaction with a map displayed on a map
//  panel.  Maintains extent state information, list of active / inactive
//  themes, etc.
//
//  If the vicinity map resource is an empty string, then no vicinity map will be used.

Map = function (newId,newConfigStruct)
{
  OBJECT_MANAGER.addControl(this,'map', newId);
  this.id        = newId;
  if (newConfigStruct)
    this.config = newConfigStruct;
  else
    this.config = null;
  this.mapNumber = 0;
  this.clientVersion = null;
  this.serverVersion = null;

  //interface objects
  this.mapImage       = null;
  this.vmapImage     = null;
  this.vmapPresent = false;
  this.bookmarkControl = null;
  this.labelControl = null;
  this.bufferControl = null;
  this.themeControl = null;
  this.selectionControl = null;
  this.coordConvControl = null;
  this.measureControl = null;

  //session specific data
  this.sessionID = null;
  this.extent    = new Array;        //extent of main map
  this.vmapExtent    = new Array;    //extent of vicinity map
  this.bookmarks = new Array();      //contains bookmarks for current session
  this.bookmark_redrawmaps = true;    //???
  this.legendVisible = null;          //is the legend currently displayed?
  this.legendSync    = false;         //does the legend match the current map display?
  this.numWaitingRequests = 0;        //counter for load image
  this.printOptions = null;
  return;
};

Map.prototype.setConfig = function(newConfig)
{
  this.config = newConfig;
  if (this.layerControl)
    this.layerControl.draw();
  if (this.labelControl)
    this.labelControl.setConfig(this.config.labelConfig);
  this.selectionsExist = false;
  var selectionCount = 0;
  this.buffersExist = false;
  var bufferCount = 0;
  for (var currentTheme in this.config.themes)
  {
    if (this.config.themes[currentTheme].selectOptions != null)
    {
      this.selectionsExist = true;
      selectionCount++;
    }
    if (this.config.themes[currentTheme].bufferOptions != null)
    {
      this.buffersExist = true;
      bufferCount++;
    }
  }
  this.vmapPresent = (this.config["vmap"]["resourceId"] != '');
  if (this.selectionControl)
    this.selectionControl.initialize();
  if (this.bufferControl)
    this.bufferControl.initialize(bufferCount);
  if (this.coordConvControl)
    this.coordConvControl.draw();
  if (this.measureControl)
    this.measureControl.draw();
};

Map.prototype.initialize = function(sessionID)
{
  var map0 = Array(this.config["resourceId"], this.config["previousStates"],this.mapImage.width(),this.mapImage.height(),false);
  if (this.vmapPresent)
  {
    var map1 = Array(this.config["vmap"]["resourceId"],0,this.vmapImage.width(),this.vmapImage.height(),true,0,this.config["vmap"]["slaveType"],this.config["vmap"]["boundBoxPercentMin"],this.config["vmap"]["styleSheet"]);
    var map_args = Array(map0,map1);
  }
  else
  {
    var map_args = Array(map0);
  }
  this.setWaiting(true);
  makeASyncPostRequest(this, 'Initialize', XMLRPC_URL,'GIS.Session.initialize',sessionID,map_args);
};

Map.prototype.setMapLoadImage = function(newImagePanel)
{
  this.mapLoadImage = newImagePanel;
};

Map.prototype.setMapImage = function(newMapImage)
{
  this.mapImage = newMapImage;
};

Map.prototype.setVmapLoadImage = function(newImagePanel)
{
  this.vmapLoadImage = newImagePanel;
};

Map.prototype.setVmapImage = function(newMapImage)
{
  this.vmapImage = newMapImage;
};

Map.prototype.setLegendImage = function(newLegendImage, newLegendVisibility)
{
  this.legendImage = newLegendImage;
  this.legendVisible = newLegendVisibility;   //initial visibility of legend; will it be displayed when the page loads?
  this.legendSync    = false;
};

Map.prototype.setWaiting = function(state)
{
  if (state)
  {
    this.mapLoadImage.show();
    if (this.vmapImage != null)
      this.vmapLoadImage.show();
    this.numWaitingRequests++;
  }
  else
  {
    this.numWaitingRequests--;
    if (this.numWaitingRequests <= 0)
    {
      this.mapLoadImage.hide();
      if (this.vmapImage != null)
        this.vmapLoadImage.hide();
    }
  }
};

Map.prototype.getMapDimensions = function()
{
  if (this.vmapImage != null)
    return Array(Array(this.mapImage.width(),this.mapImage.height()),Array(this.vmapImage.imageNode.cbe.width(),this.vmapImage.imageNode.cbe.height()));    
  else
    return Array(Array(this.mapImage.width(),this.mapImage.height()))
};

Map.prototype.loadLegend = function()
{
  this.setWaiting(true);
  makeASyncPostRequest(this,'Legend',XMLRPC_URL,'GIS.Legend.getImage',this.sessionID,0,this.config["legendAttributes"]["width"],this.config["legendAttributes"]["height"],this.config["legendAttributes"]["color"],this.config["legendAttributes"]["font"],this.config["legendAttributes"]["fontSize"],this.config["legendAttributes"]["valueFontSize"],this.config["legendAttributes"]["cellSpacing"]);
};

Map.prototype.loadLegendSync = function()
{
  var oldURL = this.legendImage.src; 
  this.setWaiting(true);
  var xmlrpcResponse = makeSyncPostRequest(XMLRPC_URL,'GIS.Legend.getImage',this.sessionID,0,this.config["legendAttributes"]["width"],this.config["legendAttributes"]["height"],this.config["legendAttributes"]["color"],this.config["legendAttributes"]["font"],this.config["legendAttributes"]["fontSize"],this.config["legendAttributes"]["valueFontSize"],this.config["legendAttributes"]["cellSpacing"]);
  var result = getXMLRPCResponseObject(xmlrpcResponse);
  if(result.data != null)
  {
    this.legendImage.src = this.correctURL(result.data);
    this.legendImage.cbe.moveTo('NW');
    this.legendSync = true;
  }
  else
    alert('Communication Error:  Unable to load legend image');
  this.setWaiting(false);
};

Map.prototype.click = function(evt, clickMode)
{
  var X = evt.offsetX;
  var Y = evt.offsetY;

  var MapWidth = this.mapImage.imageNode.cbe.width();
  var MapHeight = this.mapImage.imageNode.cbe.height();
  var XPercent = X / MapWidth;
  var YPercent = 1.0 -(Y / MapHeight);

  if (clickMode != 'ZoomBox')
    this.setWaiting(true);
  switch (clickMode)
  {
    case 'CoordConvSP2LatLon':
      var extentHeight = this.extent[1]-this.extent[0];
      var extentWidth = this.extent[3]-this.extent[2];
      var coords={x:XPercent*extentWidth+this.extent[2],y:YPercent*extentHeight+this.extent[0]};
      makeASyncPostRequest(this,clickMode,XMLRPC_URL,'CoordConv.SP.to.LL',this.config.projectionId,coords.x,coords.y);
      break;
    case 'MeasureDistance':  // ADDED-BY: JPW
      this.setWaiting(false);
      var mapImageX = this.mapImage.imageNode.cbe.left();
      var mapImageY = this.mapImage.imageNode.cbe.top();
      var measurePointX = mapImageX + X;
      var measurePointY = mapImageY + Y;
      var mapX = (XPercent * (this.extent[3]-this.extent[2])) + this.extent[2];  // XP * ExtentWidth + Left
      var mapY = (YPercent * (this.extent[1]-this.extent[0])) + this.extent[0];  // YP * ExtentHeight + Bottom
      this.measureControl.distanceAddPoint(mapX,mapY);
      this.measureControl.distanceAddPointImage(measurePointX,measurePointY,this.mapImage.imageNode.cbe.zIndex()+100);
      this.measureControl.distanceCalculate();
      break;
    case 'LabelLineAdd':  // ADDED-BY: JPW
      this.setWaiting(false);
      var mapImageX = this.mapImage.imageNode.cbe.left();
      var mapImageY = this.mapImage.imageNode.cbe.top();
      var gfxPointX = mapImageX + X;
      var gfxPointY = mapImageY + Y;
      this.labelControl.addLinePoint(XPercent,YPercent,gfxPointX,gfxPointY);
      break;
    case 'dEmail':
      break;
    case 'ZoomIn':
      makeASyncPostRequest(this,'ZoomIn',XMLRPC_URL,'GIS.Zoom.in.byPercent',this.sessionID,0,this.mapImage.imageNode.cbe.width(),this.mapImage.imageNode.cbe.height(),1.5,XPercent,YPercent);
      this.legendSync = false;
      break;
    case 'ZoomOut':
      makeASyncPostRequest(this,'ZoomOut',XMLRPC_URL,'GIS.Zoom.out.byPercent',this.sessionID,0,this.mapImage.imageNode.cbe.width(),this.mapImage.imageNode.cbe.height(),1.5,XPercent,YPercent);
      this.legendSync = false;
      break;
    case 'Center':
      makeASyncPostRequest(this,'Center',XMLRPC_URL,'GIS.Center.byPercent',this.sessionID,0,this.mapImage.imageNode.cbe.width(),this.mapImage.imageNode.cbe.height(),XPercent,YPercent);
      break;
    case 'Select':
      if (this.config.activeTheme != '')
      {
        if (this.config.themes[this.config.activeTheme].visibility && (this.config.themes[this.config.activeTheme].selectOptions != null)&&this.selectionsExist)   //only process if the theme is displayed and configured for selection
        {
          var activeThemeTolerance=-1;  // use the server-side default for this theme
          var activeThemeName = this.config.activeTheme;
          var GIS_stylesheet = this.config.themes[this.config.activeTheme].selectOptions.styleSheet;
          var fieldsList = this.config.themes[this.config.activeTheme].selectOptions.fieldList;
          var activeThemeMaxSelectCount = this.config.themes[this.config.activeTheme].selectOptions.limit;
          var requestDetails = new Object;
          requestDetails["request"] = 'newSelection';
          requestDetails["themeId"] = this.config.activeTheme;
          if(this.config.themes[this.config.activeTheme].selectOptions.sqlParams != null)
          {
            var configSQLParams = this.config.themes[this.config.activeTheme].selectOptions.sqlParams;
            var sqlParams = Array();
            for(var pos=0;pos < configSQLParams.length;pos++)
            {
              sqlParams[pos] = Array();
              sqlParams[pos][0] = configSQLParams[pos].pdqIdentifier;
              var fieldPairs = Array();
              var limits = Array();
              for(var lcv=0;lcv < configSQLParams[pos].fieldList.length;lcv++)
              {
                fieldPairs[lcv] = Array();
                fieldPairs[lcv][0] = configSQLParams[pos].fieldList[lcv].fieldName;
                fieldPairs[lcv][1] = configSQLParams[pos].fieldList[lcv].pdqFieldName;
              }
              sqlParams[pos][1] = fieldPairs;
              if (configSQLParams[pos].queryType != '')
              {
                limits[0] = configSQLParams[pos].queryType;
                limits[1] = configSQLParams[pos].numRows;
                limits[2] = configSQLParams[pos].startAt;
                sqlParams[pos][2] = limits;
              }
            }
            xypoints = Array(Array(XPercent,YPercent));
            coordsinpercent = true;
            makeASyncPostRequest(this.selectionControl,requestDetails,XMLRPC_URL,'GIS.Selection.entity.byPoint',this.sessionID,0,this.mapImage.imageNode.cbe.width(),this.mapImage.imageNode.cbe.height(),xypoints,coordsinpercent,activeThemeName,activeThemeTolerance,fieldsList,false,GIS_stylesheet,activeThemeMaxSelectCount,sqlParams);
          }
          else
          {
            xypoints = Array(Array(XPercent,YPercent));
            coordsinpercent = true;
            makeASyncPostRequest(this.selectionControl,requestDetails,XMLRPC_URL,'GIS.Selection.entity.byPoint',this.sessionID,0,this.mapImage.imageNode.cbe.width(),this.mapImage.imageNode.cbe.height(),xypoints,coordsinpercent,activeThemeName,activeThemeTolerance,fieldsList,false,GIS_stylesheet,activeThemeMaxSelectCount);
          }
          return;
        }
        else
        {
          this.setWaiting(false);
        }
      }
      else
        this.setWaiting(false);
      break;
    case 'LabelPointAdd':
      var labelName = this.labelControl.getActiveSymbolString();
      var themeName = this.labelControl.activeTheme;
      var request = 'GIS.DrawPlane.add.Point';
      var labelConfigIndex = this.labelControl.activeSymbol;
      var stylesheet = this.config.labelConfig.pointLabels[labelConfigIndex].styleSheet;
      var pointArray = Array(Array(XPercent,YPercent));  // only one point in this case
      var extentArray = Array(this.extent[0],this.extent[1],this.extent[2],this.extent[3]);
      var requestInfo = new Object();
        requestInfo.mode = clickMode;
        requestInfo.labelConfigIndex = labelConfigIndex;
        requestInfo.labelName = labelName;
        requestInfo.themeName = themeName;
        requestInfo.extentArray = extentArray;

      makeASyncPostRequest(this.labelControl,requestInfo,XMLRPC_URL,request,this.sessionID,0,this.mapImage.imageNode.cbe.width(),this.mapImage.imageNode.cbe.height(),Array(pointArray),false,themeName,stylesheet);
      break;

    case 'LabelTextAdd':
      var labelName = this.labelControl.getActiveTextString();
      var themeName = this.labelControl.activeTheme;
      var request = 'GIS.DrawPlane.add.Text';
      var labelConfigIndex = this.labelControl.activeText;
      var stylesheet = this.config.labelConfig.textLabels[labelConfigIndex].styleSheet;
      var pointArray = Array(Array(XPercent,YPercent));  // only one point in this case
      var extentArray = Array(this.extent[0],this.extent[1],this.extent[2],this.extent[3]);

      var requestInfo = new Object();
        requestInfo.mode = clickMode;
        requestInfo.labelConfigIndex = labelConfigIndex;
        requestInfo.labelName = labelName;
        requestInfo.themeName = themeName;
        requestInfo.extentArray = extentArray;

      makeASyncPostRequest(this.labelControl,requestInfo,XMLRPC_URL,request,this.sessionID,0,this.mapImage.imageNode.cbe.width(),this.mapImage.imageNode.cbe.height(),Array(pointArray),false,themeName,stylesheet,labelName);
      break;

    case 'BufferXY':
      var bufferDistance = this.bufferControl.getDistance();
      var bufferTheme = this.bufferControl.getActiveTheme();
      var bufferThemeParams = this.config.themes[bufferTheme].bufferOptions;
      var GIS_stylesheet = this.config.themes[bufferTheme].bufferOptions.styleSheet;
      var bufferFieldList = this.config.themes[bufferTheme].bufferOptions.fieldList;
      var clearFirst = true;
      var MaxBufferCount = this.config.themes[bufferTheme].bufferOptions.maxSelect;

      var bufferSQLparams = this.bufferControl.getSQLParams();
      if(this.config.themes[bufferTheme].bufferOptions.sqlParams != null)
      {
        var configSQLParams = this.config.themes[bufferTheme].bufferOptions.sqlParams;
        var sqlParams = Array();
        for(var pos=0;pos < configSQLParams.length;pos++)
        {
          sqlParams[pos] = Array();
          sqlParams[pos][0] = configSQLParams[pos].pdqIdentifier;
          var fieldPairs = Array();
          var limits = Array();
          for(var lcv=0;lcv < configSQLParams[pos].fieldList.length;lcv++)
          {
            fieldPairs[lcv] = Array();
            fieldPairs[lcv][0] = configSQLParams[pos].fieldList[lcv].fieldName;
            fieldPairs[lcv][1] = configSQLParams[pos].fieldList[lcv].pdqFieldName;
          }
          sqlParams[pos][1] = fieldPairs;
          if (configSQLParams[pos].queryType != '')
          {
            limits[0] = configSQLParams[pos].queryType;
            limits[1] = configSQLParams[pos].numRows;
            limits[2] = configSQLParams[pos].startAt;
            sqlParams[pos][2] = limits;
          }
        }
      }
      else
        var sqlParams = new Array();
      if (bufferSQLparams == null)
        makeASyncPostRequest(this.bufferControl,Array('BufferXY',bufferTheme),XMLRPC_URL,'GIS.Buffer.at.XY',this.sessionID,0,MapWidth,MapHeight,XPercent,YPercent,true,bufferTheme,bufferDistance,bufferFieldList,clearFirst,GIS_stylesheet,MaxBufferCount,sqlParams);
      else
        makeASyncPostRequest(this.bufferControl,Array('BufferXY',bufferTheme),XMLRPC_URL,'GIS.Buffer.at.XY',this.sessionID,0,MapWidth,MapHeight,XPercent,YPercent,true,bufferTheme,bufferDistance,bufferFieldList,clearFirst,GIS_stylesheet,MaxBufferCount,sqlparams,bufferSQLparams);
      break;
  }
  return;
};

Map.prototype.bufferOnSelection = function(newSelectionHandle, newSourceTheme, newTargetTheme, newDistance, newSQLParams, newBufferSQLParams, newClearFirst)
{
  var bufferThemeParams = this.config.themes[newTargetTheme].bufferOptions;
  var GIS_stylesheet = this.config.themes[newTargetTheme].bufferOptions.styleSheet;
  var bufferFieldList = this.config.themes[newTargetTheme].bufferOptions.fieldList;
  var MaxBufferCount = this.config.themes[newTargetTheme].bufferOptions.maxSelect;
  var MapWidth = this.mapImage.imageNode.cbe.width();
  var MapHeight = this.mapImage.imageNode.cbe.height();

  this.setWaiting(true);
  if (newBufferSQLParams == null)
    makeASyncPostRequest(this.bufferControl,Array('BufferOnSelection',newTargetTheme),XMLRPC_URL,'GIS.Buffer.on.Selection',this.sessionID,0,MapWidth,MapHeight,newSelectionHandle,newSourceTheme,newTargetTheme,newDistance,bufferFieldList,newClearFirst,GIS_stylesheet,MaxBufferCount,newSQLParams);
  else
    makeASyncPostRequest(this.bufferControl,Array('BufferOnSelection',newTargetTheme),XMLRPC_URL,'GIS.Buffer.on.Selection',this.sessionID,0,MapWidth,MapHeight,newSelectionHandle,newSourceTheme,newTargetTheme,newDistance,bufferFieldList,newClearFirst,GIS_stylesheet,MaxBufferCount,newSQLParams,newBufferSQLParams);
};

Map.prototype.clickVmap = function (evt)  // ASYNC
{
  var X = evt.offsetX;
  var Y = evt.offsetY;

  var MapWidth  = this.vmapImage.imageNode.cbe.width();
  var MapHeight = this.vmapImage.imageNode.cbe.height();

  var XPercent = X / MapWidth;
  var YPercent = 1.0 - (Y / MapHeight);

  var mapX = (XPercent * (this.vmapExtent[3]-this.vmapExtent[2])) + this.vmapExtent[2];  // XP * ExtentWidth + Left
  var mapY = (YPercent * (this.vmapExtent[1]-this.vmapExtent[0])) + this.vmapExtent[0];  // YP * ExtentHeight + Bottom

  this.setWaiting(true);
  makeASyncPostRequest(this,'CenterOnPoint',XMLRPC_URL,'GIS.Center.onPoint',this.sessionID,0,this.mapImage.imageNode.cbe.width(),this.mapImage.imageNode.cbe.height(),mapX,mapY);
};

Map.prototype.pan = function(DirStr)
{
  this.setWaiting(true);
  var mapData = makeASyncPostRequest(this,'Pan',XMLRPC_URL,'GIS.Pan.byDirection',this.sessionID,0,this.mapImage.imageNode.cbe.width(),this.mapImage.imageNode.cbe.height(),DirStr,0.4);
};

Map.prototype.zoomInitialExtent = function()
{
  this.setWaiting(true);
  this.legendSync = false;
  makeASyncPostRequest(this,'ZoomInitialExtent',XMLRPC_URL,'GIS.Zoom.to.initialExtent',this.sessionID,0,this.mapImage.imageNode.cbe.width(),this.mapImage.imageNode.cbe.height());
};

Map.prototype.zoomTo = function(themeIndex, SQLstr, select)
{
  this.setWaiting(true);
  this.legendSync = false;
  if (!this.selectionsExist)
    select = false;
  var GIS_stylesheet = this.config.themes[themeIndex].selectOptions.styleSheet;
  if (select)
  {
    var requestDetails = new Object;
    requestDetails["request"] = 'newSelection';
    requestDetails["themeId"] = themeIndex;
    if(this.config.themes[themeIndex].selectOptions.sqlParams != null)
    {
      var configSQLParams = this.config.themes[themeIndex].selectOptions.sqlParams;
      var sqlParams = Array();
      for(var pos=0;pos < configSQLParams.length;pos++)
      {
        sqlParams[pos] = Array();
        sqlParams[pos][0] = configSQLParams[pos].pdqIdentifier;
        var fieldPairs = Array();
        var limits = Array();
        for(var lcv=0;lcv < configSQLParams[pos].fieldList.length;lcv++)
        {
          fieldPairs[lcv] = Array();
          fieldPairs[lcv][0] = configSQLParams[pos].fieldList[lcv].fieldName;
          fieldPairs[lcv][1] = configSQLParams[pos].fieldList[lcv].pdqFieldName;
        }
        sqlParams[pos][1] = fieldPairs;
        if (configSQLParams[pos].queryType != '')
        {
          limits[0] = configSQLParams[pos].queryType;
          limits[1] = configSQLParams[pos].numRows;
          limits[2] = configSQLParams[pos].startAt;
          sqlParams[pos][2] = limits;
        }
      }
      makeASyncPostRequest(this.selectionControl,requestDetails,XMLRPC_URL,'GIS.Zoom.to.entities',this.sessionID,0,this.mapImage.width(),this.mapImage.height(),themeIndex,this.config.themes[themeIndex].selectOptions.fieldList,SQLstr,this.config.themes[themeIndex].selectOptions.zoomExtentRatio,1,select,select,false,GIS_stylesheet,sqlParams);
    }
    else
      makeASyncPostRequest(this.selectionControl,requestDetails,XMLRPC_URL,'GIS.Zoom.to.entities',this.sessionID,0,this.mapImage.width(),this.mapImage.height(),themeIndex,this.config.themes[themeIndex].selectOptions.fieldList,SQLstr,this.config.themes[themeIndex].selectOptions.zoomExtentRatio,1,select,select,false,GIS_stylesheet);
  }
  else
  {
    makeASyncPostRequest(this,'zoomTo',XMLRPC_URL,'GIS.Zoom.to.entities',this.sessionID,0,this.mapImage.width(),this.mapImage.height(),themeIndex,this.config.themes[themeIndex].selectOptions.fieldList,SQLstr,this.config.themes[themeIndex].selectOptions.zoomExtentRatio,1,select,select,false,GIS_stylesheet);
  }
};

Map.prototype.zoomToSelection = function(themeIndex, SQLstr, select)
{
  this.setWaiting(true);
  this.legendSync = false;
  var GIS_stylesheet = this.config.themes[themeIndex].selectOptions.styleSheet;
  if (select)
  {
    if(this.config.themes[themeIndex].selectOptions.sqlParams != null)
    {
      var configSQLParams = this.config.themes[themeIndex].selectOptions.sqlParams;
      var sqlParams = Array();
      for(var pos=0;pos < configSQLParams.length;pos++)
      {
        sqlParams[pos] = Array();
        sqlParams[pos][0] = configSQLParams[pos].pdqIdentifier;
        var fieldPairs = Array();
        var limits = Array();
        for(var lcv=0;lcv < configSQLParams[pos].fieldList.length;lcv++)
        {
          fieldPairs[lcv] = Array();
          fieldPairs[lcv][0] = configSQLParams[pos].fieldList[lcv].fieldName;
          fieldPairs[lcv][1] = configSQLParams[pos].fieldList[lcv].pdqFieldName;
        }
        sqlParams[pos][1] = fieldPairs;
        if (configSQLParams[pos].queryType != '')
        {
          limits[0] = configSQLParams[pos].queryType;
          limits[1] = configSQLParams[pos].numRows;
          limits[2] = configSQLParams[pos].startAt;
          sqlParams[pos][2] = limits;
        }
      }
      makeASyncPostRequest(this,'zoomToSelection',XMLRPC_URL,'GIS.Zoom.to.entities',this.sessionID,0,this.mapImage.imageNode.cbe.width(),this.mapImage.imageNode.cbe.height(),themeIndex,"*",SQLstr,this.config.themes[themeIndex].selectOptions.zoomExtentRatio,1,select,select,false,GIS_stylesheet,sqlParams);
    }
    else
      makeASyncPostRequest(this,'zoomToSelection',XMLRPC_URL,'GIS.Zoom.to.entities',this.sessionID,0,this.mapImage.imageNode.cbe.width(),this.mapImage.imageNode.cbe.height(),themeIndex,"*",SQLstr,this.config.themes[themeIndex].selectOptions.zoomExtentRatio,1,select,select,false,GIS_stylesheet);
  }
  else
    makeASyncPostRequest(this,'zoomToSelection',XMLRPC_URL,'GIS.Zoom.to.entities',this.sessionID,0,this.mapImage.imageNode.cbe.width(),this.mapImage.imageNode.cbe.height(),themeIndex,"*",SQLstr,this.config.themes[themeIndex].selectOptions.zoomExtentRatio,1,select,select,false,GIS_stylesheet);
};

Map.prototype.zoomToExtent = function(newExtent)
{
  this.setWaiting(true);
  this.legendSync = false;
  makeASyncPostRequest(this,'ZoomToExtent',XMLRPC_URL,'GIS.Zoom.to.extent',this.sessionID,0,this.mapImage.imageNode.cbe.width(),this.mapImage.imageNode.cbe.height(),newExtent);
};

Map.prototype.refresh = function()
{
  this.setWaiting(true);
  makeASyncPostRequest(this,'MapRedraw',XMLRPC_URL,'GIS.Map.redraw',this.sessionID,0,this.mapImage.imageNode.cbe.width(),this.mapImage.imageNode.cbe.height());
};

Map.prototype.redraw = function()
{
  this.setWaiting(true);
  makeASyncPostRequest(this,'MapRedraw',XMLRPC_URL,'GIS.Map.redraw',this.sessionID,0,this.mapImage.imageNode.cbe.width(),this.mapImage.imageNode.cbe.height());
};

Map.prototype.back = function()
{
  this.setWaiting(true);
  this.legendSync = false;
  makeASyncPostRequest(this,'ZoomPrevious',XMLRPC_URL,'GIS.Zoom.to.previousExtent',this.sessionID,0,this.mapImage.imageNode.cbe.width(),this.mapImage.imageNode.cbe.height());
};

Map.prototype.zoomBoxDrawn = function(x1,y1, x2,y2)
{
  if(x1 < x2)
  {
    var the_left = x1;
    var the_right = x2;
  }
  else
  {
    var the_left = x2;
    var the_right = x1;
  }
  if(y1 < y2)  // use reverse direction since web is flipped from gis
  {
    var the_top = y1;
    var the_bottom = y2;
  }
  else
  {
    var the_top = x2;
    var the_bottom = x1;
  }
  var MapWidth = this.mapImage.width();
  var MapHeight = this.mapImage.height();
  var the_bottom = 1.0 -(the_bottom / MapHeight);
  var the_top    = 1.0 -(the_top / MapHeight);
  var the_left   = the_left / MapWidth;
  var the_right  = the_right / MapWidth;

  this.setWaiting(true);
  this.legendSync = false;
  makeASyncPostRequest(this,'ZoomWindow',XMLRPC_URL,'GIS.Zoom.to.windowPercent',this.sessionID,0,this.mapImage.imageNode.cbe.width(),this.mapImage.imageNode.cbe.height(),the_bottom,the_top,the_left,the_right);
};

Map.prototype.zoombar = function (ratio,divnum,numdivs)
{
  this.setWaiting(true);
  this.legendSync = false;
  makeASyncPostRequest(this,'ZoomBar',XMLRPC_URL,'GIS.Zoom.by.bar',this.sessionID,0,this.mapImage.imageNode.cbe.width(),this.mapImage.imageNode.cbe.height(),ratio,divnum,numdivs);
};

Map.prototype.setThemes = function(newThemeList)
{
  for (i=0; i<newThemeList.length; i++)
  {
    this.themeLookup[newThemeList[i][0]] = i;
    this.themes[i] = new Array(newThemeList[i], "off");
  }
};

Map.prototype.getThemeByName = function(newThemeName)
{
  return this.themes[this.themeLookup[newThemeName]];
};

Map.prototype.setActiveTheme = function(newActiveTheme)
{
  this.config.activeTheme = newActiveTheme;
  if (this.layerControl)
    this.layerControl.update();
};

Map.prototype.getBookmarkList = function ()
{
  //does not set the load image since it does not interfere with map operations
  if (this.bookmarkControl)
    makeASyncPostRequest(this,'getBookmarkList',XMLRPC_URL,'GIS.Geobookmark.get.list',this.sessionID);
};

Map.prototype.addBookmark = function (name)
{
  if (name != '')
    makeASyncPostRequest(this,'addBookmark',XMLRPC_URL,'GIS.Geobookmark.add.state',this.sessionID,0,name,false,false);
};

Map.prototype.gotoBookmark = function (bookmarkIndex)
{
  var name = this.bookmarks[bookmarkIndex];  
  this.setWaiting(true);
  this.legendSync = false;
  makeASyncPostRequest(this,'gotoBookmark',XMLRPC_URL,'GIS.Geobookmark.restore.state',this.sessionID,0,name,this.bookmark_redrawmaps,true,true,true,false);
};

Map.prototype.removeBookmark = function(bookmarkIndex)
{
  var name = this.bookmarks[bookmarkIndex];  
  this.setWaiting(true);
  makeASyncPostRequest(this,'removeBookmark',XMLRPC_URL,'GIS.Geobookmark.remove.state',this.sessionID,name);
};

Map.prototype.loadThemes = function()
{
  this.setWaiting(true);
  makeASyncPostRequest(this,'getThemes',XMLRPC_URL,'GIS.Themes.getList',this.sessionID,0);
};

Map.prototype.setThemeState = function(themeName, visible)
{
  var themeArray = new Array();                               //array of theme information to pass to server

  themeArray[0] = new Array();                            //an individual theme
  themeArray[0][0] = themeName;       //fetch theme name
  themeArray[0][1] = visible;                             //new state
  this.config["themes"][themeName]["visibility"] = visible;
  this.legendSync = false;
  makeASyncPostRequest(this, 'setThemes', XMLRPC_URL, 'GIS.Themes.setList', this.sessionID, 0, themeArray);
};

Map.prototype.clearSelection = function(themeIndex, selectionHandle)
{
  var requestDetails = new Object;
  requestDetails.request = 'clearSelection';
  requestDetails.themeIndex = themeIndex;
  requestDetails.handle = selectionHandle;

  this.setWaiting(true);
  var mapData = makeASyncPostRequest(this.selectionControl,requestDetails,XMLRPC_URL,'GIS.Selection.clear.EntityFromTheme',this.sessionID,0,themeIndex, selectionHandle, this.mapImage.imageNode.cbe.width(),this.mapImage.imageNode.cbe.height());
};

Map.prototype.clearThemeSelections = function(themeIndex)
{
  var requestDetails = new Object;
  requestDetails.request = 'clearTheme';
  requestDetails.themeIndex = themeIndex;

  this.setWaiting(true);
  var mapData = makeASyncPostRequest(this.selectionControl,requestDetails,XMLRPC_URL,'GIS.Selection.clear.AllFromTheme',this.sessionID,0,themeIndex);
};

Map.prototype.clearSyncSelection = function(themeIndex, selectionHandle)
{
  this.setWaiting(true);
  var xmlrpcResponse = makeSyncPostRequest(XMLRPC_URL,'GIS.Selection.clear.EntityFromTheme',this.sessionID,0,this.themes[themeIndex][0][0], selectionHandle, this.mapImage.imageNode.cbe.width(),this.mapImage.imageNode.cbe.height());
  var mapData = getXMLRPCResponseObject(xmlrpcResponse);
  this.setWaiting(false);
};

Map.prototype.clearThemeBuffer = function(themeName,bufferHandle)
{
  this.setWaiting(true);
  makeASyncPostRequest(this.bufferControl,Array('clearThemeBuffer',themeName,bufferHandle),XMLRPC_URL,'GIS.Buffer.clear.FromTheme',this.sessionID,0,themeName, bufferHandle, this.mapImage.imageNode.cbe.width(),this.mapImage.imageNode.cbe.height());
};

Map.prototype.callback = function(serverReplyDoc, pendingOperation)
{
  var clearMeasurePoints = false;
  if (!validateXMLDoc(serverReplyDoc))
  {
    this.setWaiting(false);
    this.refresh();
    return null;
  }

  var clientReply = new XMLRPCResponse();
  //clientReply.setResponseByStr(serverReplyDoc.xml);
  clientReply.setResponseByDoc(serverReplyDoc);
  if(clientReply.isFault())
  {
    var data = null;
  }
  else
    var data = clientReply.getObject();
  if((data != null))
  {
    switch (pendingOperation)
    {
      case 'CoordConvSP2LatLon':  // ADDED-BY: JPW
        if (this.coordConvControl)
          this.coordConvControl.callback(data,pendingOperation);
        break;
      case 'Initialize':
      
        this.extent = data[0][1];
        this.mapImage.imageNode.src = this.correctURL(data[0][0]);
        if (this.vmapPresent)
        {
          this.vmapImage.imageNode.src = this.correctURL(data[1][0]);
          this.vmapExtent = data[1][1];
        }
        this.sessionID = data[data.length-1];
        document.setSessionID(this.sessionID);
        this.extent = Array(data[0][1][0],data[0][1][1],data[0][1][2],data[0][1][3]); //btlr
        this.loadThemes();
        this.loadLegend();
        this.getBookmarkList();
        if (this.labelControl != null)
          this.labelControl.initialize();
        if (this.selectionControl != null)
        {
          this.selectionControl.initialize();
        }
        if (this.onInitialize)
          this.onInitialize();
        break;
      case 'getThemes':
        for (i = 0; i < data.length; i++){
          try{
            this.config["themes"][data[i][0]]["visibility"] = data[i][1];
          }
          catch(e)
          {
            alert('Warning:\nUnable to set the visibility for map layer "'+data[i][0]+'"\nThere may be a mismatch between the client configuration and the map resource.');
          }
        }
        if (this.layerControl)
          this.layerControl.update();
        break;
      case 'setThemes':
        break;
      case 'Legend':
        this.legendImage.src = this.correctURL(data);
        this.legendImage.cbe.moveTo('NW');
        this.legendSync = true;
        break;
      case 'LoadLayers':
        break;
      case 'getBookmarkList':
        if (this.bookmarkControl)
          this.bookmarkControl.callback(data,'getBookmarkList');
        break;
      case 'addBookmark':
        if (this.bookmarkControl)
          this.bookmarkControl.callback(data,'addBookmark');
        this.getBookmarkList();
        break;
      case 'removeBookmark':
        if (this.bookmarkControl)
          this.bookmarkControl.callback(data,'removeBookmark');
        this.getBookmarkList();
        break;
      case 'gotoBookmark':
        this.mapImage.imageNode.src = this.correctURL(data[0][1]);
        if (this.vmapPresent)
           this.vmapImage.imageNode.src = this.correctURL(data[1][1]);
        this.extent = Array(data[0][2][0],data[0][2][1],data[0][2][2],data[0][2][3]); //btlr
        this.loadThemes();
        if (this.legendVisible)
          this.loadLegend();
        clearMeasurePoints = true;
        break;
      case 'Select':
        break;
      case 'LabelPointAdd':
      case 'LabelTextAdd':
      case 'LabelLineSave':
        this.mapImage.imageNode.src = this.correctURL(data[0][0][1]);
        if (this.vmapPresent)
          this.vmapImage.imageNode.src = this.correctURL(data[0][1][1]);
        break;
      case 'DeleteLabel':
        this.extent = Array(data[0][2][0],data[0][2][1],data[0][2][2],data[0][2][3]); //btlr
        this.mapImage.imageNode.src = this.correctURL(data[0][1]);
        break;
      case 'dEmail':
        break;
      case 'BufferXY':
        this.extent = Array(data[0][0][2][0],data[0][0][2][1],data[0][0][2][2],data[0][0][2][3]); //btlr
        this.mapImage.imageNode.src = this.correctURL(data[0][0][1]);
        if (this.vmapPresent)
          this.vmapImage.imageNode.src = this.correctURL(data[0][1][1]);
        break;
      case 'zoomTo':
      case 'zoomToSelection':
        this.mapImage.imageNode.src = this.correctURL(data[0][0][1]);
        if (this.vmapPresent)
          this.vmapImage.imageNode.src = this.correctURL(data[0][1][1]);
        if (this.legendVisible)
          this.loadLegend;
        clearMeasurePoints = true;
        break;
      case 'printMap':
        document.printMap(data);
        break;
      case 'getExportedMap':
        this.downloadExportedMap(data);
        break;
      default:
        this.extent = Array(data[0][2][0],data[0][2][1],data[0][2][2],data[0][2][3]); //btlr
        this.mapImage.imageNode.src = this.correctURL(data[0][1]);
        if (this.vmapPresent)
          this.vmapImage.imageNode.src = this.correctURL(data[1][1]);
        if (this.legendVisible && !this.legendSync)
        {
          this.loadLegend();
        }
        clearMeasurePoints = true;
        break;
    }
  }
  else
  {
    switch(parseInt(clientReply.getFaultCode()))
    {
      case 1018: // No Buffer elements found
        break;
      default:
        alert('A Server Error occurred in a Map request.\n\nOperation:  '+pendingOperation+'\nFault Code: '+clientReply.getFaultCode()+'\nError Message:\n'+clientReply.getFaultString());
    }
  }
  if ((this.measureControl != null) && clearMeasurePoints)
  {
    this.measureControl.distanceReset();
  }
  this.setWaiting(false);
};

Map.prototype.selectionCallback = function (data)
{
  var returnValue;
  if (data)
  {
    this.mapImage.imageNode.src = this.correctURL(data[0][1]);
    if (this.vmapPresent)
      this.vmapImage.imageNode.src = this.correctURL(data[1][1]);
    returnValue = true;
  }
  else
    returnValue = null;
  this.setWaiting(false);
  if (this.onSelect)
    this.onSelect();
  return returnValue;
};

Map.prototype.correctURL = function (newURL)
{
  var returnValue = newURL;
  if (returnValue.substr(0,1) == '/')  //trying to deal with relative paths
  {
    returnValue = 'http://'+this.config["imsHostname"]+newURL;
  }
  else
  {
    var url = /(\w+):\/\/([^\/]+)\/(\S*)/;
    var result = newURL.match(url);
    if (result == null)
      returnValue = newURL;  // setup doesn't have an ip or fully qualified name separated w/ .'s
    else
      returnValue = result[1]+'://'+this.config["imsHostname"]+'/'+result[3];
  }
  return returnValue;
};


Map.prototype.exportMap = function()
{
  this.setWaiting(true);
  makeASyncPostRequest(this,'getExportedMap',XMLRPC_URL,'ArcIMS.Map.export',this.sessionID,0,this.mapImage.imageNode.cbe.width(),this.mapImage.imageNode.cbe.height());
};
Map.prototype.downloadExportedMap = function(url)
{
  url = this.correctURL(url);
  downloadFile(url);
};

Map.prototype.print = function()
{
  //arguments[0] = array of name,value pairs for placeholder variables
  var placeholderVariables = new Array();
  if (this.config.printConfig.defaultTemplate == -1)
  {
    alert('Freeance Internal Error:  Unable to Print.\nReason:  No print configurations have been defined.');
  }
  else
  {
    this.loadLegendSync();
    this.setWaiting(true);
    placeholderVariables[0] = Array('legendImage',this.legendImage.src);

    if (this.vmapPresent)
      placeholderVariables[1] = Array('vmapImage',this.vmapImage.imageNode.src);
    else
      placeholderVariables[1] = Array('vmapImage',GuiWidget.THEME_PATH+'/'+GuiWidget.THEME+'/images/blank.gif');
    if (arguments.length > 0)
    {
      for (var i=0;i<arguments[0].length;i++)  //process placeholders
      {
        placeholderVariables[i+2] = Array(arguments[0][i][0],arguments[0][i][1]);
      }
    }
    var xmlrpcResponse = makeASyncPostRequest(this,'printMap',XMLRPC_URL,'PDFPrint.Template.Map',this.config.printConfig.templates[this.config.printConfig.activeTemplate].templateName,placeholderVariables,document.sessionID,0,this.mapImage.width(),this.mapImage.height(),5,[],[]);
  }
};


