//------------------------------------------------------------------------------
//	Copyright (C) 2009, 2010 Humboldt-Universitaet zu Berlin
//
//	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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//------------------------------------------------------------------------------

/**
 * @file Iso8601Time.cpp
 * @author Ronald Kluth
 * @date created at 2009/04/03
 * @brief Implementation of class odemx::data::output::Iso8601Time
 * @sa Iso8601Time.h
 * @since 2.1
 */

#include <odemx/data/output/Iso8601Time.h>

#include <cmath>
#include <iomanip>
#include <string>
#include <sstream>
#include <stdexcept>

namespace odemx {
namespace data {
namespace output {

//------------------------------------------------------construction/destruction

Iso8601Time::Iso8601Time( const TimeBase& base, short utcOffsetHour, unsigned short utcOffsetMin )
:	TimeFormat( base )
,	utcOffset_( UtcOffset( utcOffsetHour, utcOffsetMin ) )
{
}

//----------------------------------------------------------time string creation

const std::string Iso8601Time::makeString() const
{
	using namespace std;

	ostringstream stream;
	stream.fill('0');

	stream
	<< setw(4) << year << '-'
	<< setw(2) << month << '-'
	<< setw(2) << day
	<< 'T'
	<< setw(2) << hour << ':'
	<< setw(2) << min;

	// print seconds or milliseconds
	if( base.unit == TimeUnit::milliseconds )
	{
		stream << ':' << setw(6) << fixed << setprecision(3) << sec;
	}
	else
	{
		stream << ':' << setw(2) << fixed << setprecision(0) << sec;
	}

	// print UTC time zone
	if( utcOffset_.hour || utcOffset_.minute )
	{
		stream
		<< ( utcOffset_.hour > 0 ? '+' : '-' )
		<< setw(2) << setprecision(0)
		<< std::abs( static_cast< float >( utcOffset_.hour ) ) << ':'
		<< setw(2) << utcOffset_.minute;
	}
	else
	{
		stream << 'Z'; // represents UTC-0
	}

	return stream.str();
}

//--------------------------------------------------------------------UTC offset

Iso8601Time::UtcOffset::UtcOffset( short h, unsigned short m )
{
	if ( h || m )
	{
		if( h < -12 || h > 14 )
		{
			throw std::out_of_range(
					"TimeZone(): hour value range is -12 through 14" );
		}
		if( ! ( m == 0 || m == 15 || m == 30 || m == 45 ) )
		{
			throw std::out_of_range(
					"TimeZone(): minute requires values 0, 15, 30, or 45" );
		}
	}
	hour = h;
	minute = m;
}

void Iso8601Time::setUtcOffset( short hour, short minute )
{
	utcOffset_ = UtcOffset( hour, minute );
}

const Iso8601Time::UtcOffset& Iso8601Time::getUtcOffset() const
{
	return utcOffset_;
}

} } } // namespace odemx::data::output
