/*
 * Copyright 2009-2010  Stefan Gehn <stefan@srcbox.net>
 * 
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 2 of 
 * the License, or (at your option) any later version.
 * 
 * This program 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 General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#ifndef TOUCHDATA_HPP_
#define TOUCHDATA_HPP_

#include "Value.hpp"
#include "Packet.hpp"

#include <qlist.h>
#include <qhash.h>

namespace IrTouch
{

// ----------------------------------------------------------------------------
class TouchData;

class TouchRect: public QRect
{
  friend class TouchData;
public:
  TouchRect() : mId(0), mXId(0), mYId(0)
  {
  }

  TouchRect(Value &xVal, Value &yVal) :
    mId(++sId), mXId(xVal.id()), mYId(yVal.id())
  {
    updateFromValues(xVal, yVal);
    //qDebug() << "TouchRect::TouchRect()" << mId;
  }

  virtual ~TouchRect()
  {
    //qDebug() << "TouchRect::~TouchRect()" << mId;
  }

  void updateFromValues(Value &xVal, Value &yVal)
  {
    // Assert if TouchRect gets updated with wrong Values
    Q_ASSERT(mXId == xVal.id());
    Q_ASSERT(mYId == yVal.id());
    //qDebug() << "TouchRect::setFromValues()" << mId;
    setRect(xVal.start(), yVal.start(), xVal.extent(), yVal.extent());
  }

  bool isValid() const
  {
    return mId > 0;
  }

  quint32 id() const
  {
    return mId;
  }

  quint32 xId() const
  {
    return mXId;
  }

  quint32 yId() const
  {
    return mYId;
  }

  //! Scales all positions, widths and heights by @p xfactor and @p yfactor
  void scaleBy(qreal xfactor, qreal yfactor)
  {
    qreal xv = x() * xfactor;
    qreal yv = y() * yfactor;
    qreal wv = width() * xfactor;
    qreal hv = height() * yfactor;
    setRect((int)xv, (int)yv, (int)wv, (int)hv);
  }

  /*qreal relativeDifference(const TouchRect &o) const
  {
    QPointF posChange = topLeft() - o.topLeft();
    QSizeF sizeChange = size() - o.size();
    posChange.rx() -= sizeChange.width();
    posChange.ry() -= sizeChange.height();
    return posChange.x() + posChange.y();
  }*/

  /*int centerDiff(const TouchRect &o) const
  {
    return center().manhattanLength() - o.center().manhattanLength();
  }*/

  bool operator==(const TouchRect &o) const
  {
    return (mId == o.mId);
  }

private:
  static quint32 sId;

  quint32 mId;
  quint32 mXId;
  quint32 mYId;
};

typedef QHash<quint32, TouchRect>  TouchRectHash;


// ----------------------------------------------------------------------------

class TouchData
{
  friend class Decoder;
public:
  TouchData();
  virtual ~TouchData();

  //! @return true if packet contains no values at all
  bool isEmpty() const
  {
    return mXValues.isEmpty() || mYValues.isEmpty();
  }

	//! Computes the bounding rectangle around all x/y values.
  QRect boundingRect() const;

	inline const ValueList &xValues() const { return mXValues; }
	inline const ValueList &yValues() const { return mYValues; }
	inline const QList<RawValue> &rawXValues() const { return mRawXValues; }
	inline const QList<RawValue> &rawYValues() const { return mRawYValues; }
	inline const TouchRectHash &rects() const { return mRects; }

	//! @return Sum of the number of values on both axes.
	const int valueSum() const { return mXValues.count() + mYValues.count(); }

  //! Scales all positions, widths and heights by @p xfactor and @p yfactor
  void scaleBy(qreal xfactor, qreal yfactor);

  void updateRects();
  void updateObjectType();

  const QString &guessedObjectType() const
  {
    return mGuessedObjectType;
  }

private:
  static qreal sPpmX; // (touch)pixels per mm on x-axis
  static qreal sPpmY; // (touch)pixels per mm on y-axis

	//! Uninterpreted x-values coming from the hardware
	QList<RawValue> mRawXValues;

	//! Uninterpreted y-values coming from the hardware
	QList<RawValue> mRawYValues;

	ValueList mXValues;
	ValueList mYValues;

  TouchRectHash mRects;

  QString mGuessedObjectType;
};

} // namespace


QDebug operator<<(QDebug dbg, const IrTouch::TouchRect &tr);
QDebug operator<<(QDebug dbg, const IrTouch::TouchData &td);
//QDebug operator<<(QDebug dbg, const IrTouch::ValueList &l);

#endif /* TOUCHDATA_HPP_ */
