import java.util.*;
import AgentWorld.*;

class ObjectType_Feature extends Feature
{ // One feature is the object TYPE in a given direction.

  ObjectType_Feature(int direction)
  {
    super(direction);
  }

  // Is this other feature instance denoting ("specifying") the same feature as this one?
  boolean equals(Feature otherFeature)
  {
    return (otherFeature instanceof ObjectType_Feature &&
            otherFeature.sensorDirection == sensorDirection);
  }

  // Collect the subset of examples where, in this feature's direction,
  // an object of the specified type is seen.
  Vector collectMatchingExamples(Vector examples, int objectType)
  { 
    if (examples == null) return null;

    Vector result = new Vector();
    int length = examples.size();
    for(int i = 0; i < length; i++)
    { LabeledExample thisExample = (LabeledExample)(examples.elementAt(i));
      Sensors        sensors     = thisExample.getSensorReadings();

      if (sensors.getObjectType(sensorDirection) == objectType)
      {
        result.addElement(thisExample); // Found a matching example; save it.
      }
    }

    return result; // Return the list of examples that passed the test.
  }
  
  // Count the number of examples that will follow the specified arc out of this feature.
  // (I've converted my soln to no longer use this method; instead
  // computeInfo() does this counting while it is iterating through
  // the examples looking for '+' and '-' examples.  However, I'm
  // leaving this method here as sample code that illustrates iterating through a list
  // and counting items that pass some test.)
  int countMatchingExamples(Vector examples, int objectType)
  { int count = 0;

    if (examples == null) return 0;

    int length = examples.size();
    for(int i = 0; i < length; i++)
    { LabeledExample thisExample = (LabeledExample)(examples.elementAt(i));
      Sensors        sensors     = thisExample.getSensorReadings();

      if (sensors.getObjectType(sensorDirection) == objectType)
      {
        count++; // Found a matching example; count it.
      }
    }

    return count;
  }  
  
  // Compute the weighted info of the subset of examples that
  // follow the indicated arc for this feature.  
  double computeInfo(Vector examples, int objectType)
  {
    if (examples == null) return 0.0;

    int length = examples.size(), countPos = 0, countNeg = 0,
        matchingExamplesCount = 0; // The number of examples that
                                   // follow this arc out of this feature.
    for(int i = 0; i < length; i++)
    { LabeledExample thisExample = (LabeledExample)(examples.elementAt(i));
      Sensors        sensors     = thisExample.getSensorReadings();

      if (sensors.getObjectType(sensorDirection) == objectType)
      {
        matchingExamplesCount++;
        if (thisExample.isaGoodDirectionToMove()) countPos++; else countNeg++;
      }
    }

    if (matchingExamplesCount <= 0) return 0.0;

    double sum = 0.0;

    if (countPos > 0) // Recall that we define 0 * log(0) = 0.
    { double fractionPos = countPos / (double)matchingExamplesCount;

      // Need to convert log base e to log base 2.
      sum -= fractionPos * Math.log(fractionPos) / Math.log(2);
    }
    if (countNeg > 0)
    { double fractionNeg = countNeg / (double)matchingExamplesCount;

      sum -= fractionNeg * Math.log(fractionNeg) / Math.log(2);
    }

    // Weight the info in the pos/neg mixture by the fraction
    // of examples that follow this arc out of this feature.
    return (matchingExamplesCount / (double)length) * sum;
  }
}

