/////////////////////////////////////////////////////////////////////////////
// File:        roitype.h
// Author:      Cesar Mauri Loba (cesar at crea-si dot com)
// Copyright:   (C) 2011 Cesar Mauri Loba - CREA Software Systems
// 
//  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 3 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 ROITYPE_H
#define ROITYPE_H

#include "spcore/pin.h"
#include "spcore/pinimpl.h"
#include "spcore/coreruntime.h"
#include "spcore/basictypes.h"
#include "spcore/iterator.h"
#include <vector>

namespace mod_camera {
/**
	Class that carries a Region Of Interest (ROI)
*/
class CTypeROIContents;
typedef spcore::SimpleType<CTypeROIContents> CTypeROI;

class CTypeROIContents : public spcore::CTypeAny {
public:
	static inline const char* getTypeName() { return "roi"; }

	virtual float GetX() const { return m_x; }
	//virtual void SetX(float x) { assert (x>= 0.0f && x<= 1.0f); m_x= x; }
	virtual float GetY() const { return m_y; }
	//virtual void SetY(float y) { assert (y>= 0.0f && y<= 1.0f); m_y= y; }

	virtual float GetWidth() const { return m_width; }
	//virtual void SetWidth(float w) { assert (w>= 0.0f && w<= 1.0f); m_Width= w; }
	virtual float GetHeight() const { return m_height; }
	//virtual void SetHeight(float h) { assert (h>= 0.0f && h<= 1.0f); m_Height= h; }

	// Set ROI origin
	virtual void SetP1Move (float x, float y);
	virtual void SetOrigin (float x, float y) { SetP1Move (x, y); }

	// Resize ROI
	virtual void SetSize (float width, float height);
	virtual void GetSize (float& width, float& height) const;

	virtual void SetP1Resize (float x, float y);	
	virtual void SetP2Resize (float x, float y);	

	virtual void SetCenter (float x, float y);
	virtual void GetCenter (float& x, float& y) const;

	virtual bool GetUseDirection() const { return m_useDirection; }
	virtual void SetUseDirection(bool v)  { m_useDirection= v; }
	
	virtual float GetDirection() const { return m_direction; }
	virtual void SetDirection(float d) { m_direction= d; }
	
	virtual bool GetIsVisible() const { return m_isVisible; }
	virtual void SetIsVisible(bool v)  { m_isVisible= v; }
	
	virtual bool GetIsEditable() const { return m_isEditable; }
	virtual void SetIsEditable(bool v)  { m_isEditable= v; }
	
	/**
		@brief Return the drawing color of the ROI
		@returns 32 bit int formatted as 0xAARRGGBB
	*/
	virtual unsigned int GetColor() const { return m_color; }
	/**
		@brief Sets the drawing color of the ROI
		@param c	32 bit int formatted as 0xAARRGGBB
	*/
	virtual void SetColor(unsigned int c) { m_color= c; }

	virtual unsigned int GetRegistrationId() const { return m_registrationId; }
	virtual void SetRegistrationId(unsigned int id)  { m_registrationId= id; }
	
	virtual bool RegisterChildROI (CTypeROI* roi);
	virtual bool UnregisterChildROI (CTypeROI* roi);

	// Support composite behaviour but only allow to add ROIs
	virtual int AddChild(SmartPtr<spcore::CTypeAny> component);
	virtual SmartPtr<spcore::IIterator<spcore::CTypeAny*> > QueryChildren() const;

protected:
	CTypeROIContents(int id) : CTypeAny(id) {
		m_x= m_y= 0.0f;
		m_width= m_height= 1.0f;
		m_useDirection= false;
		m_direction= false;
		m_isVisible= false;
		m_isEditable= false;
		m_color= 0;
		m_registrationId= 0;		
		m_pParentROI= NULL;
	}

	virtual ~CTypeROIContents();

	virtual bool CopyTo ( CTypeAny& dst, bool ) const;
	
private:
	// Normalized coordinates (0..1)
    float m_x, m_y, m_width, m_height;
	bool m_useDirection;
	float m_direction; 	// In radians
	bool m_isVisible;
	bool m_isEditable;
	unsigned int m_color;
	unsigned int m_registrationId;

	// ROI hierarchy
	//typedef std::vector<CTypeROI*> ROICollection;
	typedef std::vector<CTypeAny*> ROICollection;
	ROICollection m_childROIs;
	CTypeROI* m_pParentROI;

	//
	// private methods
	//
	// Find minimum child's P1 coordinates
	void FindMinChildP1 (float& x, float& y) const;
	void FindMinChildP1Rec (float& x, float& y) const;

	// Find miaximum child's P2 coordinates
	void FindMaxChildP2 (float& x, float& y) const;
	void FindMaxChildP2Rec (float& x, float& y) const;

	// Parse command line (see comment on class RoiStorage for details)
	// 
	// Return true if ok, false if error
	bool ParseCommandline (int argc, const char* argv[]);

	//
	// friend access
	//
	friend class WXRoiControls;
	friend class RoiStorage;
};

// Convert from normalized coordinates to real ones given a real size
inline void Norm2Real (unsigned int width, unsigned int height, 
		float in_x, float in_y, int & result_x, int & result_y)
{
	assert (in_x>= 0.0f && in_y>= 0.0f);
	assert (width> 0);
	assert (height> 0);

	result_x= static_cast<int>(in_x * static_cast<float>(width) + 0.5f);
	result_y= static_cast<int>(in_y * static_cast<float>(height) + 0.5f);
}

// Convert from real coordinates to normalized given a real size
inline void Real2Norm (unsigned int width, unsigned int height, 
		int in_x, int in_y, float & result_x, float & result_y)
{
	assert (width> 0);
	assert (height> 0);
	// we expect reasonable values
	assert (in_x< 2000);
	assert (in_y< 2000);
	
	result_x= static_cast<float>(in_x) / static_cast<float>(width);
	result_y= static_cast<float>(in_y) / static_cast<float>(height);
}

}

#endif