// --[ Global Variables ]--------------------------------------------------------------------------
var lastLonLat            = null;
var globalSelectControl   = null;

// --[ NetstarAjax Class ]-------------------------------------------------------------------------
function NetstarAjax( aURL, synchronous, anOkHandler, anErrorHandler )
{
  var obj = new Object();

  // ATTRIBUTES
  // ----------------------------------------------------------------------------------------------
  
  obj.xml             = new zXmlHttp.createRequest();
  obj.url             = aURL;
  obj.body            = null;
  obj.type            = null;
  obj.isSynchronous   = synchronous;
  obj.errorFlag       = false;
  obj.okHandler       = null;
  obj.errorHandler    = null;
  
  // METHODS
  // ----------------------------------------------------------------------------------------------
  
  obj.okHandler = function()
  {
    obj.errorFlag = false;
  }

  obj.errorHandler = function()
  {
    obj.errorFlag = true;
  }
  
  obj.inError = function()
  {
    return ( obj.errorFlag );
  }
  
  obj.noError = function()
  {
    return ( ! obj.errorFlag );
  }

  obj.send = function()
  {
    // Pre-conditions:
    if( obj.xml == null ) return;
    
    var result  = false;
    
    obj.xml.open( obj.type, obj.url, obj.isSynchronous );
    obj.xml.setRequestHeader( "Content-Type", "application/x-www-form-urlencoded" );
    obj.xml.send( obj.body );
    
    if( !obj.isSynchronous )
    {
      if( obj.xml.status == 200 ) 
      {
        obj.errorFlag = false;
      } // end if
      else
      {
        obj.errorFlag = true;
      } // end else
    } // end if
    else
    {
    } // end else
    
    return result;
  }
  
  if( anOkHandler != null )
  {
    obj.okHandler = anOkHandler; 
  } // end if
  
  if( anErrorHandler != null )
  {
    obj.errorHandler = anErrorHandler;
  } // end if

  return obj;
}

// ================================================================================================

// --[ NetstarAjaxPost Class ]---------------------------------------------------------------------
function NetstarAjaxPost( aURL, synchronous, anOkHandler, anErrorHandler )
{
  var obj   = NetstarAjax( aURL, synchronous, anOkHandler, anErrorHandler );
  obj.type  = "post";
  
  return obj;
}

// ================================================================================================

// --[ NetstarAjaxGet Class ]----------------------------------------------------------------------
function NetstarAjaxGet( aURL, synchronous, anOkHandler, anErrorHandler )
{
  var obj   = NetstarAjax( aURL, synchronous, anOkHandler, anErrorHandler );
  obj.type  = "get";
  
  return obj;
}

// ================================================================================================

// --[ NetstarControl Class ]----------------------------------------------------------------------
function NetstarControl( aLayer, aMap )
{
  var obj = new Object();


  // ATTRIBUTES
  // ----------------------------------------------------------------------------------------------
  obj.map               = aMap;
  obj.controlLayer      = aLayer;
  obj.selectedFeature   = null;
  obj.popup             = null;
  obj.cloudContent      = null;
  obj.onSelect          = null;
  obj.onUnselect        = null;
  obj.control           = new OpenLayers.Control.SelectFeature
  (
    obj.controlLayer,
    { 
      onSelect:   obj.onSelect,
      onUnselect: obj.onUnselect
    }
  );

  // METHODS
  // ----------------------------------------------------------------------------------------------
  obj.activate = function()
  {
    // Pre-conditions:
    if( obj.control == null ) return null;
    
    var result = obj.control.activate();
    return result;
  }

  obj.deactivate = function()
  {
    // Pre-conditions:
    if( obj.control == null ) return null;
    
    var result = obj.control.deactivate();
    return result;
  }

  obj.addControl = function()
  {
    obj.map.addControl( obj.control );
  }
  
  return obj;
}

// ================================================================================================

// --[ NetstarSelectControl Class ]----------------------------------------------------------------
function NetstarSelectControl( aLayer, aMap )
{
  var obj = NetstarControl( aLayer, aMap );

  // METHODS
  // ----------------------------------------------------------------------------------------------

  obj.onSelect = function( feature )
  {
    // Pre-conditions:
    if( obj.map == null ) return;
    
    obj.selectedFeature = feature;

    // since KML is user-generated, do naive protection against
    // Javascript.
    obj.cloudContent = "<h1>" + feature.attributes.name + "</h1><p>" + feature.attributes.description + "</p>";
    if( obj.cloudContent.search("<script") != -1 ) 
    {
      obj.cloudContent = "Content contained Javascript! Escaped content below.<br />" + content.replace(/</g, "&lt;");
    } // end if

    obj.popup = new OpenLayers.Popup.FramedCloud
    ( 
      "cloud", 
      feature.geometry.getBounds().getCenterLonLat(),
      new OpenLayers.Size( 100, 100 ),
      obj.cloudContent,
      null, 
      true, 
      obj.onPopupClose
    );
    feature.popup = obj.popup;
    obj.map.addPopup( obj.popup );
  }

  obj.onUnselect = function( feature )
  {
    // Pre-conditions:
    if( feature.popup == null ) return;
    if( obj.map == null ) return;
    
    // remove the popup
    obj.map.removePopup( feature.popup );
    feature.popup.destroy();
    feature.popup = null;
  }

  obj.onPopupClose = function( event )
  {
    // Pre-conditions:
    if( obj.selectedFeature == null ) return;
    if( obj.control == null ) return;
    
    obj.control.unselect( obj.selectedFeature );
  }

  // ATTRIBUTES
  // ----------------------------------------------------------------------------------------------
  obj.control = new OpenLayers.Control.SelectFeature
  (
    obj.controlLayer,
    { 
      onSelect:   obj.onSelect,
      onUnselect: obj.onUnselect
    }
  );

  obj.addControl();
  
  return obj;
}

// ================================================================================================

// --[ NetstarEditControl Class ]------------------------------------------------------------------
function NetstarEditControl( aLayer, aMap )
{
  var obj = NetstarControl( aLayer, aMap );
  
  // ATTRIBUTES
  // ----------------------------------------------------------------------------------------------
  obj.control   = new OpenLayers.Control.ModifyFeature( obj.controlLayer );

  obj.addControl();
  
  return obj;
}

// ================================================================================================

// --[ NetstarPolygonControl Class ]---------------------------------------------------------------
function NetstarPolygonControl( aLayer, aMap )
{
  var obj = new NetstarControl( aLayer, aMap );

  // ATTRIBUTES
  // ----------------------------------------------------------------------------------------------
  obj.control = new OpenLayers.Control.DrawFeature( obj.controlLayer, OpenLayers.Handler.Polygon );
  
  obj.addControl();
  
  return obj;
}

// ================================================================================================

// --[ NetstarLayer Class ]------------------------------------------------------------------------

function NetstarLayer( aName, anID, aURL, aMap )
{
  var obj = new Object();

  // ATTRIBUTES
  // ----------------------------------------------------------------------------------------------
  
  obj.id              = anID;
  obj.name            = aName;
  obj.url             = aURL;
  obj.map             = aMap;
  obj.layer           = null;
  obj.selectControl   = null;

  // METHODS
  // ----------------------------------------------------------------------------------------------

  obj.addLayer = function()
  {
    obj.map.addLayer( obj.layer );
  }

  obj.panTo = function( position )
  {
    obj.map.panTo( position );
  }
  
  return obj;
}

// ================================================================================================

// --[ NetstarZoneLayer Class ]--------------------------------------------------------------------
function NetstarZoneLayer( aName, anID, aURL, aMap )
{
  var obj = NetstarLayer( aName, anID, aURL, aMap );

  // ATTRIBUTES
  // ----------------------------------------------------------------------------------------------
  obj.layer = new OpenLayers.Layer.GML
  ( 
    obj.name, 
    obj.url, 
    { 
      format: OpenLayers.Format.KML, 
      formatOptions: 
        { 
          extractStyles: true, 
          extractAttributes: true 
        } 
    } 
  );

  obj.layer.events.on
  (
    {
      "afterfeaturemodified": obj.onModified,
      "featureadded":         obj.onAdded
    }
  );

  // METHODS
  // ----------------------------------------------------------------------------------------------
  obj.onAdded = function()
  {
  }

  obj.onModified = function()
  {
  }

  // INITIALISATION
  // ----------------------------------------------------------------------------------------------
  obj.addLayer();
  
  obj.selectControl  = NetstarSelectControl( obj.layer, obj.map );
  obj.editControl    = NetstarEditControl( obj.layer, obj.map );
  obj.polygonControl = NetstarPolygonControl( obj.layer, obj.map );
  
  return obj;
}

// ================================================================================================

// --[ NetstarLatestPositionLayer Class ]--------------------------------------------------------------------
function NetstarLatestPositionLayer( aName, anID, aURL, aMap )
{
  var obj = NetstarLayer( aName, anID, aURL, aMap );

  // METHODS
  // ----------------------------------------------------------------------------------------------
  obj.onAdded = function( event )
  {
    if( event.features.length > 0 )
    {
      var extent = event.features[ event.features.length - 1 ].geometry.getBounds();
      var lonlat = extent.getCenterLonLat();
      
      lastLonLat = lonlat;
      
      obj.panTo( lonlat );
    } // end if
  }

  // ATTRIBUTES
  // ----------------------------------------------------------------------------------------------
  obj.layer = new OpenLayers.Layer.GML
  (
    obj.name,
    obj.url,
    {
      format: OpenLayers.Format.KML,
      formatOptions: 
      {
        extractStyles:      true,
        extractAttributes:  true
      },
      eventListeners: 
      { 
        "featuresadded": obj.onAdded
      }
    }
  );

  // INITIALISATION
  // ----------------------------------------------------------------------------------------------
  obj.addLayer();
  obj.selectControl = NetstarSelectControl( obj.layer, obj.map );
  obj.selectControl.activate();
  
  return obj;
}

// ================================================================================================

// --[ NetstarHistoryPositionsLayer Class ]--------------------------------------------------------
function NetstarHistoryPositionsLayer( aName, anID, aURL, aMap )
{
  var obj = NetstarLayer( aName, anID, aURL, aMap );

  // METHODS
  // ----------------------------------------------------------------------------------------------
  obj.onAdded = function( event )
  {
    var extent = event.features[ event.features.length - 1 ].geometry.getBounds();
    var lonlat = extent.getCenterLonLat();
    
    obj.panTo( lonlat );
  }
  
  // ATTRIBUTES
  // ----------------------------------------------------------------------------------------------
  obj.layer = new OpenLayers.Layer.GML
  (
    obj.name,
    obj.url,
    {
      format: OpenLayers.Format.KML,
      formatOptions: 
      {
        extractStyles:      true,
        extractAttributes:  true
      },
      eventListeners: 
      { 
        "featuresadded": obj.onAdded
      }
    }
  );

  // INITIALISATION
  // ----------------------------------------------------------------------------------------------
  obj.addLayer();
  obj.selectControl = new NetstarSelectControl( obj.layer, obj.map );
  obj.selectControl.activate();
  
  return obj;
}

// ================================================================================================

// --[ NetstarRouteLayer Class ]-------------------------------------------------------------------
function NetstarRouteLayer( aName, anID, aURL, aMap )
{
  var obj = NetstarLayer( aName, anID, aURL, aMap );
  
  // ATTRIBUTES
  // ----------------------------------------------------------------------------------------------
  obj.layer = new OpenLayers.Layer.GML
  ( 
    obj.name, 
    obj.url, 
    { 
      format: OpenLayers.Format.KML, 
      formatOptions: 
        { 
          extractStyles: true, 
          extractAttributes: true 
        } 
    } 
  );

  // METHODS
  // ----------------------------------------------------------------------------------------------

  // INITIALISATION
  // ----------------------------------------------------------------------------------------------
  obj.addLayer();
  
  return obj;
}

// ================================================================================================

// --[ NetstarMapLayer Class ]---------------------------------------------------------------------

function NetstarMapLayer( aMap, anID, aName, aHeight, aWidth, nZoomLevels, aZoomLevel )
{
  var obj = new Object;
  
  // ATTRIBUTES
  // ----------------------------------------------------------------------------------------------
  obj.map         = aMap;
  obj.id          = anID;
  obj.name        = aName;
  obj.width       = aWidth;
  obj.height      = aHeight;
  obj.zoomLevels  = nZoomLevels;
  obj.zoomLevel   = aZoomLevel;
  obj.layer       = null;
  
  // METHODS
  // ----------------------------------------------------------------------------------------------
  obj.addLayer = function()
  {
    obj.map.addLayer( obj.layer );
  };
  
  // INITIALISATION
  // ----------------------------------------------------------------------------------------------
  
  return obj;
}

// ================================================================================================

// --[ NetstarDefaultMapLayer Class ]--------------------------------------------------------------
function NetstarDefaultMapLayer( aMap, anID, aName, aHeight, aWidth, nZoomLevels, aZoomLevel )
{
  var obj = NetstarMapLayer( aMap, anID, aName, aHeight, aWidth, nZoomLevels, aZoomLevel );
  
  // ATTRIBUTES
  // ----------------------------------------------------------------------------------------------
  var urls = 
  [
    "http://60.48.149.85:8000/images",
    "http://60.48.149.85:8001/images",
    "http://60.48.149.85:8002/images"
  ];
  
  obj.layer = new OpenLayers.Layer.WMS
  (
    obj.name,
    urls,//"http://test.netstaronline.net:9000/images",
    { 
      request:            "openlayers", 
      layers:             "",
      styles:             "", 
      crs:                "EPSG:4326",/*
      width:              obj.width, 
      height:             obj.height, */
      format:             "image/png", 
      version:            "1.3.0",
      transparent:        "True",
      opacity:            0.3,
      attribution:        "Provided by Altech Netstar",
      usertoken:          "uuid-916c52f6-7d7d-4722-b7a5-0bd52d15f8b3-1"
    },
    { 
      'buffer':           0,
      'numZoomLevels':    obj.zoomLevels,
      'isBaseLayer':      true,
      'visibility':       true,
      'transitionEffect': "resize"
    }, 
    { 
      'reproject':        true
    }
  );
  
  // METHODS
  // ----------------------------------------------------------------------------------------------
  
  // INITIALISATION
  // ----------------------------------------------------------------------------------------------
  obj.addLayer();
  obj.map.zoomTo( obj.zoomLevel );

  return obj;
}

// ================================================================================================

// --[ NetstarGoogleStreetsLayer Class ]-----------------------------------------------------------
function NetstarGoogleStreetsLayer( aMap, anID, aName, aHeight, aWidth, nZoomLevels, aZoomLevel )
{
  var obj = NetstarMapLayer( aMap, anID, aName, aHeight, aWidth, nZoomLevels, aZoomLevel );
  
  // ATTRIBUTES
  // ----------------------------------------------------------------------------------------------
  obj.layer      = new OpenLayers.Layer.Google
  (
    obj.name,
    {
      'isBaseLayer':        true,
      'transitionEffect':   "resize",
      'sphericalMercator':  true/*,
      'width':              obj.width,
      'height':             obj.height*/
    }
  );

  
  // METHODS
  // ----------------------------------------------------------------------------------------------
  
  // INITIALISATION
  // ----------------------------------------------------------------------------------------------
  obj.addLayer();
  obj.map.zoomToMaxExtent();
  
  return obj;
}

// ================================================================================================

// --[ NetstarGoogleHybridLayer Class ]------------------------------------------------------------

function NetstarGoogleHybridLayer( aMap, anID, aName, aHeight, aWidth, nZoomLevels, aZoomLevel )
{
  var obj = NetstarMapLayer( aMap, anID, aName, aHeight, aWidth, nZoomLevels, aZoomLevel );
  
  // ATTRIBUTES
  // ----------------------------------------------------------------------------------------------
  obj.layer      = new OpenLayers.Layer.Google
  (
    obj.name,
    {
      'isBaseLayer':        true,
      'transitionEffect':   "resize",
      'sphericalMercator':  true,
      type:                 G_HYBRID_MAP/*,
      'width':              obj.width,
      'height':             obj.height*/
    }
  );
  
  // METHODS
  // ----------------------------------------------------------------------------------------------
  
  // INITIALISATION
  // ----------------------------------------------------------------------------------------------
  obj.addLayer();
  obj.map.zoomToMaxExtent();
  
  return obj;
}

// ================================================================================================

// --[ NetstarMapControl Class ]-------------------------------------------------------------------



function NetstarMapControl( aPlaceholder, aWidth, aHeight, defaultZoomLevel )
{
  var obj = new Object();
  
  // ATTRIBUTES
  // ----------------------------------------------------------------------------------------------
  obj.layers        = new Array();
  obj.placeholder   = aPlaceholder;
  obj.width         = aWidth;
  obj.height        = aHeight;
  obj.zoomLevel     = defaultZoomLevel;
  obj.map           = null;
  
  // METHODS
  // ----------------------------------------------------------------------------------------------
  obj.addGoogleStreets = function()
  {
    if( obj.map == null )
    {
      var options = 
      {
        //projection:         new OpenLayers.Projection("EPSG:900913"),
        //displayProjection:  new OpenLayers.Projection("EPSG:4326"),
        units:              "m",
        numZoomLevels:      20,
        maxResolution:      156543.0339,
        maxExtent:          new OpenLayers.Bounds(-20037508, -20037508, 20037508, 20037508.34)
      };
      obj.map = new OpenLayers.Map( obj.placeholder, options );
    }

    obj.map.addControl( new OpenLayers.Control.LayerSwitcher({ 'ascending': true }) );
    obj.map.addControl( new OpenLayers.Control.ScaleLine() );
    obj.map.addControl( new OpenLayers.Control.MousePosition() );
    obj.map.addControl( new OpenLayers.Control.KeyboardDefaults() );

    var o = NetstarGoogleStreetsLayer( obj.map, "Google", "Google Streets", obj.width, obj.height, 20, defaultZoomLevel );
    obj.layers[ obj.layers.length ] = o.layer;
    return o;
  }

  obj.addGoogleHybrid = function()
  {
    if( obj.map == null )
    {
      var options = 
      {
        //projection:         new OpenLayers.Projection("EPSG:900913"),
        //displayProjection:  new OpenLayers.Projection("EPSG:4326"),
        units:              "m",
        numZoomLevels:      20,
        maxResolution:      156543.0339,
        maxExtent:          new OpenLayers.Bounds(-20037508, -20037508, 20037508, 20037508.34)
      };
      obj.map = new OpenLayers.Map( obj.placeholder, options );
    }

    obj.map.addControl( new OpenLayers.Control.LayerSwitcher({ 'ascending': true }) );
    obj.map.addControl( new OpenLayers.Control.ScaleLine() );
    obj.map.addControl( new OpenLayers.Control.MousePosition() );
    obj.map.addControl( new OpenLayers.Control.KeyboardDefaults() );
    
    var o = NetstarGoogleHybridLayer( obj.map, "Google", "Google Hybrid", obj.width, obj.height, 20, defaultZoomLevel );
    obj.layers[ obj.layers.length ] = o.layer;
    return o;
  }

  obj.addNetstarDefault = function()
  {
    if( obj.map == null )
    {
      obj.map = new OpenLayers.Map
      (
        obj.placeholder,
        { 
          controls: 
          [
            new OpenLayers.Control.Navigation(),
            new OpenLayers.Control.PanPanel(),
            new OpenLayers.Control.ZoomPanel(),
            new OpenLayers.Control.LayerSwitcher({ 'ascending': true }),
            new OpenLayers.Control.ScaleLine(),
            new OpenLayers.Control.MousePosition(),
            new OpenLayers.Control.KeyboardDefaults()
          ]
        }
      );
    }
    
    var o = NetstarDefaultMapLayer( obj.map, "Netstar", "Netstar Map", obj.width, obj.height, 20, defaultZoomLevel );
    obj.layers[ obj.layers.length ] = o.layer;
    return o;
  }

  obj.addZoneLayer = function( name, id, url )
  {
    var o = NetstarZoneLayer( name, id, url, obj.map );
    obj.layers[ obj.layers.length ] = o.layer;
    return o;
  }

  obj.addLatestPositionsLayer = function( name, id, url )
  {
    var o = NetstarLatestPositionLayer( name, id, url, obj.map );
    obj.layers[ obj.layers.length ] = o.layer;
    obj.map.zoomTo( obj.zoomLevel );
    return o;
  }

  obj.addHistoryPositionsLayer = function( name, id, url )
  {
    var o = NetstarHistoryPositionsLayer( name, id, url, obj.map );
    obj.layers[ obj.layers.length ] = o.layer;
    obj.map.zoomTo( obj.zoomLevel );
    return o;
  }

  obj.addRouteLayer = function( name, id, url )
  {
    var o = new NetstarRouteLayer( name, id, url, obj.map );
    obj.layers[ obj.layers.length ] = o.layer;
    return o;
  }
  
  // INITIALISATION
  // ----------------------------------------------------------------------------------------------
  
  return obj;
}

