/*
 *	subtitleeditor -- a tool to create or edit subtitle
 *
 *	https://kitone.github.io/subtitleeditor/
 *	https://github.com/kitone/subtitleeditor/
 *
 *	Copyright @ 2005-2010, kitone
 *
 *	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/>.
 */
 
#include "subtitletime.h"
#include <stdio.h>
#include <stdlib.h>
#include <glib.h>
#include <iostream>
#include <sstream>
#include <iomanip>
#include "utility.h"

/*
 */
SubtitleTime::SubtitleTime()
:totalmsecs(0)
{

}

/*
 */
SubtitleTime::SubtitleTime(const long &total)
:totalmsecs(total)
{
}

/*
 */
SubtitleTime::SubtitleTime(const Glib::ustring &str)
:totalmsecs(0)
{
	try
	{
		int hours, mins, secs, msecs;

		Glib::ustring::size_type pos=0, end=0;

		// hours
		end = str.find(":", pos);
		from_string(str.substr(pos, end), hours);
		pos = end+1;

		if(hours <0)
			hours = -hours;

		// minutes
		end = str.find(":", pos);
		from_string(str.substr(pos, end), mins);
		pos = end+1;

		// seconds
		double ms = 0.0;

		end = str.size();

		from_string(str.substr(pos, end), ms);

		// split into seconds and fraction
		secs = (int)ms;

		msecs = (int)((ms - secs)*1000+0.5);

		set(hours, mins, secs, msecs);

		if(str.find("-") != Glib::ustring::npos)
			totalmsecs = -1 * totalmsecs;
	}
	catch(...)
	{
		g_warning("Could not initialize time from string :'%s'", str.c_str());
	}

}

/*
 */
SubtitleTime::SubtitleTime(const int &h, const int &m, const int &s, const int &ms)
:totalmsecs(0)
{
	set(h,m,s,ms);
}

/*
 */
void SubtitleTime::set(const int &h, const int &m, const int &s, const int &ms)
{
	totalmsecs = h * 3600000 + m * 60000 + s * 1000 + ms;
}

/*
 */
int SubtitleTime::hours() const
{
	return totalmsecs / 3600000;
}

/*
 */
void SubtitleTime::set_hours(int value)
{
	totalmsecs += (value - hours()) * 3600000;
}

/*
 */
int SubtitleTime::minutes() const
{
	return (totalmsecs % 3600000) / 60000;
}

/*
 */
void SubtitleTime::set_minutes(int value)
{
	totalmsecs += (value - minutes()) * 60000; 
}

/*
 */
int SubtitleTime::seconds() const
{
	return (totalmsecs % 60000) / 1000;
}

/*
 */
void SubtitleTime::set_seconds(int value)
{
	totalmsecs += (value - seconds()) * 1000;
}

/*
 */
int SubtitleTime::mseconds() const
{
	return totalmsecs % 1000;
}

/*
 */
void SubtitleTime::set_mseconds(int value)
{
	totalmsecs += value - mseconds();
}

/*
 */
SubtitleTime SubtitleTime::operator-(const SubtitleTime &b) const
{
	long total = totalmsecs - b.totalmsecs;
	return SubtitleTime(total);
}

/*
 */
SubtitleTime SubtitleTime::operator+(const SubtitleTime &b) const
{
	long total = totalmsecs + b.totalmsecs;
	return SubtitleTime(total);
}

/*
 */
double SubtitleTime::operator/(const SubtitleTime &b) const
{
	double total = totalmsecs / b.totalmsecs;
	return total;
}

/*
 */
SubtitleTime SubtitleTime::operator/(const double &div) const
{
	double total = static_cast<double>(totalmsecs) / div;
	return SubtitleTime(static_cast<long>(total));
}

/*
 */
SubtitleTime SubtitleTime::operator/(const long &div) const
{
	double total = static_cast<double>(totalmsecs) / static_cast<double>(div);
	return SubtitleTime(static_cast<long>(total));
}

/*
 */
SubtitleTime SubtitleTime::operator*(const double &mult) const
{
	double total = (double)(totalmsecs * mult);
	return SubtitleTime((long int)total);
}

/*
 */
bool SubtitleTime::operator>(const SubtitleTime &time) const
{
	return totalmsecs > time.totalmsecs;
}

/*
 */
bool SubtitleTime::operator==(const SubtitleTime &time) const
{
	return totalmsecs == time.totalmsecs;
}

/*
 */
bool SubtitleTime::operator!=(const SubtitleTime &time) const
{
	return totalmsecs != time.totalmsecs;
}

/*
 */
bool SubtitleTime::operator>=(const SubtitleTime &time) const
{
	return totalmsecs >= time.totalmsecs;
}

/*
 */
bool SubtitleTime::operator<(const SubtitleTime &time) const
{
	return totalmsecs < time.totalmsecs;
}

/*
 */
bool SubtitleTime::operator<=(const SubtitleTime &time) const
{
	return totalmsecs <= time.totalmsecs;
}

/*
 */
Glib::ustring SubtitleTime::str() const
{
	std::string sign;
	long t = totalmsecs;

	if(t < 0)
	{
		sign = "-";
		t = -t;
	}

	int hours = t / 3600000;
	int minutes = (t % 3600000) / 60000;
	int seconds = (t % 60000) / 1000;
	int mseconds = t % 1000;
	
	gchar *tmp = g_strdup_printf("%s%01d:%02d:%02d.%03d", sign.c_str(), hours, minutes, seconds, mseconds);

	std::string str(tmp);

	g_free(tmp);

	return str;
}

/*
 */
long getMSecs(const SubtitleTime &time)
{
	return 3600000 * time.hours() + 60000 * time.minutes() + 1000 * time.seconds() + time.mseconds();
}

/*
 * Check if the string has the good format 'H:MM:SS.MS'
 */
bool SubtitleTime::validate(const Glib::ustring &str)
{
	int h,m,s,ms;

	if(sscanf(str.c_str(), "%d:%d:%d.%d", &h, &m, &s, &ms) == 4)
		return true;
	return false;
}

/*
 * Return "0:00:00.000"
 */
Glib::ustring SubtitleTime::null()
{
	return "0:00:00.000";
}

/*
 * Convert the time to a frame using a framerate
 * e.g (450, 23.976)
 */
SubtitleTime SubtitleTime::frame_to_time(const long int& frame, const float& framerate)
{
	// secs = frame / framerate
	// msecs = secs * 1000

	return SubtitleTime((long)((frame / framerate) * 1000));
}

/*
 * Convert the frame to the time using a framerate
 */
long int SubtitleTime::time_to_frame(const SubtitleTime& time, const float& framerate)
{
	return (long int)round((time.totalmsecs * framerate) / 1000);
}
