#include <iostream>
#include <iostream>
#include <iomanip>
#include <ctime>
#include <atomic>
#include <mutex>

 // Eager-Initialization, Thread Safe - double check locking with atomic type

class current_date_time {

private:
 //private constuctor and lock variable
    current_date_time() {};
    static std::mutex m_;

public:
    //creates global instance on call - saves memory if instance is memory intense
    static std::atomic<current_date_time*>& create_instance();
    //responsible for assignment of single class object with lock variable
    static current_date_time*& initialize_instance(current_date_time*& global_time_variable);

    void time_output(){
        std::time_t t = std::time(nullptr);
        std::tm tm = *std::localtime(&t);
        std::cout << std::put_time(&tm, "%c %Z") << "\n";
    }

};


std::mutex current_date_time::m_;

std::atomic<current_date_time*>& current_date_time::create_instance(){
    static std::atomic<current_date_time*> global_time_variable = nullptr; //global variable creation
    return global_time_variable;
}



current_date_time*& current_date_time::initialize_instance(current_date_time*& global_time_variable){

    if(global_time_variable == nullptr){  //check to see if the variable is empty
        std::lock_guard<std::mutex> lock(m_);  //acquire lock
        if(global_time_variable == nullptr){  //second check if multiple threads acquire lock
            global_time_variable = new current_date_time(); //only one thread executes this line atomically
        }
    }

    return global_time_variable;
}



int main() {

    current_date_time* eager_initialized_variable = current_date_time::create_instance();
    current_date_time* after_thread_safe_variable = current_date_time::initialize_instance(eager_initialized_variable);
    after_thread_safe_variable->time_output();

    return 0;
}