// ====================================================================
// Copyright (c) 2005 and onwards, Josh Glover <jmglov@jmglov.net>
//
// LICENCE:
//
//   This file is distributed under the terms of the BSD-2 License.
//   See the COPYING file, which should have been distributed
//   with this file, for details. If you did not receive the
//   COPYING file, see:
//
//   http://www.jmglov.net/opensource/licenses/bsd.txt
//
// Marker.js
//
// DESCRIPTION:
//
//   A Gaijin's Guide to Central Yokohama, Marker class
//
// MODIFICATIONS:
//
//   Josh Glover <jmglov@jmglov.net> (2005/11/01): Initial revision
// ====================================================================


// Object: Marker
//
// Marker


// Constructor: Marker()
//
// Parameters:
//
//   catalogue - MarkerCatalogue object to which this marker belongs
//   cat       - category
//   name      - name of this marker
//   title     - title
//   vis       - is marker visible?
//   gmarker   - [optional] GMarker object
//   gmap      - [optional] GMap object
//   info      - [optional] info HTML
//   date      - [optional] date

function Marker( catalogue, cat, name, title, vis, gmarker, gmap, info, date ) {

  if (name == null || title == null || vis == null) { return null }

  this.catalogue = catalogue;
  this.category  = cat;
  this.date      = date;
  this.gmap      = gmap;
  this.gmarker   = gmarker;
  this.info      = info;
  this.name      = name;
  this.title     = title;
  this.visible   = vis;

  this.createGIcon     = mCreateGIcon;
  this.createGMarker   = mCreateGMarker;
  this.getCatalogue    = mGetCatalogue;
  this.getCategory     = mGetCategory;
  this.getDate         = mGetDate;
  this.getGMap         = mGetGMap;
  this.getGMarker      = mGetGMarker;
  this.getInfo         = mGetInfo;
  this.getName         = mGetName;
  this.getTitle        = mGetTitle;
  this.getVisibility   = mGetVisibility;
  this.populateFromXML = mPopulateFromXML;
  this.setCatalogue    = mSetCatalogue;
  this.setCategory     = mSetCategory;
  this.setDate         = mSetDate;
  this.setGMap         = mSetGMap;
  this.setGMarker      = mSetGMarker;
  this.setInfo         = mSetInfo;
  this.setName         = mSetName;
  this.setTitle        = mSetTitle;
  this.setVisibility   = mSetVisibility;
  this.showInfo        = mShowInfo;

} // Marker()


// Method: createGIcon()
//
// Creates a GIcon object for this Marker.
//
// Returns:
//
//   Newly constructed GIcon object on success; null on failure

function mCreateGIcon() {

  var icon = new GIcon();

  icon.shadow           = "http://www.google.com/mapfiles/shadow50.png";
  icon.iconSize         = new GSize(20, 34);
  icon.shadowSize       = new GSize(37, 34);
  icon.iconAnchor       = new GPoint(9, 34);
  icon.infoWindowAnchor = new GPoint(9, 2);
  icon.infoShadowAnchor = new GPoint(18, 25);
  icon.image            = "icons/m_" + this.getCategory() + ".png";

  return icon;
  
} // mCreateGIcon()


// Method: createGMarker()
//
// Creates a GMarker object for this Marker.
//
// Parameters:
//
//   point - GPoint object
//
// Returns:
//
//   Newly constructed GMarker object on success; null on failure

function mCreateGMarker( point ) {

  if (point == null) { return null }

  var cat  = this.getCategory();
  var name = this.getName();
  var icon = this.createGIcon();
  var gm   = new GMarker( point, icon );
  
  GEvent.addListener( gm, "click", function() {

    var m = m_cat.getMarker( cat, name );
    if (m != null) { m.showInfo() }

    } );

  // If this marker belongs to a catalogue, we will need to register the opening
  // and closing of info windows
  var c = this.getCatalogue();
  if (c != null) {

    GEvent.addListener( gm, "infowindowclose",
                        function() { c.setOpenInfoWindow( null ) } );
    GEvent.addListener( gm, "infowindowopen",
                        function() { c.setOpenInfoWindow( cat ) } );

  } // if (registering open / close events)
  
  return gm;

} // mCreateGMarker()


// Method: getCatalogue()
//
// Gets the catalogue to which this marker belongs.
//
// Returns:
//
//   The MarkerCatalogue object on success, null on failure

function mGetCatalogue() {

  return this.catalogue;

} // mGetCatalogue()


// Method: getCategory()
//
// Gets the category of this marker.
//
// Returns:
//
//   The category of this marker on success, null on failure

function mGetCategory() {

  return this.category;

} // mGetCategory()


// Method: getDate()
//
// Gets the date of this marker.
//
// Returns:
//
//   The date of this marker on success, null on failure

function mGetDate() {

  return this.date;

} // mGetDate()


// Method: getGMap()
//
// Gets the GMap object associated with this marker.
//
// Returns:
//
//   GMap object on success, null on failure

function mGetGMap() {

  return this.gmap;

} // mGetGMap()


// Method: getGMarker()
//
// Gets the GMarker object associated with this marker.
//
// Returns:
//
//   The GMarker object on success, null on failure

function mGetGMarker() {

  return this.gmarker;

} // getGMarker()


// Method: getInfo()
//
// Gets the info HTML of this marker.
//
// Returns:
//
//   The info HTML of this marker on success, null on failure

function mGetInfo() {

  return this.info;

} // mGetInfo()


// Method: getName()
//
// Gets the name of this marker.
//
// Returns:
//
//   The name of this marker on success, null on failure

function mGetName() {

  return this.name;

} // mGetName()


// Method: getTitle()
//
// Gets the title of this marker.
//
// Returns:
//
//   The title of this marker on success, null on failure

function mGetTitle() {

  return this.title;

} // mGetTitle()


// Method: getVisibility()
//
// Gets the visibility of this marker.
//
// Returns:
//
//   The visibility of this marker on success, null on failure

function mGetVisibility() {

  return this.visible;

} // mGetVisibility()


// Method: populateFromXML()
//
// Populates a marker from a chunk of an XML DOM object. Note that you probably
// do not need to call <populateFromXML()> directly; see
// <MarkerCatalogue::populateFromXML()>.
//
// Parameters:
//
//   xml - chunk of XML DOM object
//
// Returns:
//
//   The marker that was populated on success, null on failure

function mPopulateFromXML( xml ) {

  if (xml == null) { return null }

  var name  = xml.getAttribute( "name" );
  var x     = parseFloat( xml.getAttribute( "lng" ) );
  var y     = parseFloat( xml.getAttribute( "lat" ) );

  // The next three are complicated, since they are not attributes but nested
  // tags. We must first grab the node, then extract the text.
  var n_title = xml.getElementsByTagName( "title" );
  var n_info  = xml.getElementsByTagName( "info" );
  var n_date  = xml.getElementsByTagName( "date" );

  var title;
  var info;
  var date;
  
  if (n_title != null &&
      n_title.length != 0) { title = n_title[0].firstChild.nodeValue }
  if (n_info != null &&
      n_info.length != 0)  { info  = n_info[0].firstChild.nodeValue  }
  if (n_date != null &&
      n_date.length != 0)  { date  = n_date[0].firstChild.nodeValue  }
    
  if (name == null || title == null ||
      x == null || y == null || isNaN( x ) || isNaN( y )) { return null }

  // Replace newlines inside the XML info tag with <br /> tags for our HTML
  if (info != null) { info = info.replace( /([^^])\n([^$])/g, "$1<br />$2" ) }
  
  this.setDate( date );
  this.setInfo( info );
  this.setName( name );
  this.setTitle( title );
  var point = new GPoint( x, y );

  var html = "<b>" + title + "</b>";
  if (info != null) { html += "<br />" + info }
  this.setGMarker( this.createGMarker( point ) );

  return this;

} // mPopulateFromXML()


// Method: setCatalogue()
//
// Sets the catalogue to which this marker belongs.
//
// Parameters:
//
//   catalogue - MarkerCatalogue object
//
// Returns:
//
//   The new MarkerCatalogue object on success, null on failure

function mSetCatalogue( catalogue ) {

  this.catalogue = catalogue;
  return this.catalogue;

} // mSetCatalogue()


// Method: setCategory()
//
// Sets the category of this marker.
//
// Paramters:
//
//   cat - new category of marker
//
// Returns:
//
//   The new category of this marker on success, null on failure

function mSetCategory( cat ) {

  if (cat == null || cat == '') { return null }

  this.category = cat;
  
  return this.category;

} // mSetCategory()


// Method: setDate()
//
// Sets the date of this marker.
//
// Paramters:
//
//   date - new date of marker
//
// Returns:
//
//   The new date of this marker on success, null on failure

function mSetDate( date ) {

  if (date == null || date == '') { return null }

  this.date = date;
  
  return this.date;

} // mSetDate()


// Method: setGMap()
//
// Sets the GMap object associated with this marker.
//
// Parameters:
//
//   gmap - GMap object
//
// Returns:
//
//   New GMap object on success, null on failure

function mSetGMap( gmap ) {

  this.gmap = gmap;
  return this.gmap;

} // mSetGMap()


// Method: setGMarker()
//
// Sets the GMarker object associated with this marker.
//
// Paramters:
//
//   gmarker - new GMarker object
//
// Returns:
//
//   The new GMarker object on success, null on failure

function mSetGMarker( gmarker ) {

  if (gmarker == null) { return null }

  this.gmarker = gmarker;
  
  return this.gmarker;

} // mSetGMarker()


// Method: setInfo()
//
// Sets the info HTML for this marker.
//
// Paramters:
//
//   info - new info HTML
//
// Returns:
//
//   The new info HTML for this marker on success, null on failure

function mSetInfo( info ) {

  if (info == null) { return null }

  this.info = info;
  
  return this.info;

} // mSetInfo()


// Method: setName()
//
// Sets the name of this marker.
//
// Paramters:
//
//   name - new name of marker
//
// Returns:
//
//   The new name of this marker on success, null on failure

function mSetName( name ) {

  if (name == null || name == '') { return null }

  this.name = name;
  
  return this.name;

} // mSetName()


// Method: setTitle()
//
// Sets the title of this marker.
//
// Paramters:
//
//   title - new title of marker
//
// Returns:
//
//   The new title of this marker on success, null on failure

function mSetTitle( title ) {

  if (title == null || title == '') { return null }

  this.title = title;
  
  return this.title;

} // mSetTitle()


// Method: setVisibility()
//
// Sets the visibility of this marker.
//
// Parameters:
//
//   vis - new visibility
//
// Returns:
//
//   The new visibility of this marker on success, null on failure

function mSetVisibility( vis ) {

  if (vis == null) { return null }

  this.visible = vis;

  return this.visible;

} // mSetVisibility()


// Method: showInfo()
//
// Loads the info panel with this marker's info and opens either a map blowup
// or an info window, depending on the zoom level.
//
// Parameters:
//
//   type - [optional; default: 'info' for zoom level 0, 'map' otherwise] set to
//          'info' to open an info window, 'map' to open a map blowup

function mShowInfo( type ) {

  var html = "<b>" + this.getTitle() + "</b>";
  var info = this.getInfo();
  if (info != null && info != '') { html += "<br />" + info }

  // !!! Oh my! This call to a global function show be replaced somehow! !!!
  // Load the info text into the info panel
  loadInfoPanel( html );
  // !!! Oh my! This call to a global function show be replaced somehow! !!!

  var map = this.getGMap();
  var gm  = this.getGMarker();

  // If we have a zoom type of 'map', open the map blowup, zoomed into 0
  if (type == 'map') { gm.showMapBlowup( 0 ) }
  
  // Otherwise, if the zoom level is already 0 or we have a type of 'info', open
  // an info window over the marker
  else if (type == 'info' || map.getZoomLevel() == 0) {

    gm.openInfoWindowHtml( html );

  } // else if (opening info window)

  // Otherwise, show a blowup of the marker, zoomed in to 0
  else { gm.showMapBlowup( 0 ) }

} // mShowInfo()
