#include <iostream>
#include <ctime>

// file: sleep.h
void sleep_milli(unsigned milliseconds);

// file: sleep.cpp
#ifdef _WIN32
    #include <windows.h>

    void sleep_milli(unsigned milliseconds)
    {
        Sleep(milliseconds);
    }
#else
    #include <unistd.h>

    void sleep_milli(unsigned milliseconds)
    {
        usleep(milliseconds * 1000);
    }
#endif

// file: task.h
class Task
{
	public:
		virtual void Execute() = 0;
};

// file: factorialtask.h
class FactorialTask : public Task
{
	public:
		FactorialTask(unsigned int n) : _n(n) { }
		void Execute();
		
	private:
		unsigned int _n;
};

// file: fibonaccitask.h
class FibonacciTask : public Task
{
	public:
		FibonacciTask(unsigned int n) : _n(n) { }
		void Execute();
		
	private:
		unsigned int _n;
};

// file: loggingtask.h
template <class T>
class LoggingTask : public T
{
	public:
		LoggingTask(unsigned int n) : T(n) { }
		void Execute();
};

template <class T>
void LoggingTask<T>::Execute()
{
	time_t now;
	struct tm *current;
	
	now = time(0);
	current = localtime(&now);
	std::cout << "[" << current->tm_hour << ":" << current->tm_min << ":" << current->tm_sec << "] Logging started" << std::endl;
	
	T::Execute();
	
	now = time(0);
	current = localtime(&now);
	std::cout << "[" << current->tm_hour << ":" << current->tm_min << ":" << current->tm_sec << "] Logging ended" << std::endl;
}

using namespace std;

// file: factorialtask.cpp
void FactorialTask::Execute()
{
	unsigned int result = 1;
	for(int i = 1; i <= _n; ++i)
	{
		result *= i;
		sleep_milli(100);
	}
	cout << _n  << "!= " << result << endl;
}

// file: fibonaccitask.cpp
void FibonacciTask::Execute()
{
	unsigned int a = 1, b = 1;
	for(int i = 3; i <= _n; ++i)
	{
		b = a + b;
		a = b - a;
		sleep_milli(100);
	}
	cout << "Fibonacci(" << _n << ") = " << b << endl;
}

// file: main.cpp
int main()
{
	FactorialTask facTask(20);
	facTask.Execute();
	
	FibonacciTask fibTask(20);
	fibTask.Execute();
	
	LoggingTask<FactorialTask> logFacTask(20);
	logFacTask.Execute();
	
	LoggingTask<FibonacciTask> logFibTask(20);
	logFibTask.Execute();
	
	return 0;
}
