//-----------------------------------------------------------------------#
// IdvMapViewer.js - Copyright (C) 2007 IDV Solutions                    #
//-----------------------------------------------------------------------#

// make sure IDV namespace exists
if(typeof idv == "undefined") { var idv = new Object(); }

// Enumeration Values
idv.VectorFormat     = { GeoRSS: 0, FML: 1, GML: 2 }
idv.FindSourceType   = { Server: 0, Memory: 1 }
idv.VectorSourceType = { Server: 0, Memory: 1 }
idv.RasterSourceType = { Single: 0, Mosaic: 1, Tiled: 2 }

// Global Variables
idv.MapInstance = null;


//-----------------------------------------------------------------------#
// Global Methods                                                        #
//-----------------------------------------------------------------------#

/*
TODO: MVFindSourceClass(function(query, n, e, s, w) {})
*/

// Obtains reference to main map viewer
function MVGetMainMap()
{
   return idv.MapInstance;
}

// Removes a vector source from the map viewer
function MVRemoveVectorSource(name)
{
   idv.MapInstance.removeVectorSource(name);
}

// Adds a new vector source to the main map viewer
function MVAddVectorSource(options, format, isDynamic, url)
{
   idv.MapInstance.addVectorSource(
      new idv.ServerVectorSource(options, format, isDynamic, url)
   );
}

// Sets URL for a vector source of main map viewer
function MVSetVectorRequest(source, url, doc)
{
   idv.MapInstance.getVectorSource(source).setRequest(url, doc);
}

// Removes a raster source from the main map viewer
function MVRemoveRasterSource(name)
{
   idv.MapInstance.removeRasterSource(name);
}

// Adds a new raster source to the main map viewer
function MVAddRasterSource(options, isDynamic, url)
{
   idv.MapInstance.addRasterSource(
      new idv.SingleRasterSource(options, isDynamic, url)
   );
}

// Sets the URL for a raster source on the main map viewer
function MVSetRasterRequest(source, url, bound)
{
   idv.MapInstance.getRasterSource(source).setRequest(url, bound);
}

// Sets the alpha value for a raster source in main map viewer
function MVSetRasterAlpha(source, alpha)
{
   idv.MapInstance.getRasterSource(source).setAlpha(alpha);
}

// Removes a find data source from the main map viewer
function MVRemoveFindSource(source)
{
    idv.MapInstance.getFindSource(source).removeFindSource(source);
}

// Adds a new find data source to the main map viewer
function MVAddFindSource(options, url)
{
   idv.MapInstance.addFindSource(new idv.FindSource(options, url));
}

// Moves a vector layer above another vector layer
function MVMoveVectorLayerAbove(layerName, afterName)
{
   idv.MapInstance.moveVectorLayerAbove(layerName, afterName);
}

// Moves a raster layer above another raster layer
function MVMoveRasterLayerAbove(layerName, aboveName)
{
   idv.MapInstance.moveRasterLayerAbove(layerName, aboveName);
}

// Instructs the main map viewer to navigate to a point
function MVGotoPoint(cx, cy, level, animate)
{
   idv.MapInstance.gotoPoint(cx, cy, level, animate);
}

// Instructs the main map viewer to navigate to an extent
function MVGotoExtent(north, east, south, west, animate)
{
   idv.MapInstance.gotoExtent(north, east, south, west, animate);
}


//-----------------------------------------------------------------------#
// MapViewer: Class that manages a single map viewer component           #
//-----------------------------------------------------------------------#
idv.MapViewer = IdvCreateClass(idv.FlashMovie, {

   // Event Constants
   NavigateBegin: "NavigateBegin",
   NavigateEnd:   "NavigateEnd",
   VectorClicked: "VectorClicked",

   // Obtains a vector source in this map viewer
   getVectorSource: function(name) {
      return this.mFeatSrc[name];
   },

   // Obtains a raster source in this map viewer
   getRasterSource: function(name) {
      return this.mRastSrc[name];
   },

   // Obtains a find source in this map viewer
   getFindSource: function(name) {
      return this.mFindSrc[name];
   },

   // Adds a new find source to the map viewer
   addFindSource: function(source)
   {
      this.addMapDataSource(this.mFindSrc, source, "addFindSource");
   },

   // Removes a find source from the map viewer   
   removeFindSource: function(name)
   {
      this.removeMapDataSource(this.mFindSrc, name, "removeFindSource");
   },

   // Adds a new vector source to the map viewer
   addVectorSource: function(source)
   {
      this.addMapDataSource(this.mFeatSrc, source, "addVectorSource");
   },

   // Removes a vector source from the map viweer
   removeVectorSource: function(name)
   {
      this.removeMapDataSource(this.mFeatSrc, name, "removeVectorSource");
   },

   // Sets the list used to re-order vector layers
   setVectorLayerOrder: function(order)
   {
      this.invokeASMethod("setVectorLayerOrder", order);
   },

   // Moves one vector layer above another
   moveVectorLayerAbove: function(layerName, aboveName)
   {
      this.invokeASMethod("moveVectorLayerAbove", layerName, aboveName);
   },

   // Adds a new raster source to the map viewer
   addRasterSource: function(source)
   {
      this.addMapDataSource(this.mRastSrc, source, "addRasterSource"); 
   },

   // Removes a raster source from the map viewer
   removeRasterSource: function(name)
   {
      this.removeMapDataSource(this.mRastSrc, name, "removeRasterSource");
   },

   // Moves one raster layer above another
   moveRasterLayerAbove: function(layerName, aboveName)
   {
      this.invokeASMethod("moveRasterLayerAbove", layerName, aboveName);
   },

   // Tells the map viewer to go to a particular location
   gotoPoint: function(cx, cy, level, animate)
   {
      this.invokeASMethod("gotoPoint", cx, cy, level, animate);
   },

   // Tells the map viewer to go to a particular extent
   gotoExtent: function(n, e, s, w, animate)
   {
      this.invokeASMethod("gotoExtent", n, e, s, w, animate);
   },

   // Adds a callback to be invoked when the map viewer has fully
   // loaded. The prototype of method should be function(viewer)
   // where viewer will be a reference to the initialized map viewer.
   // If map is already loaded, the callback method will immediately
   // be invoked.
   addLoadListener: function(target, method)
   {
      // invoke the register method directly
      if(this.mLoaded) {
         if(method == null) {
            target.mapViewerLoaded(this);
         } else {
            method.call(target, this);
         }

      // register the object or method
      } else {
         if(method == null) {
            this.mLdIface.push(target);
         } else {
            this.mLoadLnr.push({method: method, target: target});
         }
      }
   },

   // (private) Adds a new data source to the map viewer
   addMapDataSource: function(list, source, method)
   {
      // save reference to the raster source
      list[source.name] = source;

      // bind map viewer to raster source
      source.bindMapViewer(this);

      // add the raster source to the map viewer
      this.invokeASMethod(
         method,
         source.type,
         source.options,
         source.params
      );
   },

   // (private) Removes a data source from the map viewer
   removeMapDataSource: function(list, name, method)
   {
      this.invokeASMethod(method, name);
      delete list[name];
   },

   // (private) Handles find query messages from viewer
   handleFindQuery: function(src, query, n, e, s, w)
   {
      this.mFindSrc[src].onFindLocation(query, n, e, s, w);
   },

   // (private) Handles map initialization
   handleInitialize: function()
   {
      var info;

      // set the loaded flag
      this.mLoaded = true;

      // send mapViewerLoaded to all IDV movies
      for(var i = 0; i < this.mLdIface.length; i++) {
         this.mLdIface[i].mapViewerLoaded(this);
      }

      // send mapViewerLoaded to listeners
      for(var i = 0; i < this.mLoadLnr.length; i++) {
         info = this.mLoadLnr[i]
         info.method.call(info.target, this);
      }

      // clear load listeners
      this.mLoadLnr = null;
      this.mLdIface = null;
   },

   // Constructs a new IDV Map Viewer object
   $construct: function(name, file)
   {
      // call base class constructor
      //++this.$super.$construct.call(this, name, file);
      idv.FlashMovie.prototype.$construct.call(this, name, file);

      // setup internal structures
      this.mLoaded  = false;        // true when loaded
      this.mFeatSrc = new Object(); // feature sources
      this.mRastSrc = new Object(); // raster sources
      this.mFindSrc = new Object(); // find sources 
      this.mLoadLnr = new Array();  // load listener method+target pairs
      this.mLdIface = new Array();  // map load listener interfaces

      // save this as main map instance
      idv.MapInstance = this;
   }
})


//-----------------------------------------------------------------------#
// MapDataSource: Base class for map data source objects                 #
//-----------------------------------------------------------------------#
idv.MapDataSource = IdvCreateClass(Object, {

   // Called on each new map view
   onNewMapView: function(map, view) {
      // default implementation does nothing
   },

   // (internal) Binds a map view viewer to a data source
   bindMapViewer: function(viewer)
   {
      // save viewer reference
      this.mViewer = viewer;

      // register for navigate end events if needed
      if(this.onNewMapView != idv.MapDataSource.prototype.onNewMapView) {
         viewer.addListener(idv.MapViewer.NavigateEnd,this,this.onNewMapView);
      }
   }
})


//-----------------------------------------------------------------------#
// ServerFindSource: Find source that will use a server for queries      #
//-----------------------------------------------------------------------#
idv.ServerFindSource = IdvCreateClass(idv.MapDataSource, {

   // Sets the request to use for this find source
   setRequest: function(url, xmldoc) {
      this.mViewer.invokeASMethod("setFindRequest", this.name, url, xmldoc);
   },

   // Constructs a new FindSource object
   $construct: function(options, url)
   {
      this.type    = idv.FindSourceType.Server;
      this.options = options;
      this.name    = options.name;
      this.params  = {url: url};
   }
})


//-----------------------------------------------------------------------#
// MemoryFindSource: Find source that will use JavaScript for queries    #
//-----------------------------------------------------------------------#
idv.MemoryFindSource = IdvCreateClass(idv.MapDataSource, {

   // Abstract method to be overriden by sub-classes
   onFindLocation: function(query, n, e, s, w)
   {
      // default implementation does nothing
   },

   // Shows an error message to the user
   showErrorMessage: function(msg)
   {
      this.waitingForResults = false;
      this.mViewer.invokeASMethod("showFindError", this.name, msg);
   },

   // Sets the URL for this find source
   showResultList: function(list)
   {
      this.waitingForResults = false;
      this.mViewer.invokeASMethod("setFindResults", this.name, list);
   },

   // Goes to a single find result
   gotoSingleResult: function(result)
   {
      this.waitingForResults = false;
      this.mViewer.invokeASMethod("gotoFindResult", this.name, result);
   },

   // (internal) User has entered a query
   handleFindQuery: function(query, n, e, s, w)
   {
      this.waitingForResults = true;
      this.onFindLocation(query, n, e, s, w);
   },

   // Constructs a new FindSource object
   $construct: function(options)
   {  
      // setup common variables
      this.type    = idv.FindSourceType.Memory;
      this.options = options;
      this.name    = options.name;
      this.params  = null;

      // clear internal varaibles
      this.waitingForResults = false;
   }
})


//-----------------------------------------------------------------------#
// RasterSource: Base class for all raster data sources                  #
//-----------------------------------------------------------------------#
idv.RasterSource = IdvCreateClass(idv.MapDataSource, {

   // Sets the alpha for a raster data source
   setAlpha: function(value) {
      this.mViewer.invokeASMethod("setRasterAlpha", this.name, value);
   }
})


//-----------------------------------------------------------------------#
// SingleRasterSource: Manages a single-image raster data source         #
//-----------------------------------------------------------------------#
idv.SingleRasterSource = IdvCreateClass(idv.RasterSource, {

   // Sets the URL, bound from which to read the raster image
   setRequest: function(url, bound) {
      this.mViewer.invokeASMethod("setRasterRequest", this.name, url, bound);
   },

   // Constructs a new single raster data source
   $construct: function(options, isDynamic, url)
   {
      this.name    = options.name;
      this.options = options;
      this.type    = idv.RasterSourceType.Single;
      this.params  = { isDynamic: isDynamic, url: url };
   } 
})


//-----------------------------------------------------------------------#
// MosaicRasterSource: Manages a mosaic raster data source               #
//-----------------------------------------------------------------------#
idv.MosaicRasterSource = IdvCreateClass(idv.RasterSource, {

   // Constructs a new mosaic raster data source
   $construct: function(options /*TBD*/)
   {
      this.name    = options.name;
      this.options = options;
      this.type    = idv.RasterSourceType.Mosaic;
      this.params  = { /*TBD*/ }
   }
})


//-----------------------------------------------------------------------#
// TiledRasterSource: Manages a tiled raster data source                 #
//-----------------------------------------------------------------------#
idv.MosaicRasterSource = IdvCreateClass(idv.RasterSource, {

   // Constructs a new mosaic raster data source
   $construct: function(options /*TBD*/)
   {
      this.name    = options.name;
      this.options = options;
      this.type    = idv.RasterSourceType.Tiled;
      this.params  = { /*TBD*/ }
   }
})



//-----------------------------------------------------------------------#
// ServerVectorSource: Manages a single server vector source             #
//-----------------------------------------------------------------------#
idv.ServerVectorSource = IdvCreateClass(idv.MapDataSource, {

   // sets the request URL and document for this source   
   setRequest: function(url, xmldoc) {
      this.mViewer.invokeASMethod("setVectorRequest", this.name, url, xmldoc);
   },

   // Constructs a new server based vector data source
   $construct: function(options, format, isDynamic, url, layers)
   {
      this.name    = options.name;
      this.options = options;
      this.type    = idv.VectorSourceType.Server;
      this.params  = {
         layers:    layers,
         isDynamic: isDynamic,
         format:    format,
         url:       url 
      };
   }
})


//-----------------------------------------------------------------------#
// MemoryVectorSource: Manages an in-memory vector source                #
//-----------------------------------------------------------------------#
idv.MemoryVectorSource = IdvCreateClass(idv.MapDataSource, {

   // Adds a new layer to a memory vector source
   addLayer: function(layer)
   {
      // TODO: implement MemoryVectorSource.addLayer
   },

   // Constructs a new in-memory vector data source
   $construct: function(options)
   {
      this.name    = options.name;
      this.options = options;
      this.type    = idv.VectorSourceType.Memory;
      this.params  = {/*TBD*/};
   }
})


//-----------------------------------------------------------------------#
// Base class for in-memory map layers                                   #
//-----------------------------------------------------------------------#
idv.VectorLayer = IdvCreateClass(Object, {

   // Sets the content within a vector layer
   setVectors: function(vectors)
   {
      // TODO: implement VectorLayer.setVectors
   }
})


//-----------------------------------------------------------------------#
// In-memory map layer that contains points                              #
//-----------------------------------------------------------------------#
idv.PointLayer = IdvCreateClass(Object, {

   // Constructs a new point layer
   $construct: function(name, options)
   {
      // TODO: implement idv.PointLayer.$construct
   }
})


//-----------------------------------------------------------------------#
// In-memory map layer that contains shapes                              #
//-----------------------------------------------------------------------#
idv.ShapeLayer = IdvCreateClass(Object, {

   // Constructs a new shape layer
   $construct: function(name, minLevel, maxLevel, closed)
   {
      // TODO: implement idv.GeometryLayer..ctor
   }
})


//-----------------------------------------------------------------------#
// ShapeStyle: Stores information about style for lines and polygons     #
//-----------------------------------------------------------------------#
idv.ShapeStyle = function(
   fillColor,
   fillAlpha,
   lineColor,
   lineAlpha,
   lineWeight)
{
   this.fillColor  = fillColor;
   this.fillAlpha  = fillAlpha;
   this.lineColor  = lineColor;
   this.lineAlpha  = lineAlpha;
   this.lineWeight = lineWeight;
}


//-----------------------------------------------------------------------#
// VectorOptions: Stores options for a vector source                     #
//-----------------------------------------------------------------------#
idv.VectorSourceOptions = function(
   name,
   minLevel,
   maxLevel,
   defaultIcon,
   defaultStyle)
{
   this.name         = name;
   this.minLevel     = minLevel;
   this.maxLevel     = maxLevel;
   this.defaultStyle = defaultStyle;
   this.defaultIcon  = defaultIcon;
}


//-----------------------------------------------------------------------#
// FindSourceOptions: Stores options for a find source                   #
//-----------------------------------------------------------------------#
idv.FindSourceOptions = function(name, label, example)
{
   this.name    = name;
   this.label 	 = label;
   this.example = example;
}


//-----------------------------------------------------------------------#
// RasterOptions: Stores options for a raster source                     #
//-----------------------------------------------------------------------#
idv.RasterSourceOptions = function(
   name,
   minLevel,
   maxLevel,
   alpha,
   bound)
{
   this.name     = name;
   this.minLevel = minLevel;
   this.maxLevel = maxLevel;
   this.bound    = bound;
   this.alpha    = alpha;
}


//-----------------------------------------------------------------------#
// Extent: Stores map extent information                                 #
//-----------------------------------------------------------------------#
idv.Extent = function(north, east, south, west)
{
   this.north = north;
   this.east  = east;
   this.south = south;
   this.west  = west;
}
