﻿Ext.namespace('Mapping.Ext.Esri');

Mapping.Ext.Esri.Marker = function() {
  var marker, markerDimension, markerTip, markerTipTitle, markerTipContent;
  var markerLocation, map;
  var initialized = false;
  var active = false;

  // Array of markers (and tracker) we cycle through to create a moving effect under Internet Explorer
  // We start at 1 because 30 is the initial marker
  var currentMarker = 1;
  var markers = [
    '<img style="visibility: visible;" src="js/mapping/ext/resources/marker/glow020.png">',
    '<img style="visibility: visible;" src="js/mapping/ext/resources/marker/glow030.png">',
    '<img style="visibility: visible;" src="js/mapping/ext/resources/marker/glow040.png">',
    '<img style="visibility: visible;" src="js/mapping/ext/resources/marker/glow050.png">',
    '<img style="visibility: visible;" src="js/mapping/ext/resources/marker/glow040.png">',
    '<img style="visibility: visible;" src="js/mapping/ext/resources/marker/glow030.png">'
  ];

  /// Fade the marker, then out over a 2 second period
  /// Called repeatedly by FadeMarkerTask
  var fadeMarker = function() {
    marker.fadeIn({ duration: 2 }).fadeOut({ duration: 2 });
  }
  /// Display the next image in the above array
  /// Called repeatedly by updateMarkerTask
  var updateMarkerImage = function() {
    currentMarker++;
    if (currentMarker >= markers.length) {
      currentMarker = 0;
    }
    Ext.DomHelper.overwrite(marker, markers[currentMarker]);
  }
  /// {Task} object for Ext.TaskMgr to run marker animation under non-IE browser
  /// Runs after 4 seconds (the function runs for 4 seconds, so this triggers right as it stops)
  var fadeMarkerTask = {
    interval: 4001,
    run: fadeMarker
  };
  /// {Task} object for Ext.TaskMgr to run marker animation under Internet Explorer
  /// runs every 250ms
  var updateMarkerTask = {
    interval: 250,
    run: updateMarkerImage
  };

  /// Hides/shows the element and starts/stops the blinking
  /// @param {bool} state The state the visibility should be set to
  function setVisible(state) {
    //if(state && !isMarkerReady()) { return; }
    // if the markertip exists and we're hiding the marker, hide the tip first
    if (markerTip != null && !state) {
      markerTip.setVisible(state);
    }
    // turn the marker on and start the blinking, else turn it off and stop blinking
    if (state && active) {

      // Start the blinking
      if (Ext.isIE) {
        marker.show();
        Ext.TaskMgr.start(updateMarkerTask);
      } else {
        Ext.TaskMgr.start(fadeMarkerTask);
        marker.show();
      }
    } else if (!state) {
      // Stop the blinking
      if (Ext.isIE) {
        Ext.TaskMgr.stopAll();
        //Ext.DomHelper.overwrite(marker, "");
        //marker.setDisplayed(false);
        Ext.DomHelper.overwrite(marker, '<img style="visibility: hidden;" src="js/mapping/ext/resources/marker/glow030.png">');
      } else {
        Ext.TaskMgr.stopAll();
        marker.stopFx();
        marker.hide();
      }
    }
  }
  // Offset used in placing the marker on the screen
  function MarkerOffset() {
    return marker.getWidth() / 2;
  }
  // Create the marker tip with the current values
  function createMarkerTip() {
    if (markerTip != null) {
      markerTip.destroy();
      markerTip = null;
    }
    markerTip = new Ext.ToolTip({
      id: 'markerTip',
      target: marker,
      title: markerTipTitle,
      html: markerTipContent,
      anchor: 'left',
      anchorOffset: 30,
      autoHide: false,
      closable: true,
      draggable: true,
      forceLayout: true
    });
  }
  // Sets the location for the marker and checks if it's ready for display
  function setMarkerLocation(point) {
    markerLocation = point;
    updateReady();
  }
  // Sets the content for the marker and checks if it's ready for display
  function setMarkerTipContent(content) {
    markerTipContent = content;
    updateReady();
  }
  // Sets the title for the marker and checks if it's ready for display
  function setMarkerTipTitle(title) {
    markerTipTitle = title;
    updateReady();
  }

  function updateReady() {
    if (isMarkerReady()) {
      Mapping.Ext.Esri.Marker.fireEvent('ready');
    }
  }

  // Check if our marker is ready, meaning it hsa a location, title and content
  function isMarkerReady() {
    if (markerLocation != null && markerTipContent != null && markerTipTitle != null) {
      return true;
    }
    return false;
  }

//  // Delayed task to udate screen only after it's done moving
//  var delayScreenUpdate = new Ext.util.DelayedTask(function() {
//    setScreenLocation();
//    setVisible(true);
//  });

  // Move the marker to the correct spot on the screen for the local variable location
  function setScreenLocation() {
    // If map is null, alert user
    if (map == null) {
      Mapping.Ext.Esri.ErrorManager.generalError('Error', 'Markers widget does not have a map associated yet. Please contact your administrator.');
      return;
    }
    if (isMarkerReady()) {
      if (markerTip) {
        markerTip.hide();
      }
      var screenLocation = map.toScreen(markerLocation);
      if (Ext.isIE) { marker.show(); }
      marker.setLeftTop(screenLocation.x - MarkerOffset(), screenLocation.y - MarkerOffset());
    }
  }

  // Update the marker's data with current local values
  function updateMarker() {
    setScreenLocation();
    // We can only update if it's been rendered. It's not rendered until it's moused over at least once
    // So, if it hasn't been moused over yet, we recreate it to update the content inside
    if (markerTip && markerTip.rendered) {
      markerTip.hide();
      markerTip.update(markerTipContent);
      markerTip.setTitle(markerTipTitle);
    } else {
      createMarkerTip();
    }
    if (Mapping.Ext.Esri.CursorManager) {
      Mapping.Ext.Esri.CursorManager.removeCursor('mouseProgress');
    }
    active = true;
    setVisible(true);
    Mapping.Ext.Esri.Marker.fireEvent('displayed');
  }
  
  var panEvent, zoomEvent, extentEvent;
  
  /// We return our public facing methods here
  /// We are applying (extending) Ext.util.Observable so that we can fire events
  return Ext.apply(new Ext.util.Observable(), {

    /// Hides the marker and tip (if it exists)
    hide: function() {
      setVisible(false);
    },
    
    /// Hides only the marker and does so for the session. 
    /// This allows us to show just the hover manually
    hideMarker: function() {
      setVisible(false);
      dojo.disconnect(extentEvent);
      extentEvent = dojo.connect(map, "onExtentChange", this, function() {
        this.updateScreenLocation(false);
      });
    },

    /// Hides just the tooltip popup
    hidePopUp: function() {
      if (markerTip != null) {
        markerTip.hide();
      }
    },

    isInitialized: function() { return initialized; },

    isReady: function() { return isMarkerReady(); },

    updateScreenLocation: function(showAfter) {
      setScreenLocation();
//      delayScreenUpdate.delay(250);
      if(showAfter != false){
        setVisible(true);
      }
    },

    /// Resets the marker by clearing the title, content and location
    /// @returns {Mapping.Ext.Esri.Marker} Returns a reference to itself so methods can be chained
    /// Ex: Mapping.Ext.Esri.Marker.reset().setLocation();
    reset: function() {
      dojo.disconnect(extentEvent);
      extentEvent = dojo.connect(map, "onExtentChange", this, function() {
        this.updateScreenLocation(true);
      });    
      this.hide();
      markerLocation = null;
      markerTipContent = null;
      markerTipTitle = null;
      active = false;
      return this;
    },

    getLocation: function() {
      return markerLocation;
    },

    /// Assign the location of the marker
    /// @param {esri.geometry.Point} point The point where the marker should be placed
    setLocation: function(point) {
      setMarkerLocation(point);
    },

    /// Set the content to be used next time the marker is shown
    /// @param {content} string The content block in HTML
    /// @param {showAfter} bool (Optional) Whether to display the marker after setting content
    setContent: function(content) {
      setMarkerTipContent(content);
    },

    /// Set the title to be used next time the marker is shown
    /// @param {title} string The title to use
    setTitle: function(title) {
      setMarkerTipTitle(title);
    },

    /// Update the marker content and location and display it
    updateMarker: function() {
      if (this.isReady()) {
        updateMarker();
      }
    },

    /// @param {mapObj} esri.Map The map this marker will be associated with    
    init: function(mapObj) {
      if (!initialized) {
        if (!Ext.get('marker')) {
          console.debug('marker element has not been added to page');
          Mapping.Ext.Esri.ErrorManager.generalError('Mapping application could not be initialized properly. Please notify your administrator.');
          return;
        }
        if (!mapObj.declaredClass || mapObj.declaredClass != 'esri.Map') {
          console.debug('object passed to Marker.init() is not of type esri.Map');
          Mapping.Ext.Esri.ErrorManager.generalError('Mapping application could not be initialized properly. Please notify your administrator.');
          return;
        }
        marker = Ext.get('marker');
        map = mapObj;
        initialized = true;
        // Setup event handler to hide/show marker when the map is moving/moved
        panEvent = dojo.connect(map, "onPan", this, function() {
          this.hide();
        });
        zoomEvent = dojo.connect(map, "onZoom", this, function() {
          this.hide();
        });
        extentEvent = dojo.connect(map, "onExtentChange", this, function() {
          this.updateScreenLocation(true);
        });
      }
    }
  });
  // End of the return Ext.apply() method is here
} ();

/// Config section for Ext.Observable
Mapping.Ext.Esri.Marker.addEvents('ready');
Mapping.Ext.Esri.Marker.addEvents('displayed');
// On show, check if ready and fire update method
Mapping.Ext.Esri.Marker.addListener(
  "show", 
  function() {
    if (this.isReady()) {
      this.updateMarker();
    }
  }, 
  Mapping.Ext.Esri.Marker
);
// When marker is ready, fire update method
Mapping.Ext.Esri.Marker.addListener(
  "ready", 
  function() {
    this.updateMarker();
  }, 
  Mapping.Ext.Esri.Marker
);

