/** Defines the Wales_PointOfInterest_Pin class.
 *
 * @author Josh Zerin <josh.zerin@standingdog.com>
 * @since Thursday, April 16, 2009
 *
 * @package HotelWales
 * @subpackage Library
 */

/** Implements a pin in a POI map.
 *
 * @package PointOfInterest
 */
function Wales_PointOfInterest_Pin(  )
{
  /**#@+ @access private */
  var

    /** Unique identifier for this object.
     *
     * @var Number
     */
    $myUID = Wales_PointOfInterest_Controller.generateUID(),

    /** The POI associated with this pin.
     *
     * @var Wales_PointOfInterest
     */
    $myPointOfInterest,

    /** Stores whether the pin is active (visible) or inactive (hidden).
     *
     * @var Boolean
     */
    $myState = false,

    /** The map to which this pin will be applied.
     *
     * @var google.maps.GMap2
     */
    $myMap,

    /** Caches a constructed GMarker for adding to/removing from maps.
     *
     * @var GMarker
     */
    $myGMarker;
  /**#@-*/

  /** Accessor for $myUID.
   *
   * @return Number
   */
  this['getUID'] =
    function(  )
    {
      return $myUID;
    };

  /** Accessor for $myPointOfInterest.
   *
   * @return Wales_PointOfInterest
   */
  this['getPointOfInterest'] =
    function(  )
    {
      return $myPointOfInterest;
    };

  /** Modifier for $myPointOfInterest.
   *
   * @param Wales_PointOfInterest $Point
   *
   * @return Wales_PointOfInterest_Pin this (for chaining).
   */
  this['setPointOfInterest'] =
    function( $Point )
    {
      /* Validate $Point. */
      if( $Point && $Point.constructor == Wales_PointOfInterest )
      {
        $myPointOfInterest = $Point;

        /* Fix reciprocal reference if necessary. */
        if( $myPointOfInterest.getPin() != this )
        {
          $myPointOfInterest.setPin(this);
        }

        return this;
      }
      else
      {
        throw 'Point of interest must be an instance of Wales_PointOfInterest.';
      }
    };

  /** Accessor for $myState.
   *
   * @return Boolean
   */
  this['getState'] =
    function(  )
    {
      return $myState;
    };

  /** Modifier for $myState.
   *
   * @param Boolean $state
   *
   * @return Wales_PointOfInterest_Pin this (for chaining).
   */
  this['setState'] =
    function( $state )
    {
      if( $myState != $state )
      {
        $myState = Boolean($state);
        this.apply();
      }

      return this;
    };

  /** Toggles $myState between on and off.
   *
   * @return Wales_PointOfInterest_Pin this (for chaining).
   */
  this['toggleState'] =
    function(  )
    {
      this.setState(! this.getState());
    };

  /** Modifier for $myMap.
   *
   * @param google.maps.Map2 $Map
   *
   * @return Wales_PointOfInterest_Pin this (for chaining).
   */
  this['setMap'] =
    function( $Map )
    {
      if( $Map != $myMap )
      {
        var $prevState = $myState;

        /* Destroy any existing pins. */
        if( $myState )
        {
          this.setState(false);
        }

        /* Set the new map. */
        $myMap = $Map;

        /* Display the pin if it was previously visible. */
        if( $prevState )
        {
          this.setState(true);
        }
      }
      return this;
    };

  /** Adds or removes the actual pin to or from a map.
   *
   * @return Wales_PointOfInterest_Pin this (for chaining).
   */
  this['apply'] =
    function(  )
    {
      /* Validate $myMap. */
      if( typeof($myMap) == 'undefined' )
      {
        throw 'Call to method apply() before $myMap has been set.';
      }

      if( $myState )
      {
        /* Check to see if we've set up the marker yet. */
        if( typeof($myGMarker) == 'undefined' )
        {
          /* Validate $myPointOfInterest. */
          if( ! $myPointOfInterest.getName() )
          {
            throw 'Attempting to create an overlay window for a POI with no name.';
          }

          /* Set the icon for this marker.
           *
           * Right now, we're using color variations on the standard GMap
           *  marker, so we only have to worry about the base URL.
           *
           * Note that we need to clone G_DEFAULT_ICON, not modify it.
           */
          var $GIcon = $.extend(new GIcon(), G_DEFAULT_ICON);
          $GIcon.image = $myPointOfInterest.getCategory().getPinIcon();

          $myGMarker =
            new GMarker(
              new google.maps.LatLng(
                $myPointOfInterest.getGeocode()[0],
                $myPointOfInterest.getGeocode()[1]
              ), {
                'icon'          : $GIcon,
                'zIndexProcess' : function( $Marker ) {
                  return 1; // Send to front.
                }
              }
            );

          /* Create an overlay window. */
          var $overlay =
            $(document.createElement('div')).append(
              /* KLUDGE:  jQuery's html() method only returns *inner* HTML. */
              $(document.createElement('div'))
                .addClass('poi-gmap-overlay')

                /* Lead with the property name. */
                .append(
                  $(document.createElement('span'))
                    .addClass('poi-gmap-overlay-name')
                    .text($myPointOfInterest.getName())
                )

                /* KLUDGE:  GMap overlay windows don't size properly unless you
                 *  use <br />s.
                 */
                .append(document.createElement('br'))
            );

          /* Add the POI's URL if applicable. */
          if( $myPointOfInterest.getURL() )
          {
            $overlay.append(
              $(document.createElement('span'))
                .addClass('poi-gmap-overlay-url')
                .append(
                  $(document.createElement('a'))
                    .attr('href', $myPointOfInterest.getURL())
                    .attr('target', '_blank')
                    .text($myPointOfInterest.getURL())
                )

                /* KLUDGE:  GMap overlay windows don't size properly unless you
                 *  use <br />s.
                 */
                .append(document.createElement('br'))
            );
          }

          /* Add the POI's addy if applicable. */
          if( $myPointOfInterest.getAddress() )
          {
            $overlay.append(
              $(document.createElement('span'))
                .addClass('poi-gmap-overlay-address')
                .html($myPointOfInterest.getAddress())
            )

            /* KLUDGE:  GMap overlay windows don't size properly unless you use
             *  <br />s.
             */
            .append(document.createElement('br'));
          }

          /* Add the overlay window generator.
           *
           * KLUDGE: bindInfoWindow() breaks after the first click.
           */
          $myGMarker.bindInfoWindowHtml(
            $overlay.html(),
            {'maxWidth': 140}
          );

          $myMap.addOverlay($myGMarker);
        }
        else
        {
          $myGMarker.show();
        }
      }

      /* If $myState is false, we only have to remove existing markers. */
      else if( typeof($myGMarker) != 'undefined' )
      {
        /* Remove the marker. */
        $myGMarker.hide();
      }
    };

  /** Destroys the pin's marker.  If the pin is visible, the marker will be
   *   rebuilt.
   *
   * If the pin hasn't built a marker yet, this method does nothing.
   *
   * @return Wales_PointOfInterest_Pin this (for chaining).
   */
  this['rebuildMarker'] =
    function(  )
    {
      if( typeof($myGMarker) != 'undefined' )
      {
        $prevState = $myState;

        /* Get rid of any existing markers. */
        this.setState(false);

        /* Destroy the existing marker. */
        $myGMarker = null;

        /* Reset the marker state. */
        this.setState($prevState);
      }
    };

  /** Returns the latitude/longitude of the Pin's marker.
   *
   * @return GLatLng
   */
  this['getLatLng'] =
    function(  )
    {
      if( $myGMarker )
      {
        return $myGMarker.getLatLng();
      }
    };
}