// vc_id = "$Id: PositionChangeSupport.js 11366 2008-03-14 21:50:50Z robert $"
// This library represents specific mapping functions for
// position change support.  It provides methods to add PositionChangeListener objects.
// The PositionChangeListener interface requires one method to be implemented,
// positionChange( positionevent ) where the positionevent is a PostionChangeEvent object.  The
// PostionChangeEvent object contains the current map,earth and screen coordinates.
// @author Robert D. Rice

var POSITION = new PositionChangeSupport(  );
var POSITION_MAP = "Position Map";
var POSITION_EARTH = "Position Earth";

// Constructor for PositionChangeSupport
// @param map in projected coords
// @param map in earth coords
function PositionChangeSupport( map, earth ) {
  // PositionChangeListener objects.
  // require one method, positionChange( positionevent )
  this.listeners = new Array( );

  // the two position maps, projection and earth coords
  this.positionMap = map;
  this.positionEarth = earth;

  // add listener method
  this.addListener = PositionChangeAddListener;

  // fire change method
  this.fireChange = PositionChangeFireChange;
}


// Add a PositionChangeListener to the PositionChangeSupport
// A PositionChangeListener is required to provide a 
// positionChange( positionevent ) method.  This method accepts
// a PostionChangeEvent object, and has no return.
// @param the PositionChangeListener object
function PositionChangeAddListener( listener ) {
  this.listeners[ this.listeners.length ] = listener;
}

// Fire a PositionChangeEvent to the listeners
// @param event that triggered the position change
// @param optional offset, added to position, 
//  used to translate bounding box to underlying map.
// @param optional qualifier for the offset position.
//  if true, the offset refers to an alternate origin rather than an offset.
//  the position will be tranlated back to this reference.
function PositionChangeFireChange( e, offset, offsetIsOrigin ) {
	
  if( !this.positionMap ) return;

  var size = this.listeners.length;

  if ( offsetIsOrigin ) {
    var screen = ScreenCoordinatesOnElementFromEvent( e, offset );
  } else {
    var screen = ScreenCoordinatesOnElementFromEvent( e );
    if ( offset ) { screen = GeoPointSum( screen, offset ); }
  }

  var page = ScreenCoordinatesOnPageFromEvent( e );
  var map = this.positionMap.fromScreenCoordinates( screen );
  var earth = this.positionEarth.fromScreenCoordinates( screen );
  var positionevent = new PositionChangeEvent( map, earth, screen, page );
  for ( var i = 0; i < size; i++ ) {
    this.listeners[ i ].positionChange( positionevent );
  }
}

// Constructor for a PositionChangeEvent
// This class contains the current position in all three coord systems.
// @param GeoPoint representing the point in map coords
// @param GeoPoing representing the point in earth coords
// @param GeoPoint representing the point in screen coords
// @param GeoPoint representing the point in page coords
function PositionChangeEvent( mapPoint, earthPoint, screenPoint, pagePoint ) {
  // map coords
  this.map = mapPoint;
  // earth coords
  this.earth = earthPoint;
  // screen coords
  this.screen = screenPoint;
  // page coords
  this.page = pagePoint;

  // toString method
  this.toString = PositionChangeEventToString;
}

// to string method for PositionChangeEventToString
// @return string representation
function PositionChangeEventToString( ) {
   var toString = "";
   toString = toString + "map:    " + this.map;
   toString = toString + "\nearth:  " + this.earth;
   toString = toString + "\nscreen: " + this.screen;
   toString = toString + "\npage:   " + this.page;
   return toString;
}

// Convenience method to initialize the PositionChangeSupport
// @param GeoRectangle representing the map in map coords, or a map object
// @param GeoRectangle representing the map in earth coords, or a map object
// @param GeoRectangle representing the map in screen coords
function initializePositionChangeSupport( map, earth, screen ) {
    if ( map.id && earth.id ) {
	map.id = POSITION_MAP;
	earth.id = POSITION_EARTH;
	addMap( map );
	addMap( earth );
    } else {
	addMap( POSITION_MAP, map, null, screen, null );
	addMap( POSITION_EARTH, earth, null, screen, null );
    }
    POSITION.positionMap = retrieveMap( POSITION_MAP );
    POSITION.positionEarth = retrieveMap( POSITION_EARTH );
}

// Convenience method to add a PositionChangeListener
// @param PositionChangeListener object
function addPositionChangeListener( positionListener ) {
  POSITION.addListener( positionListener );
}

// Convenience method to fire PositionChangeEvents
// @param event that triggered the position change
// @param optional offset, added to position, 
//  used to translate bounding box to underlying map
// @param optional qualifier for the offset position.
//  if true, the offset refers to an alternate origin rather than an offset.
//  the position will be tranlated back to this reference.
function firePositionChangeEvent( e, offset, offsetIsOrigin ) {
    POSITION.fireChange( e, offset, offsetIsOrigin );
}
