/*
 *  Trace2DArithmeticMeanX.java of project jchart2d, a trace 
 *  that accumulates the latest n x values added to a single point with the arithmetic 
 *  mean y value and the latest x value. 
 *  Copyright 2005 - 2011 (C) Achim Westermann.
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License as published by the Free Software Foundation; either
 *  version 2.1 of the License, or (at your option) any later version.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA*
 *  If you modify or optimize the code in a useful way please let me know.
 *  Achim.Westermann@gmx.de
 *
 */
package info.monitorenter.gui.chart.traces.computing;

import info.monitorenter.gui.chart.ITracePoint2D;
import info.monitorenter.gui.chart.traces.ATrace2D;
import info.monitorenter.util.collections.IRingBuffer;
import info.monitorenter.util.collections.RingBufferArrayFast;

import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;

/**
 * A trace that accumulates the latest n x values added to points with
 * the arithmetic mean x value and the latest y value.
 * <p>
 * 
 * This trace will not reduce the amount of n points added to one carrying the arithmetic mean but 
 * always add a point that has the average of the recent added n points.
 * <p>
 * 
 * Please note that this trace scan be used in two modes:
 * <ol>
 * <li>Stand alone: <br/>
 * Add the <code>ITrace2D</code> implementation to a chart and add data points
 * to it as normal.</li>
 * <li>Computing trace: <br/>
 * Add the <code>ITrace2D</code> implementation as a computing trace to an
 * existing trace via
 * <code>{@link info.monitorenter.gui.chart.ITrace2D#addComputingTrace(info.monitorenter.gui.chart.ITrace2D)}</code>
 * and only add data points to the original trace. Add the computing trace to
 * the same chart and updates of the original trace will be reflected on the
 * computing trace as well.</li>
 * </ol>
 * <p>
 * 
 * @author Achim Westermann
 * 
 * @version $Revision: 1.4 $
 * 
 */
public class Trace2DArithmeticMeanX extends ATrace2D {

  /** Generated <code>serialVersionUID</code>. */
  private static final long serialVersionUID = -4365986306182830082L;

  /** The buffer for the points about to be merged. */
  private final IRingBuffer<ITracePoint2D> m_pointBuffer;

  /** The internal list of points to render. */
  private final List<ITracePoint2D> m_points = new LinkedList<ITracePoint2D>();

  /**
   * The amount of n recent points to buffer. private int m_pointBufferSize; /**
   * Constructor with the given amount of points to merge into one point with
   * their arithmetic mean.
   * <p>
   * 
   * @param arithmenticMeanSpan
   *          the amount of points to merge into one point with their arithmetic
   *          mean.
   */
  public Trace2DArithmeticMeanX(final int arithmenticMeanSpan) {
    super();
    this.m_pointBuffer = new RingBufferArrayFast<ITracePoint2D>(arithmenticMeanSpan);
  }

  /**
   * @see info.monitorenter.gui.chart.traces.ATrace2D#addPointInternal(info.monitorenter.gui.chart.ITracePoint2D)
   */
  @Override
  protected boolean addPointInternal(final ITracePoint2D p) {
    this.m_pointBuffer.add(p);
    final ITracePoint2D cumulate = this.getArithmeticMean();
    final boolean result = this.m_points.add(cumulate);
    this.firePointAdded(cumulate);
    return result;
  }

  /**
   * Returns a point with the arithmetic mean values for x and y computed of the
   * last n added points (n was constructor - given).
   * <p>
   * 
   * @return a point with the arithmetic mean values for x and y computed of the
   *         last n added points (n was constructor - given).
   */
  private ITracePoint2D getArithmeticMean() {
    double x = 0;
    double y = 0;
    ITracePoint2D result;
    for (final ITracePoint2D point : this.m_pointBuffer) {
      result = point;
      x += result.getX();
      y = result.getY();
    }
    int divisor = this.m_pointBuffer.size();
    if (divisor == 0) {
      divisor = 1;
    }
    x /= divisor;
    result = this.getRenderer().getTracePointProvider().createTracePoint(x, y);
    return result;

  }

  /**
   * @see info.monitorenter.gui.chart.ITrace2D#getMaxSize()
   */
  public int getMaxSize() {
    return Integer.MAX_VALUE;
  }

  /**
   * @see info.monitorenter.gui.chart.ITrace2D#getSize()
   */
  public int getSize() {

    return this.m_points.size();
  }



  /**
   * @see info.monitorenter.gui.chart.ITrace2D#isEmpty()
   */
  public boolean isEmpty() {
    return this.m_points.isEmpty();
  }

  /**
   * @see info.monitorenter.gui.chart.ITrace2D#iterator()
   */
  public Iterator<ITracePoint2D> iterator() {
    return this.m_points.iterator();
  }

  /**
   * @see info.monitorenter.gui.chart.traces.ATrace2D#removeAllPointsInternal()
   */
  @Override
  protected void removeAllPointsInternal() {
    this.m_pointBuffer.clear();
    this.m_points.clear();

  }

  /**
   * @see info.monitorenter.gui.chart.traces.ATrace2D#removePointInternal(info.monitorenter.gui.chart.ITracePoint2D)
   */
  @Override
  protected ITracePoint2D removePointInternal(final ITracePoint2D point) {
    final ITracePoint2D result = this.m_points.remove(0);
    return result;
  }

}
