#include "Employee.hpp"

/* típus a Worker munka nap státuszának kifejezésére
 *  typepun-olva, hogy könnyeben szérializálható legyen;
 *  bár lenne értelme a Worker-en belül definiálni,
 *  globális, hogy kevésbe legyen fájdalmas használni
 */
typedef enum {
	FULL     = 'F',
	DAY_OFF  = 'X',
	WAS_SICK = 'O',
} workday_t;
/* egy ismerősöm nem rég rámutatott, hogy a "_t" suffix-ot lefoglalja a POSIX,
 *   így ez technikailag árt a portolhatóságnak
 */

class Worker : Employee {
	/* mindösze heti fizetéssel operálunk, az átláthatóságért
	 */
	static const int days = 7;

	int pay_per_day_m;
	/* ledolgozott napok adatai
	 */
	workday_t work_data_m[Worker::days];

	/* work_data_m átalakítása a serializációhoz (mentésnél)
	 */
	std::string work_data_to_string() {
		std::string r("");
		for (int i = 0; i < days; i++) {
			r += (char)work_data_m[i];
		}
		return r;
	}

	/* work_data_to_string() ellentettje
	 */
	int c_string_to_work_data(const char * const s) {
		const int l = strlen(s);
		int r = 0;
		for (int i = 0; i < std::max(l, 7); i++) {
			switch ((workday_t)s[i]) {	// az invalid karakterek ignorálásra kerülnek
				case FULL:    [[ fallthrough ]];
				case DAY_OFF: [[ fallthrough ]];
				case WAS_SICK:
					work_data_m[i] = (workday_t)s[i];
					++r;
					break;
			}
		}
		return r;
	}

	/* munka adatok naptár szerű megjelenítése
	 */
	char * work_table() {
		int magic_number = ((7*2)+2)*2;
		char * r = (char*)malloc(sizeof(char) * magic_number);
		char b[] = "\th k s c p S v\n";
		memcpy(r, b, sizeof(b)-1);
		char * listing_start = r + sizeof(b)-1 + 1;
		listing_start[-1] = '\t';
		memset(listing_start, ' ', 7*2);
		for (int i = 0; i < 7; i++) {
			char &slot = *(listing_start + i * 2);
			slot = (char)work_data_m[i];
		}
		r[magic_number-2] = '\n';
		r[magic_number-1] = '\0';

		return r;
	}

public:
	Worker(std::string name)
		: Employee(name) {
		for (int i = 0; i < Worker::days; i++) {
			work_data_m[i] = FULL;
		}
	}

	Worker(std::string name, int year_of_birth, int pay_per_day, const char * const work_data)
		: Employee(name, year_of_birth), pay_per_day_m(pay_per_day) {
		c_string_to_work_data(work_data);
	}

	Worker(std::string name, int year_of_birth, int pay_per_day, workday_t * work_data)
		: Employee(name, year_of_birth), pay_per_day_m(pay_per_day) {
		for (int i = 0; i < Worker::days; i++) {
			work_data_m[i] = work_data[i];
		}
	}

	bool modify(const std::string &modification) override {
		if (Employee::modify(modification)) { return true; }
		
		auto eq_pos = modification.find("=");
		if (modification.substr(0, eq_pos) == "pay") {
			try {
				pay_per_day_m = std::stoi(modification.substr(eq_pos+1));
				return true;
			} catch (...) {
				return false;
			}
		} else if(modification.substr(0, eq_pos) == "performance") {
			c_string_to_work_data(modification.substr(eq_pos+1).c_str());
		}

		return false;
	}

	int get_cost(){
		/* munka napok öszegzése a nap enum értékétől függően súlyozva
		 */
		return std::accumulate(std::begin(work_data_m), std::end(work_data_m), 0, [this](int sum, int e) {
			int r;
			switch (e) {
				case FULL: {
					r = pay_per_day_m;
				} break;
				case WAS_SICK: {
					r = (int)(DAY_OFF * 0.6);
				} break;
				default: {
					r = 0;
				};
			}
			return sum + r;
		});
	};

	int get_pay(){
		return get_cost();
	};

	void details() {
		common_details();
		printf(
			"%s"
			"\tCalculated pay: %d\n",
			work_table(),
			get_pay()
		);
	};

	std::string serialize() {
		return std::string()
			+ "w;"
			+ Employee::serialize() + ";"
			+ std::to_string(pay_per_day_m) + ";"
			+ work_data_to_string()
			;
	}
};