/// Evolver Copyright 2000, Morgan McGuire
/// matrix@alum.mit.edu   http://graphics3d.com/matrix
import java.awt.*;

public abstract class MultiArgumentOperator extends AbstractELOperator implements ELOperator
{
  public void apply(ELMatrix argument[], ELMatrix out, ELEnvironment environment)
  {
    checkArguments(argument);

    int numArguments = argument.length;
    
    out.set(argument[0]);
    for(int a = 1; a < numArguments; a++) {
      combine(out, argument[a]);
    }
  }

  /**
   * Override this to provide your element-by-element operator.  
   */
  protected abstract float combine(float a, float b);

  protected void clamp(ELMatrix out)
  {
    // For extra performance, pull the arrays into locals so we avoid
    // excess dereferences.
    float red[] = out.red;
    float grn[] = out.grn;
    float blu[] = out.blu;

    // For performance, run array backwards.
    for(int i = out.numElements - 1; i >= 0; i--) {
      red[i] = clamp(red[i]);
      grn[i] = clamp(grn[i]);
      blu[i] = clamp(blu[i]);
    }
  }

  /**
   * Combines the cumulative result (out) with the next argument
   * (other).
   */
  protected void combine(ELMatrix out, ELMatrix other)
  {
    // For extra performance, pull the arrays into locals so we avoid
    // excess dereferences.
    float red[] = out.red;
    float grn[] = out.grn;
    float blu[] = out.blu;
    
    float r[] = other.red;
    float g[] = other.grn;
    float b[] = other.blu;
    
    // For performance, run array backwards.
    for(int i = out.numElements - 1; i >= 0; i--) {
      red[i] = combine(red[i], r[i]);
      grn[i] = combine(grn[i], g[i]);
      blu[i] = combine(blu[i], b[i]);
    }
  }

  public int getMaxNumArguments()
  {
    return LARGE_NUMER_OF_ARGUMENTS;
  }

  public int getMinNumArguments()
  {
    return 2;
  }

  public String unparse()
  {
    return name();
  }
}
