#ifndef _Duration_h_
#define _Duration_h_

#include <CtrlLib/CtrlLib.h>
using namespace Upp;

class Duration
{
public:
	int hour;
	byte minute;
	byte second;

	Duration(int h = 0, byte m = 0, byte s = 0) { Set(h, m, s); }
	Duration(const Value &v) 					{ *this = v; }
	
	void 	Set(int h, byte m, byte s)			{ hour = h; minute = m; second = s; }
	
	int 	ToInt() const 						{ return hour*3600 + minute*60 + second; }
	void 	FromInt(int d)						{ hour = d/3600; minute = d/60 - hour*60; second = d%60; }
	String 	ToString() const 					{ return Format("%d:%02d:%02d", hour, minute, second); }
	
	operator Value() const						{ return ToInt(); }
	operator int() const						{ return ToInt(); }
	Duration& operator=(const Value &v)			{ ASSERT(v.GetType() == INT_V); FromInt((int)v); return *this; }
	Duration& operator=(int d)					{ FromInt(d); return *this; }
	
	bool operator<(const Duration &d)			{ return ToInt() < d.ToInt(); }
	bool operator>(const Duration &d)			{ return ToInt() > d.ToInt(); }
	bool operator<=(const Duration &d)			{ return ToInt() <= d.ToInt(); }
	bool operator>=(const Duration &d)			{ return ToInt() >= d.ToInt(); }
	bool operator==(const Duration &d)			{ return ToInt() == d.ToInt(); }
	bool operator!=(const Duration &d)			{ return ToInt() != d.ToInt(); }
};

class ConvertDuration : public Convert
{
public:
	ConvertDuration() { minval.Set(0, 0, 0); maxval.Set(INT_MAX/(3600*60), 59, 59); notnull = false; }
	
	virtual Value Format(const Value& q) const;
	virtual Value Scan(const Value& text) const;
	virtual int   Filter(int chr) const;	

	ConvertDuration& MinMax(Time _min, Time _max)      { minval = _min; maxval = _max; return *this; }
	ConvertDuration& NotNull(bool b = true)            { notnull = b; return *this; }
	ConvertDuration& NoNotNull()                       { return NotNull(false); }
	Duration         GetMin() const                    { return minval; }
	Duration         GetMax() const                    { return maxval; }
	bool         	 IsNotNull() const                 { return notnull; }
	
protected:
	Value DurScan(const String& text) const;

	Duration minval, maxval;
	bool notnull;	
};

Value ConvertDuration::DurScan(const String& text) const
{
	String s = (String)text;
	Duration tm;
	try {
		CParser p(s);
		if(p.IsEof())
			return tm;
		int q = p.ReadInt();
		if(q < 0)
			throw CParser::Error("");
		tm.hour = q;
		if(p.IsEof())
			return tm;
		p.PassChar(':');
		q = p.ReadInt();
		if(q < 0 || q > 59)
			throw CParser::Error("");
		tm.minute = q;
		if(p.IsEof())
			return tm;
		p.PassChar(':');
		q = p.ReadInt();
		if(q < 0 || q > 59)
			throw CParser::Error("");
		tm.second = q;
		if(p.IsEof())
			return tm;
	}
	catch(CParser::Error) { }
	return ErrorValue(t_("Not a valid duration, must be in the format XXX:XX:XX:XX. Maximum no. of hours: 255"));	
}

Value ConvertDuration::Format(const Value& q) const
{
	Duration d = (Duration)q;
	return AsString(d);
}

Value ConvertDuration::Scan(const Value& text) const
{
	Value v = DurScan(text);
	if(IsError(v)) return v;
	if(IsNull(v)) return notnull ? NotNullError() : v;
	Duration d = v;
	if(d >= minval && d <= maxval) return v;
	return ErrorValue(t_("Duration must be between ") + AsString(minval) + t_("range\v and ") + AsString(maxval) + ".");
}

int ConvertDuration::Filter(int chr) const
{
	if(IsDigit(chr) || chr == ' ' || chr == '.' || chr == ':')
		return chr;
	if(chr == ',')
		return '.';
	return 0;
}
typedef EditMinMax<Duration, ConvertDuration> EditDur;

#endif
