OpenLayers.Control.HoverClickSelect = OpenLayers.Class(OpenLayers.Control.SelectFeature, {
    
    hover: true,
    onSelectHover: function() {},
    onSelectClick: function() {},
    highLightedFeature: null,
    
    initialize: function(layers, options) {
        OpenLayers.Control.SelectFeature.prototype.initialize.apply(this, [layers, options]);
        
        this.handlers.feature.handle = function(evt) {
            if(this.feature && !this.feature.layer) {
                // feature has been destroyed
                this.feature = null;
            }
                        
            var type = evt.type;
            var handled = false;
            var previouslyIn = !!(this.feature); // previously in a feature
            var click = (type == "click" || type == "dblclick");
            this.feature = this.layer.getFeatureFromEvent(evt);
            if(this.feature && !this.feature.layer) {
                // feature has been destroyed
                this.feature = null;
            }
            if(this.lastFeature && !this.lastFeature.layer) {
                // last feature has been destroyed
                this.lastFeature = null;
            }
            if(this.feature) {
                /////////////////////////////////
                this.feature.latestEvent = evt;
                ////////////////////////////////
                var inNew = (this.feature != this.lastFeature);
                if(this.geometryTypeMatches(this.feature)) {
                    // in to a feature
                    if(previouslyIn && inNew) {
                        // out of last feature and in to another
                        if(this.lastFeature) {
                            this.triggerCallback(type, 'out', [this.lastFeature]);
                        }
                        this.triggerCallback(type, 'in', [this.feature]);
                    } else if(!previouslyIn || click) {
                        // in feature for the first time
                        this.triggerCallback(type, 'in', [this.feature]);
                    }
                    this.lastFeature = this.feature;
                    handled = true;
                } else {
                    // not in to a feature
                    if(this.lastFeature && (previouslyIn && inNew || click)) {
                        // out of last feature for the first time
                        this.triggerCallback(type, 'out', [this.lastFeature]);
                    }
                    // next time the mouse goes in a feature whose geometry type
                    // doesn't match we don't want to call the 'out' callback
                    // again, so let's set this.feature to null so that
                    // previouslyIn will evaluate to false the next time
                    // we enter handle. Yes, a bit hackish...
                    this.feature = null;
                }
            } else {
                if(this.lastFeature && (previouslyIn || click)) {
                    this.triggerCallback(type, 'out', [this.lastFeature]);
                }
            }
            return handled;
        };
    },
   
        /**
        * Method: clickFeature
        * Called on click in a feature
        * Only responds if this.hover is false.
        *
        * Parameters:
        * feature - {<OpenLayers.Feature.Vector>} 
        */
       clickFeature: function(feature) {
           
           var selected = (OpenLayers.Util.indexOf(
               feature.layer.selectedFeatures, feature) > -1);
           if(selected) {
               if(this.toggleSelect()) {
                   this.unselect(feature);
               } else if(!this.multipleSelect()) {
                   this.unselectAll({except: feature});
               }
           } else {
               if(!this.multipleSelect()) {
                   this.unselectAll({except: feature});
               }
               this.select(feature, false);
           }
      
       },
       
       /**
       * Method: clickoutFeature
       * Called on click outside a previously clicked (selected) feature.
       * Only responds if this.hover is false.
       *
       * Parameters:
       * feature - {<OpenLayers.Vector.Feature>} 
       */
      clickoutFeature: function(feature) {
          if(this.clickout) {
              this.unselectAll();
          }
      },

      /**
       * Method: overFeature
       * Called on over a feature.
       * Only responds if this.hover is true.
       *
       * Parameters:
       * feature - {<OpenLayers.Feature.Vector>} 
       */
      overFeature: function(feature) {
          var layer = feature.layer;
          
          if(this.highlightOnly) {
              this.highlight(feature);
          } else if(OpenLayers.Util.indexOf(
              layer.selectedFeatures, feature) == -1) {
              this.select(feature, true);
          }
          
      },
      
      /**
       * Method: outFeature
       * Called on out of a selected feature.
       * Only responds if this.hover is true.
       *
       * Parameters:
       * feature - {<OpenLayers.Feature.Vector>} 
       */
      outFeature: function(feature) {
          
          if(this.highlightOnly) {
              // we do nothing if we're not the last highlighter of the
              // feature
              if(feature._lastHighlighter == this.id) {
                  // if another select control had highlighted the feature before
                  // we did it ourself then we use that control to highlight the
                  // feature as it was before we highlighted it, else we just
                  // unhighlight it
                  if(feature._prevHighlighter &&
                     feature._prevHighlighter != this.id) {
                      delete feature._lastHighlighter;
                      var control = this.map.getControl(
                          feature._prevHighlighter);
                      if(control) {
                          control.highlight(feature);
                      }
                  } else {
                      this.unhighlight(feature);
                  }
              }
          } else {
              this.unselect(feature, true);
          }
         
      },
      
      /**
       * Method: select
       * Add feature to the layer's selectedFeature array, render the feature as
       * selected, and call the onSelect function.
       * 
       * Parameters:
       * feature - {<OpenLayers.Feature.Vector>} 
       */
      select: function(feature, hovering) {
          if (hovering == feature.hovering) {
              var cont = this.onBeforeSelect.call(this.scope, feature);
              var layer = feature.layer;
              if(cont !== false) {
                  cont = layer.events.triggerEvent("beforefeatureselected", {
                      feature: feature
                  });
                  if(cont !== false) {
                      layer.selectedFeatures.push(feature);
                      this.highlight(feature);
                      layer.events.triggerEvent("featureselected", {feature: feature});
                      
                      if (hovering) {
                          slctd = this.onSelectHover.call(this.scope, feature);
                      } else {
                          slctd = this.onSelectClick.call(this.scope, feature);
                      }
                  }
              }
         } else if (feature.type == 'directory') {
             slctd = this.onSelectHover.call(this.scope, feature);
         }
      },
      
      /**
       * Method: unselect
       * Remove feature from the layer's selectedFeature array, render the feature as
       * normal, and call the onUnselect function.
       *
       * Parameters:
       * feature - {<OpenLayers.Feature.Vector>}
       */
      unselect: function(feature, hovering) {
          var layer = feature.layer;
          // Store feature style for restoration later
          this.unhighlight(feature);
          OpenLayers.Util.removeItem(layer.selectedFeatures, feature);
          layer.events.triggerEvent("featureunselected", {feature: feature});
          this.onUnselect.call(this.scope, feature, hovering);
      },
      
    CLASS_NAME: "OpenLayers.Control.HoverClickSelect"
});
