
//
// This is example code from Chapter 9.4.2 "Member functions and constructors" of 
// "Programming -- Principles and Practice Using C++" by Bjarne Stroustrup
//

//------------------------------------------------------------------------------

#include <iostream>
using namespace std;

// simple Date:
// guarantee initialization with constructor
// provide some notational convenience
struct Date {
    int y, m, d;                        // year, month, day 
    Date(int y, int m, int d);          // check for valid date and initialize
	Date() { d = m = y = 0; }
    void add_day(int n);                // increase the Date by n days
	bool isValid();
};

//------------------------------------------------------------------------------

Date::Date(int y, int m, int d) : y(y), m(m), d(d) {
	if (!isValid()) {
		y = 0;
		d = 0;
		m = 0;
	}
}

bool isLeapYr(int y) {
	if (y % 400 == 0) return true;
	if (y % 100 == 0) return false;
	if (y % 4 == 0) return true;
	return false;
}

void Date::add_day(int n) {
	if (n == 0) return;   // base case
	if (m == 12 && d == 31) {  // is it New Year's eve?
		++y;
		d = 1;
		m = 1;
		return add_day(n - 1);
	}
	switch (m) {
		case 1:
		case 3:
		case 5:
		case 7:
		case 8:
		case 10:
		case 12: {
			if (d == 31) { // is it the end of the month?
				++m;
				d == 1;
				return add_day(n - 1);
				break;
			}
			++d;
			return add_day(n - 1);
			break;
		}
		case 4:
		case 6:
		case 9:
		case 11: {
			if (d == 30) { // is it the end of the month
				++m;
				d == 1;
				return add_day(n - 1);
				break;
			}
			++d;
			return add_day(n - 1);
			break;
		}
		case 2: // February
			if (isLeapYr(y) && d == 29) {
				++m;
				d = 1;
				return add_day(n - 1);
			}
			if (d = 28) {
				++m;
				d = 1;
				return add_day(n - 1);
			}
			++d;
			return add_day(n - 1);
		default:
			return;
	} // end switch
}

//------------------------------------------------------------------------------



// helper functions:
//------------------------------------------------------------------------------

ostream& operator<<(ostream& os, const Date& d)
{
	return os << '(' << d.y << ',' << d.m << ',' << d.d << ')';
}

// member functions:
//------------------------------------------------------------------------------

bool Date::isValid() {
	switch (m) {
	case 1:
	case 3:
	case 5:
	case 7:
	case 8:
	case 10:
	case 12: {
		if (d > 0 && d < 32) return true;
		return false;
		break;
	}
	case 4:
	case 6:
	case 9:
	case 11: {
		if (d > 0 && d < 31) return true;
		return false;
		break;
	}
	case 2:
		if (isLeapYr(y) && d > 0 && d < 30) {
			return true;
			return false;
		}
		if (isLeapYr(y) && d > 0 && d < 29) {
			return true;
			return false;
		}
	default:
		return false;
	}
}
//------------------------------------------------------------------------------

int main()
{
    Date my_birthday;                 // error: my_birthday not initialized
	cout << "my_birthday = " << my_birthday << '\n';
    Date today(12,24,2007);             // oops! run-time error 
    Date last(2000, 12, 31);            // ok (colloquial style)
    Date christmas = Date(1976,12,24);  // also ok (verbose style)

    //We can now try to use our newly defined variables:
	cout << "last (before increment) = " << last << '\n';
    last.add_day(1);
	cout << "last (after increment) = " << last;
	for (int i = 1; i < 5; ++i) {
		last.add_day(i);
		cout << "last (after increment) = " << last << '\n';

	}
    //add_day(2);                       // error: what day?
	cin.get();
}

//------------------------------------------------------------------------------
