
#include<iostream>
#include<string>
#include<sstream>
#include"Date.h"

using namespace std;



Date::Date(int m,int d,int y)
{
	day=d;
	month=m;
	year=y;
	checkDate();
}

Date::Date(string s)
{
	size_t position1=s.find_first_of("/");
	s.replace(position1,1," ");
	size_t position2=s.find_last_of("/");
	s.replace(position2,1," ");
	istringstream inputString(s);
	inputString>>month>>day>>year;
	checkDate();


}

void Date::setMonth(int m){
	month=m;
}

void Date::setDay(int d){
	day=d;
}

void Date::setYear(int y){
	year=y;
}

bool Date::invalidMonth(){

	return (month<1||month>12);
}

bool Date::invalidDay(){

	int daysInMonth[13]={0,31,(leapYear(year)?29:28),31,30,31,30,31,31,30,31,30,31};
	return (day<1 || day>daysInMonth[month]);
}
bool Date::invalidYear(){

	return(year<1900);
}

void Date::checkDate(){

	
	int m;
	while(invalidMonth()){
		cout<<"Month must be between 1 and 12, please re-enter month: ";
		cin>>m;
		setMonth(m);
	}

	int y;
	while(invalidYear()){
		cout<<"Year must be at least 1900, please re-enter year: ";
		cin>>y;
		setYear(y);
	}

	int d;
	int daysInMonth[13]={0,31,(leapYear(year)?29:28),31,30,31,30,31,31,30,31,30,31};
	while(invalidDay()){
		cout<<"Day must be between 1 and "<<daysInMonth[month]<<", please re-enter day: ";
		cin>>d;
		setDay(d);
	}
}
int Date::daysSinceStart()const{

	int days=0;
	for(int y=1900;y<year;y++){
		leapYear(y) ? days+=366 : days+=365;
	}

	return days+dayOfTheYear();
}

int Date::dayOfTheYear()const {
	
	int days=0;
	switch (month) {
		case 1:
			days+=day; 
			break;
		case 2:
			days+=day+31;
			break;
		case 3:
			days+=31+(leapYear(year) ? 29 : 28 )+day;
			break;
		case 4:
			days+=31+(leapYear(year) ? 29 : 28 )+31+day;
			break;
		case 5:
			days+=31+(leapYear(year) ? 29 : 28 )+31+30+day;
			break;
		case 6:
			days+=31+(leapYear(year) ? 29 : 28 )+31+30+31+day;
			break;
		case 7:
			days+=31+(leapYear(year) ? 29 : 28 )+31+30+31+30+day;
			break;
		case 8:
			days+=31+(leapYear(year) ? 29 : 28 )+31+30+31+30+31+day;
			break;
		case 9:
			days+=31+(leapYear(year) ? 29 : 28 )+31+30+31+30+31+31+day;
			break;
		case 10:
			days+=31+(leapYear(year) ? 29 : 28 )+31+30+31+30+31+31+30+day;
			break;
		case 11:
			days+=31+(leapYear(year) ? 29 : 28 )+31+30+31+30+31+31+30+31+day;
			break;
		case 12:
			days+=31+(leapYear(year) ? 29 : 28 )+31+30+31+30+31+31+30+31+30+day;
			break;
	}

	return days;
}
	
string Date::dayOfTheWeek()const{
	static string dayOfTheWeek[7]={"Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"};
	return dayOfTheWeek[daysSinceStart()%7];
}

string Date::nameOfMonth()const{
	static string Months[13]={"invalid","January","February","March","April","May","June","July","August","September","October","November","December"};
	return Months[month];
}

void Date::printDate()const{
cout<<month<<"/"<<day<<"/"<<year<<endl;
}

void Date::printVerbose()const{
	cout<<dayOfTheWeek()<<", "<<nameOfMonth()<<" "<<day<<", "<<year<<endl;
}

int Date::getMonth()const{
	return month;
}

int Date::getDay()const{
	return day;
}

int Date::getYear()const{
	return year;
}

Date::~Date()
{
}

Date daysToDate(int d){

	int year;
	int yy=1900;

	while(d>0)
	{
		d-=(leapYear(yy)? 366:365);
		yy++;
	}
	year=yy-1;

	d+=(leapYear(year)?366:365);

	Date date=daysOfYearToDate(d,year);
	return date;
}

Date daysOfYearToDate(int d, int y){

	if( d>(leapYear(y)?366:365))
		return daysToDate(d);

	int da;
	int mo;

	if (d<=31){
		mo=1;
		da=d;}	
	else 
		if (d<=31+(leapYear(y)?29:28)){
			mo=2;
			da=d-31;
	}
	else 
		if(d<=31+(leapYear(y)?29:28)+31){
			mo=3;
			da=d-31-(leapYear(y)?29:28);
		}
	else
		if(d<=31+(leapYear(y)?29:28)+31+30){
			mo=4;
			da=d-(31+(leapYear(y)?29:28)+31);
		}
	else
		if(d<=31+(leapYear(y)?29:28)+31+30+31){
			mo=5;
			da=d-(31+(leapYear(y)?29:28)+31+30);
		}
	else
		if(d<=31+(leapYear(y)?29:28)+31+30+31+30){
			mo=6;
			da=d-(31+(leapYear(y)?29:28)+31+30+31);
		}
	else
		if(d<=31+(leapYear(y)?29:28)+31+30+31+30+31){
			mo=7;
			da=d-(31+(leapYear(y)?29:28)+31+30+31+30);
		}
	else
		if(d<=31+(leapYear(y)?29:28)+31+30+31+30+31+31){
			mo=8;
			da=d-(31+(leapYear(y)?29:28)+31+30+31+30+31);
		}
	else
		if(d<=31+(leapYear(y)?29:28)+31+30+31+30+31+31+30){
			mo=9;
			da=d-(31+(leapYear(y)?29:28)+31+30+31+30+31+31);
		}
	else
		if(d<=31+(leapYear(y)?29:28)+31+30+31+30+31+31+30+31){
			mo=10;
			da=d-(31+(leapYear(y)?29:28)+31+30+31+30+31+31+30);
		}
	else
		if(d<=31+(leapYear(y)?29:28)+31+30+31+30+31+31+30+31+30){
			mo=11;
			da=d-(31+(leapYear(y)?29:28)+31+30+31+30+31+31+30+31);
		}
	else
		if(d<=31+(leapYear(y)?29:28)+31+30+31+30+31+31+30+31+30+31){
			mo=12;
			da=d-(31+(leapYear(y)?29:28)+31+30+31+30+31+31+30+31+30);
		}

	Date date(mo,da,y);
	return date;
}

Date Date::operator ++ () {

	int dd=daysSinceStart();
	*this = daysToDate(++dd);
	return *this;

}

Date Date::operator ++(int){

	Date d=*this;
	int dd=daysSinceStart();
	*this=daysToDate(dd+1);
	return d;
}

Date Date::operator --(){

	int dd=daysSinceStart();
	*this=daysToDate(--dd);
	return *this;
}

Date Date::operator --(int){

	Date d=*this;
	int dd=daysSinceStart();
	*this = daysToDate(--dd);
	return d;
}

Date Date::nextBusDay() {

	int dd=daysSinceStart();

	if ( dd %7==5)
	{ 
		*this = daysToDate(dd+3);
		return *this;
	}
	if (dd % 7==6)
	{
		*this =daysToDate(dd+2);
		return *this;
	}

	return ++*this;
}

Date Date::operator+=(unsigned int d){

	int dd=daysSinceStart();
	*this=daysToDate(dd+d);
	return *this;
}



bool leapYear(int y)
{
	return(y % 4==0 && (y % 100 != 0 || y % 400==0));
}

bool operator == ( const Date &d1, const Date &d2){

	return (d1.daysSinceStart() == d2.daysSinceStart());
}

bool operator != (const Date &d1,const Date &d2){

	return (d1.daysSinceStart()!= d2.daysSinceStart());
}

bool operator > (Date &d1,Date &d2){

	return(d1.daysSinceStart()>d2.daysSinceStart());
}

bool operator <=(const Date &d1,const Date &d2){

	return(d1.daysSinceStart()<=d2.daysSinceStart());
}

bool operator >=(const Date &d1,const Date &d2){

	return(d1.daysSinceStart()>=d2.daysSinceStart());
}

bool operator <(const Date &d1,const Date &d2){

	return(d1.daysSinceStart()<d2.daysSinceStart());
}

Date operator+(const Date &d,const unsigned int &dd){

	int days=d.daysSinceStart()+dd;
	return daysToDate(days);
}


