/****************************************************************************
 * @file          map.js
 *
 * @project       YAMI (Yet Another Mapping Interface)
 * @contributors  Rose Jackson, William Garrick, Eric Hanson, Morgan Harvey,
 *                Cristopher Holm, David Percy       
 * 
 * Copyright (c) 2006, Academic & Research Computing, Portland State 
 *                University, Portland Oregon.
 * 
 ***************************************************************************/

// resize handler
var timerID;
function resizeToWindow() {
  if (map.isDrawn) {
    window.clearTimeout(timerID);
    timerID=window.setTimeout('map.resizeMap()',500);
	}
}

var map_http_request,state_http_request;
var res;

/*******************************************************************
* Map - the main map object
* this object handles all map related queries and functionality
*******************************************************************/ 
function Map() {
  this.isDrawn=false;
  this.resizeToFitWindow=true;
  this.minx=this.miny=this.maxx=this.maxy=0;
  this.maxScale=0;
  this.minScale=10000;
  this.assignedInfoTabIds=new Array();
  this.assignedInfoTabNames=new Array();
  this.latestQueryDestination="";
  
	// init gets called onload.  it's responsible for setting up first time stuff
  this.init=function() {
    // point our div pointers to the actual div elements
    if (this.resizeToFitWindow) {
      window.onresize=resizeToWindow;
    }
    
    this.mapfile=document.getElementById("mapfile");
    this.session_id=document.getElementById("session_id");
    
    // point our div pointers to the actual div elements
    this.mapdiv=document.getElementById("map");
    this.mapimg=document.getElementById("map_img");
    this.loadingdiv=document.getElementById("loading");
    this.headerdiv=document.getElementById("header");
    this.updatediv=document.getElementById("update");
    this.panelsdiv=document.getElementById("panels");
    this.toolspaneldiv=document.getElementById("tools_panel");
    this.groupspaneldiv=document.getElementById("groups_panel");
    this.refmapdiv = document.getElementById ('refmap');
    
    this.queryString="";
    this.mapImage=document.getElementById("map_image");
    this.setCoordinates();
  }
  
  /***************************************************************************
  there are 4 fundamental types of events that can change a map:
    1) the contents of the map are changed (i.e. - layers turned on/off)
    2) the viewable area that the map displays changes (i.e. - zoom)
    3) the content displayed remains unchanged but is alterer to appear 
       differently (i.e. - colors change from color to greyscale)
    4) the projection changes  
  ****************************************************************************/
  
  /***************************************************************************
   * updateMap
   * tells the map object that the map needs to be redrawn with new data 
   * (new extents, new layers, new colors, etc). the redraw parameter is a
   * boolean that describes whether or not to redraw the map immediately. it
   * is the reponsibility of the caller to add any addition query string
   * parameters that may be needed.
   ***************************************************************************/
  this.updateMap=function(queryString,redraw) {
    this.setQueryString();
    if (queryString && queryString.length>0)
      this.queryString+="&"+queryString;
    if (redraw) this.draw();
    //percy added this to force a redraw of the legend
    //drawLegend();
  }
  
  this.resizeMap=function() {
    var newWidth=null,newHeight=null;
    var top=0,left=0,headerHeight=0;

    if (this.headerdiv.style && this.headerdiv.style.height)
      headerHeight=parseInt(this.headerdiv.style.height);
    else if (this.headerdiv.clientHeight)
      headerHeight=this.headerdiv.clientHeight;
    else
      headerHeight=this.headerdiv.offsetHeight;
    headerHeight+=1;
    top=headerHeight;

    this.panelsdiv.style.top=top+"px";
    if (this.panelsdiv.style && this.panelsdiv.style.height)
      top+=parseInt(this.panelsdiv.style.height);
    else if (this.panelsdiv.clientHeight)
      top+=this.panelsdiv.clientHeight;
    else
      top+=this.panelsdiv.offsetHeight;
    if (this.panelsdiv.style && this.panelsdiv.style.width)
      left=parseInt(this.panelsdiv.style.width);
    else if (this.panelsdiv.clientWidth)
      left=this.panelsdiv.clientWidth;
    else
      left=this.panelsdiv.offsetWidth;

    this.toolspaneldiv.style.top=top+"px";
    this.groupspaneldiv.style.top=top+"px";
    this.mapdiv.style.top=headerHeight+"px";
    this.refmapdiv.style.top=headerHeight+"px";
    
    if (arguments.length==2) {
      newWidth=arguments[0];
      newHeight=arguments[1];
    } else if (this.resizeToFitWindow) {
      var totalWidth,totalHeight;
      if (self.innerWidth) {
        totalWidth=self.innerWidth-1;
        totalHeight=self.innerHeight-1;
      } else if (document.documentElement && document.documentElement.clientWidth) {
        totalWidth=document.documentElement.clientWidth-1;
        totalHeight=document.documentElement.clientHeight-1;
      } else if (document.body.clientWidth) {
        totalWidth=document.body.clientWidth-1;
        totalHeight=document.body.clientHeight-1;
      } else {
        totalWidth=document.body.offsetWidth-1;
        totalHeight=document.body.offsetHeight-1;
      }
      
      //newWidth=parseInt(document.body.clientWidth)-parseInt(this.mapdiv.style.left)-1;
      //newWidth=totalWidth-parseInt(this.mapdiv.style.left);
      newWidth=totalWidth-left-1;
      newHeight=totalHeight-headerHeight;
    }
    
    if (newWidth && newHeight) {
      currentMapState.setDimensions(parseInt(newWidth),parseInt(newHeight));
      
      this.mapdiv.style.width=newWidth+"px";
      this.mapdiv.style.height=newHeight+"px";
      
      if (this.loadingdiv.style && this.loadingdiv.style.height)
        var loadingHeight=parseInt(this.loadingdiv.style.height);
      else if (this.headerdiv.clientHeight)
        var loadingHeight=this.loadingdiv.clientHeight;
      else
        var loadingHeight=this.loadingdiv.offsetHeight;
      
      this.loadingdiv.style.top=newHeight/2 + headerHeight - loadingHeight/2 + "px";
      this.loadingdiv.style.left=newWidth/2 + parseInt(this.mapdiv.style.left) - loadingHeight/2 + "px";
      
      this.setCoordinates();
      this.setQueryString();
      this.draw();
    }
    
    /*
    window.onmouseup=null;
  
    this.setCoordinates();
    this.setQueryString();
    this.draw();
    */
  }
  
	// initialize our mapdiv coordinates
	this.setCoordinates=function() {
		this.mapX1=parseInt(mapdiv.style.left);
		this.mapY1=parseInt(mapdiv.style.top);
		this.mapX2=this.mapX1+parseInt(mapdiv.style.width);
		this.mapY2=this.mapY1+parseInt(mapdiv.style.height);
	}

	this.getWidth=function() {
		return Math.abs(this.mapX1-this.mapX2);
	}

	this.getHeight=function() {
		return Math.abs(this.mapY1-this.mapY2);
	}

  // redraws the map div
  this.draw=function() {
    this.loadingdiv.style.display="block";
    
    // draw the map
    //var bg="transparent no-repeat scroll center";
    //this.mapdiv.style.background=bg;
    
    var url="map.php?"+this.queryString;
    //queue.EnqueueItem("map creation",map.notifyMap,url,false);
    this.setMapURL(url);
    
    // get the map's state
    currentMapState.inspectMap();
    
    this.setRefmapURL("map.php?req_type=refmap&"+this.queryString);
    // draw the scalebar
    //url="map.php?req_type=scalebar&"+this.queryString;
    //queue.EnqueueItem("scalebar creation",map.notifyScalebar,url,false);
  }
  
  this.getInfoTabId=function(tabName) {
    var tabId=null;
    for (var i=0;i<this.assignedInfoTabNames.length;++i) {
      if (this.assignedInfoTabNames[i]==tabName) {
        tabId=this.assignedInfoTabIds[i];
        break;
      }
    }
    return tabId;
  }
  
  this.setMapURL=function(url) {
    if (url.length==0) {
      alert('invalid map url');
      return;
    }
    this.loadingdiv.style.display="block";
    var bg="transparent url(\""+url+"\") no-repeat scroll center";
    this.mapdiv.style.background=bg;
    this.isDrawn=true;
    this.updatediv.style.display="block";
  }
  
  this.setRefmapURL=function(url) {
    var bg = "#fff url(\"" + url + "\") no-repeat";
    this.refmapdiv.style.background=bg;
  }

	this.setQueryString=function() {
		var qs=new Array();
		var temp;
		if (this.mapfile.value.length>0)
		  qs.push("mapfile="+escape(this.mapfile.value));
		else
		  return;
		if (this.session_id.value.length>0)
		  qs.push("session_id="+escape(this.session_id.value));
		else
		  return;
		qs.push("image_width="+this.getWidth());
		qs.push("image_height="+this.getHeight());
		if (this.minx!=0 && this.miny!=0 && this.maxx!=0 && this.maxy!=0) {
		  qs.push("max_extent[x1]="+this.minx);
		  qs.push("max_extent[y1]="+this.miny);
		  qs.push("max_extent[x2]="+this.maxx);
		  qs.push("max_extent[y2]="+this.maxy);
		}
		temp=currentLayerState.queryString();
		if (temp.length>0)
      qs.push(temp);
		temp=currentMapState.queryString();
		if (temp.length>0)
		  qs.push(temp);
		this.queryString=qs.join("&");
	}

/*
  this.notifyMap=function(status,response) {
    if (status=="OK") {
      mapdiv.innerHTML=response;
    } else {
      alert("Map Image Creation:\n"+status+"\n"+response);
    }
  }
*/
  this.notifyQuery=function(status,response) {
    if (status=="OK") {
      document.getElementById(map.latestQueryDestination).innerHTML=response;
      
    } else {
      alert("Query Area:\n"+status+"\n"+response);
    }
  }
  
  this.notifyScalebar=function(status,response) {
    if (status=="OK") {
      map.drawScalebar(response);
    } else {
      alert("Scalebar Image Creation:\n"+status+"\n"+response);
    }
  }
  
  this.queryArea=function(queryProcessor,queryDestination,queryString) {
    this.latestQueryDestination=queryDestination;
    this.setQueryString();
    var qs=this.queryString;
    if (queryString && queryString.length>0)
      qs+="&"+queryString;
    var url=queryProcessor+"?"+qs;
    queue.EnqueueItem("map query",map.notifyQuery,url,false);
  }

  this.drawScalebar=function(scalebar_image) {
    var scalebar_panel=null;
    var scalebar_id=this.getInfoTabId("Scalebar");
    if (!scalebar_id) {
      scalebar_id=infoTabs.addTab("Scalebar",100,290,80);
      this.assignedInfoTabNames[this.assignedInfoTabNames.length]="Scalebar";
      this.assignedInfoTabIds[this.assignedInfoTabIds.length]=scalebar_id;
    }
    if (scalebar_id) {
      scalebar_panel=document.getElementById(scalebar_id);
      if (scalebar_panel) {
        var bg="#e1cbae no-repeat scroll";
        try {
		      scalebar_panel.style.background=bg;
		      scalebar_panel.innerHTML=scalebar_image;
		    } catch (e) {
		      alert("Error creating scalebar: "+e.message);
		    }
      }
    }
  }
}


/*******************************************************************
* MapState object
* keeps track of a map's state:
*  - extent (extent_x1, extent_y1, ...)
*  - dimensions (width, height)
*******************************************************************/ 

function MapState() {
	this.extent_x1=this.extent_y1=this.extent_x2=this.extent_y2=0;
	this.north_lat=this.south_lat=this.east_long=this.west_long=0;
	this.mid_lat=this.mid_long=0;
	this.scale=this.image_width=this.image_height=0;
  this.projection="";
  this.isInitialized=false;
  this.assignedInfoTabIds=new Array();
  this.assignedInfoTabNames=new Array();
  this.msg="";
  
  this.notify=function(status,response) {
    if (status=="OK") {
      var contents=parseResponse(response,false);
      currentMapState.setState(contents);
      currentMapState.drawMapState();
      currentMapState.isInitialized=true;
      drawLegend();
    } else {
      alert("Inspect Map State:\n"+status+"\n"+response);
    }
  }
  
  this.inspectMap=function() {
    var url="map.php?req_type=state&"+map.queryString;
    queue.EnqueueItem("map inspection",currentMapState.notify,url,true);
  }
  
  this.drawMapState=function() {
    var state_panel=null;
    var state_id=this.getInfoTabId("Location Info");
    if (!state_id) {
      state_id=infoTabs.addTab("Location Info",120,270,110);
      this.assignedInfoTabNames[this.assignedInfoTabNames.length]="Location Info";
      this.assignedInfoTabIds[this.assignedInfoTabIds.length]=state_id;
    }
    if (state_id) {
      state_panel=document.getElementById(state_id);
      if (state_panel) {
        var html="Longitude West: "+this.west_long+"<br/>";
        html+="Longitude East: "+this.east_long+"<br/>";
        html+="Latitude North: "+this.north_lat+"<br/>";
        html+="Latitude South: "+this.south_lat+"<br/>";
        html+="Scale: 1 : "+format_number(this.scale)+"<br/>";
        html+="Projection: "+this.projection;

		    state_panel.innerHTML=html;
      }
    }
  }

  this.setState=function(contents) {
    // contents returned are extents (minx, maxx, miny, maxy), width, 
    // height, layers, scale, projection, lat & long
    //var contents=parseResponseContent(http_request.responseXML);
    var value;
    if (contents.length>0) {
      value=getParsedItemById(contents,"minx");
      if (value!=null) {
        currentMapState.extent_x1=value;
        if (map.minx==0) map.minx=value;
      }
      value=getParsedItemById(contents,"miny");
      if (value!=null) {
        currentMapState.extent_y1=value;
        if (map.miny==0) map.miny=value;
      }
      value=getParsedItemById(contents,"maxx");
      if (value!=null) {
        currentMapState.extent_x2=value;
        if (map.maxx==0) map.maxx=value;
      }
      value=getParsedItemById(contents,"maxy");
      if (value!=null) {
        currentMapState.extent_y2=value;
        if (map.maxy==0) map.maxy=value;
      }
      if (!currentLayerState.isInitialized) {
        // send these off to the layer state object
        var group=getParsedItemById(contents,"groups");
        var layer=getParsedItemById(contents,"layers");
        var status=getParsedItemById(contents,"layer_status");
        if (group!=null && layer!=null && status!=null) {
          group=group.split("|");
          layer=layer.split("|");
          status=status.split("|");
          var on,visible;
          for (var i=0;i<layer.length;++i) {
            on=(status[i]=="on");
            visible=(group[i].length>0);
            currentLayerState.addLayer(layer[i],group[i],on,visible,visible);
          }
          currentLayerState.isInitialized=true;
          currentLayerState.drawLayers();
        }
      }
      /*
      if (panels.dataSource && panels.dataSource.legendProcessor) {
        var legend_names=getParsedItemById(contents,"legend_names");
        if (legend_names) {
          legend_names=legend_names.split("|");
          panels.dataSource.legendNames=legend_names;
        }
      }
      */
      value=getParsedItemById(contents,"width");
      if (value!=null) {
        currentMapState.image_width=value;
      }
      value=getParsedItemById(contents,"height");
      if (value!=null) {
        currentMapState.image_height=value;
      }
      value=getParsedItemById(contents,"scale");
      if (value!=null) {
        currentMapState.scale=value;
        if (map.maxScale==0) map.maxScale=value;
        if (mapScales.length==0) populateScales(); 
      }
      currentMapState.projection="NAD 83 Oregon Lambert Projection";
      value=getParsedItemById(contents,"bottom_latitude");
      if (value!=null) {
        currentMapState.south_lat=value;
      }
      value=getParsedItemById(contents,"left_longitude");
      if (value!=null) {
        currentMapState.west_long=value;
      }
      value=getParsedItemById(contents,"top_latitude");
      if (value!=null) {
        currentMapState.north_lat=value;
      }
      value=getParsedItemById(contents,"right_longitude");
      if (value!=null) {
        currentMapState.east_long=value;
      }
      value=getParsedItemById(contents,"mid_latitude");
      if (value!=null) {
        currentMapState.mid_lat=value;
      }
      value=getParsedItemById(contents,"mid_longitude");
      if (value!=null) {
        currentMapState.mid_long=value;
      }
    }
  }
  
  this.getInfoTabId=function(tabName) {
    var tabId=null;
    for (var i=0;i<this.assignedInfoTabNames.length;++i) {
      if (this.assignedInfoTabNames[i]==tabName) {
        tabId=this.assignedInfoTabIds[i];
        break;
      }
    }
    return tabId;
  }

	this.setExtents=function(x1, y1, x2, y2) {
		this.extent_x1 = x1;
		this.extent_y1 = y1;
		this.extent_x2 = x2;
		this.extent_y2 = y2;
	}

	this.setDimensions=function(width, height) {
		this.image_width = width;
		this.image_height = height;
	}

  this.queryString=function() {
    var qs=new Array;
    // if our extent values are non-default / non-zero, add it to the query string
//    if (this.extent_x1!=0 && this.extent_y1!=0 && this.extent_x2!=0 && this.extent_y2!=0) {
      qs.push("extent[x1]="+this.extent_x1);
      qs.push("extent[y1]="+this.extent_y1);
      qs.push("extent[x2]="+this.extent_x2);
      qs.push("extent[y2]="+this.extent_y2);
//    }
    return qs.join("&");
  }
}
