/////////////////////////////////////////////////////////////////////////////
// Name:		valuerange.h
// Purpose:  
// Author:      Cesar Mauri Loba (cesar at crea-si dot com)
// Modified by: 
// Created:     
// Copyright:   (C) 2010 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/>.
/////////////////////////////////////////////////////////////////////////////
#pragma once

#include <assert.h>
#include <math.h>
#include <stdexcept>
#include "../mod_widgets/linear2exp.h"

template <typename T> 
class CValueRange
{
public:
	CValueRange(T value, T min= 0, T max= 0, T defaul= 0) {
		m_min= min;
		m_max= max;
		assert (defaul>= min && defaul<= max);
		if (defaul< min || defaul> max)
			throw std::runtime_error("CValueRange: value out of range");
		m_default= defaul;
		setValue (value);
	}

	void setValue (T val) {
		if (val< m_min || val> m_max) 
			throw std::runtime_error("CValueRange: value out of range");
		m_value= val;
	}

	T getDefault() const { return m_default; }

	T getValue () const { return m_value; }

	T getMin() const { return m_min; }

	T getMax() const { return m_max; }

private:
	T m_value;
	T m_min;
	T m_max;
	T m_default;
};

typedef CValueRange<int> CValueRangeI;
typedef CValueRange<unsigned short> CValueRangeUS;

class CValueRangeFExp : public Linear2ExpMapping
{
public:
	CValueRangeFExp (float min_linear= 0, float min_exp= 0, float max_linear= 1.0f, float max_exp= 1.0f, float default_exp= 0, float grow= 0)
	{
		SetParams (min_linear, min_exp, max_linear, max_exp, default_exp, grow);
		m_expValue= default_exp;
	}

	void SetParams (float min_linear, float min_exp, float max_linear, float max_exp, float default_exp, float grow)
	{
		Linear2ExpMapping::SetParams (min_linear, min_exp, max_linear, max_exp, grow);
		assert (default_exp>= min_exp && default_exp<= max_exp);
		if (!(default_exp>= min_exp && default_exp<= max_exp))
			throw std::out_of_range("CValueRangeFexp: wrong default_exp");
			
		m_maxExp= max_exp;
		m_defaultExp= default_exp;		
	}

	float GetMinLinear () const { return 0.0f; }
	float GetMaxLinear () const { return ToLinear(m_maxExp); }
	float GetDefaultLinear () const { return ToLinear(m_defaultExp); }
	
	float GetMinExp () const { return GetC(); }
	float GetMaxExp () const { return m_maxExp; }
	float GetDefaultExp () const { return m_defaultExp; }

	float GetLinearValue () const { return ToLinear(m_expValue); }

	void SetLinearValue (float lin) {
		assert (lin>= GetMinLinear ());
		assert (lin<= GetMaxLinear ());

		// Only assert these conditions but do not 
		// throw exceptions as it is not dangerous
		m_expValue= ToExp(lin);
	}

	float GetExpValue () const { return m_expValue; }

	void SetExpValue (float expv) {
		assert (expv>= GetMinExp());
		assert (expv<= GetMaxExp ());

		// Raise an exception only if the new value would
		// produce further analytical errors
		if (!(expv>= GetMinExp())) 
			throw std::invalid_argument("CValueRangeFexp: !(expv>= GetMinExp())");
		m_expValue= expv;
	}

private:
	float m_maxExp;
	float m_defaultExp;
	float m_expValue;
};
