#include <imgui.h>
#include <imgui_internal.h>
#include <time.h>
#include <stdio.h>
#include <stdint.h>
#include <hydrogen.h>

#include "localization.h"

#include "inter.h"
#include "inter-bold.h"
#include "font-awesome-solid.h"
#include "licenses.cpp"

extern bool should_exit;
extern bool show_demo_window;

//standard year
static int year;

static int current_year;
static int current_month;
static int current_day;

//fonts
static ImFont *inter_regular;
static ImFont *inter_bold;
static ImFont *font_awesome;

char *open_file_dialog();
char *save_file_dialog();
void set_window_title(const char *title);

int get_current_year(){
    time_t t = time(NULL);           
    struct tm tm = *localtime(&t);   

    current_year  = tm.tm_year + 1900;
    current_month = tm.tm_mon + 1;
    current_day   = tm.tm_mday;
     
    // tm_year is years since 1900
    return year = current_year;
} 

bool is_leap_year(int year) {
    return  ((year % 4) == 0 && (year % 100) != 0) || year % 400 == 0;
}

int weekday_from_day(int year, int month, int day) {
    int a = (14 - month) / 12;
    int y = year - a;
    int m = month + (12 * a) - 2;
    return (day + y + (y / 4) - (y / 100) + (y / 400) + ((31 * m) / 12) - 1) % 7;
}

int calendar_week_from_day(int year, int month, int day){
    int days_sum[] = {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334};
    int days = days_sum[month - 1];
    if (is_leap_year(year) && month > 2)
        days++;
    
    return (10 + days + day - weekday_from_day(year, month, day)) / 7;
}

int days_per_month(int year, int month){
    int days_in_month[] = { 31,28,31,30,31,30,31,31,30,31,30,31 };
    if (month == 2) {
        return is_leap_year(year) ? 29 : 28;
    }
    return days_in_month[month - 1];
}

#define HYDROGEN_CONTEXT "WorkCalS"
#define HYDROGEN_OPSLIMIT 10000
#define HYDROGEN_MEMLIMIT 0
#define HYDROGEN_THREADS  1
static uint8_t master_key[hydro_pwhash_MASTERKEYBYTES] = { 0x6c, 0x2e, 0xed, 0x47, 0x36, 0x29, 0xda, 0x11, 0x6e, 0xf4, 0x41, 0x66, 0x3b, 0xd7, 0xfa, 0x72, 0xf7, 0x51, 0x48, 0x6d, 0x10, 0x7b, 0xa5, 0x04, 0x00, 0x11, 0x2e, 0xc4, 0xf2, 0xdb, 0x77, 0x51 };
static uint8_t derived_key[hydro_secretbox_KEYBYTES];

static char password_input_buffer[256];
static char password_confirmation_input_buffer[256];

static Language current_language = L_GERMAN; 
static Language selected_language = L_GERMAN;

const char *get_localized_string(Localized_String localized_string) {
    if(localized_strings_storage[current_language][localized_string]) {
        return localized_strings_storage[current_language][localized_string];
    }

    return localized_strings_storage[L_ENGLISH][localized_string];
}

static Localized_String month_names[] = { LS_JANUARY, LS_FEBRUARY, LS_MARCH, LS_APRIL, LS_MAY, LS_JUNE, LS_JULY, LS_AUGUST, LS_SEPTEMBER, LS_OCTOBER, LS_NOVEMBER, LS_DECEMBER };

static char *save_file_path = NULL;
static const char *wiki_url = "https://gitea.ammerhai.com/Ammerhai/work-calendar/wiki";

static ImGuiID close_popup;
static ImGuiID close_calendar_popup;
static ImGuiID close_and_load_calendar_popup;
static ImGuiID save_password_popup;
static ImGuiID open_password_popup;
static ImGuiID about_popup;
static ImGuiID load_error_popup;

void init() {
    hydro_init();
    ImGuiIO &io = ImGui::GetIO();
    inter_regular = io.Fonts->AddFontFromMemoryCompressedTTF(inter_compressed_data, inter_compressed_size);
    inter_bold    = io.Fonts->AddFontFromMemoryCompressedTTF(inter_bold_compressed_data, inter_bold_compressed_size);
    font_awesome  = io.Fonts->AddFontFromMemoryCompressedTTF(font_awesome_solid_compressed_data, font_awesome_solid_compressed_size, 16.0f);

    year = get_current_year();
    save_file_path = (char *)calloc(1, 1);

    ImGuiSettingsHandler settings_handler = {};
    settings_handler.TypeName = "Calendar";
    settings_handler.TypeHash = ImHashStr("Calendar");
    settings_handler.ReadOpenFn = [](ImGuiContext *context, ImGuiSettingsHandler *handler, const char *name) -> void * {
        return (void *)-1;
    };
    settings_handler.ReadLineFn = [](ImGuiContext *context, ImGuiSettingsHandler *handler, void *entry, const char *line) {
        if (strncmp(line, "language", sizeof("language") - 1) == 0) {
            for (int i = 0; i < LANGUAGE_COUNT; i++) {
                if (strncmp(line + sizeof("language"), localized_strings_storage[i][LS_LANGUAGE_NAME], strlen(localized_strings_storage[i][LS_LANGUAGE_NAME])) == 0)
                    selected_language = (Language)i;
            }
        }
    };
    settings_handler.WriteAllFn = [](ImGuiContext *context, ImGuiSettingsHandler *handler, ImGuiTextBuffer *buffer) {
        buffer->append("[Calendar][Settings]\n");
        buffer->appendf("language=%s\n\n", get_localized_string(LS_LANGUAGE_NAME));
    };
    ImGui::AddSettingsHandler(&settings_handler);
}

typedef struct Category {
    bool editing;
    ImColor color;
    char name[64] = "New Category";
} Category;

static uint32_t num_categories = 0;
static Category categories[128];

static bool legend_visible = true;
static int selected_category = -1;

typedef struct Categorized_Day {
    int year;
    int month;
    int day;
    
    int category;
} Categorized_Day;

static int year_min_size = 1;
static uint32_t num_categorized_days = 0;
static Categorized_Day categorized_days[365*50];

//Colors
static ImVec4 table_white_bg = ImVec4(1.0f, 1.0f, 1.0f, 1.0f);
static ImVec4 table_saturday_bg = ImVec4(0.0f, 0.0f, 0.0f, 0.1f);
static ImVec4 table_sunday_bg = ImVec4(0.0f, 0.0f, 0.0f, 0.2f);

static ImVec4 table_hover_color = ImVec4(0.0f, 0.3f, 0.6f, 0.2f);
    
static char plaintext_buffer[2 * 1024 * 1024] = {};
static char encrypted_buffer[hydro_secretbox_HEADERBYTES + sizeof(plaintext_buffer)];

static bool unsaved_changes;
static bool last_frame_unsaved_changes;
static char *category_name_before_editing = NULL;

static bool about_open;

void save(){
    if (!save_file_path) return;

    uint32_t version = 1;
    #define write_to_buffer(x) memcpy(plaintext_buffer + offset, &(x), sizeof(x)); offset += sizeof(x);

    size_t offset = 0;
    write_to_buffer(version);
    write_to_buffer(num_categories);
    write_to_buffer(num_categorized_days);

    for (int i = 0; i < num_categories; i++) {
        write_to_buffer(categories[i].color);
        write_to_buffer(categories[i].name);
    }

    for (int i = 0; i < num_categorized_days; i++) { 
        write_to_buffer(categorized_days[i].year);
        write_to_buffer(categorized_days[i].month);
        write_to_buffer(categorized_days[i].day);
        write_to_buffer(categorized_days[i].category);
    }
    
    #undef write_to_buffer

    if (hydro_secretbox_encrypt((uint8_t *)encrypted_buffer, plaintext_buffer, offset, 0, HYDROGEN_CONTEXT, derived_key) != 0) {
        return; //TODO error message
    }
    hydro_memzero(plaintext_buffer, sizeof(plaintext_buffer));

    FILE *save_file = fopen(save_file_path, "wb");
    fwrite(encrypted_buffer, hydro_secretbox_HEADERBYTES + offset, 1, save_file);
    fclose (save_file);
    hydro_memzero(encrypted_buffer, sizeof(encrypted_buffer));

    char *title = (char *)calloc(1, strlen("Work Calendar - ") + strlen(save_file_path) + 1);
    memcpy(title, "Work Calendar - ", strlen("Work Calendar - "));
    memcpy(title + strlen("Work Calendar - "), save_file_path, strlen(save_file_path));

    set_window_title(title);
    free(title);

    unsaved_changes = false;
}

void interaction_save_as(){
    char *new_save_file_path = save_file_dialog();
    if (new_save_file_path) {
        if (save_file_path) free(save_file_path);
        save_file_path = new_save_file_path;
        ImGui::OpenPopup(save_password_popup);
    }
}

void load(){
    FILE *save_file = fopen(save_file_path, "rb");
    size_t num_bytes = fread(encrypted_buffer, 1, sizeof(encrypted_buffer), save_file);
    fclose (save_file);

    if (num_bytes <= 0) {
        ImGui::OpenPopup(load_error_popup);
        return;
    }

    if (hydro_secretbox_decrypt(plaintext_buffer, (uint8_t *)encrypted_buffer, num_bytes, 0, HYDROGEN_CONTEXT, derived_key) != 0){
        ImGui::OpenPopup(load_error_popup);
        return;
    }
    hydro_memzero(encrypted_buffer, sizeof(encrypted_buffer));

    #define read_from_buffer(x) memcpy(&(x), plaintext_buffer + offset, sizeof(x)); offset += sizeof(x);
    
    size_t offset = 0;
    uint32_t version = 0;
    read_from_buffer(version);
    if (version != 1) {
        ImGui::OpenPopup(load_error_popup);
        return;
    }

    read_from_buffer(num_categories);
    read_from_buffer(num_categorized_days);

    if (num_categories > IM_ARRAYSIZE(categories) || num_categorized_days > IM_ARRAYSIZE(categorized_days)){
        ImGui::OpenPopup(load_error_popup);
        num_categories = 0;
        num_categorized_days = 0; 
        return;
    }

    for (int i = 0; i < num_categories; i++) {
        read_from_buffer(categories[i].color);
        read_from_buffer(categories[i].name);
    }

    for (int i = 0; i < num_categorized_days; i++) { 
        read_from_buffer(categorized_days[i].year);
        read_from_buffer(categorized_days[i].month);
        read_from_buffer(categorized_days[i].day);
        read_from_buffer(categorized_days[i].category);
    }
    #undef read_from_buffer

    hydro_memzero(plaintext_buffer, sizeof(plaintext_buffer));

    char *title = (char *)calloc(1, strlen("Work Calendar - ") + strlen(save_file_path) + 1);
    memcpy(title, "Work Calendar - ", strlen("Work Calendar - "));
    memcpy(title + strlen("Work Calendar - "), save_file_path, strlen(save_file_path));

    set_window_title(title);
    free(title);

    unsaved_changes = false;
}

void interaction_open(){
    if(unsaved_changes) {
        ImGui::OpenPopup(close_and_load_calendar_popup);
    } else {
        char *new_save_file_path = open_file_dialog();
        if (new_save_file_path) {
            if (save_file_path) free(save_file_path);
            save_file_path = new_save_file_path;
            ImGui::OpenPopup(open_password_popup);
        }
    }
}

void close_calendar(){
    if (save_file_path) free(save_file_path);
    save_file_path = (char *)calloc(1, 1);
    num_categories = 0;
    num_categorized_days = 0;
    hydro_memzero(categories, sizeof(categories));
    hydro_memzero(categorized_days, sizeof(categorized_days));
    hydro_memzero(derived_key, sizeof(derived_key));
    set_window_title("Work Calendar");
    unsaved_changes = false;
}

void interaction_close_calendar() {
    if(unsaved_changes) {
        ImGui::OpenPopup(close_calendar_popup);
    } else {
        close_calendar();
    }
}

void per_frame(){
    current_language = selected_language;

    close_popup                   = ImGui::GetID("###Close");
    close_calendar_popup          = ImGui::GetID("###CloseCalendar");
    close_and_load_calendar_popup = ImGui::GetID("###CloseLoadCalendar");
    save_password_popup           = ImGui::GetID("###Save");
    open_password_popup           = ImGui::GetID("###Open");
    about_popup                   = ImGui::GetID("###About");
    load_error_popup              = ImGui::GetID("###LoadError");

    if (ImGui::IsKeyDown(ImGuiMod_Ctrl) && ImGui::IsKeyPressed(ImGuiKey_S, false)) {
        if (ImGui::IsKeyDown(ImGuiMod_Shift)) {
            interaction_save_as();
        } else if (strlen(save_file_path)) {
            save();
        }
    }

    if (ImGui::IsKeyDown(ImGuiMod_Ctrl) && ImGui::IsKeyPressed(ImGuiKey_O, false)) {
        interaction_open();
    }

    if (ImGui::IsKeyDown(ImGuiMod_Ctrl) && ImGui::IsKeyPressed(ImGuiKey_X, false)) {
        interaction_close_calendar();
    }

    if (last_frame_unsaved_changes != unsaved_changes) {
        char *title = (char *)calloc(1, strlen("Work Calendar - ") + strlen(save_file_path) + 2);
        memcpy(title, "Work Calendar - ", strlen("Work Calendar - "));
        memcpy(title + strlen(title), save_file_path, strlen(save_file_path));
        if(unsaved_changes)
            memcpy(title + strlen(title), "*", 1);

        set_window_title(title);
        free(title);
        
        last_frame_unsaved_changes = unsaved_changes;
    }

    ImGuiStyle &style = ImGui::GetStyle();
    ImVec2 center = ImGui::GetMainViewport()->GetCenter();

    year_min_size = ImGui::CalcTextSize("8888").x + 5;

    ImGuiID main_viewport_dock = ImGui::GetID("main_viewport_dock");
    if (!ImGui::DockBuilderGetNode(main_viewport_dock)) {
        ImGui::DockBuilderAddNode    (main_viewport_dock, ImGuiDockNodeFlags_DockSpace | ImGuiDockNodeFlags_NoTabBar);
        ImGui::DockBuilderSetNodePos (main_viewport_dock, ImGui::GetMainViewport()->WorkPos);
        ImGui::DockBuilderSetNodeSize(main_viewport_dock, ImGui::GetMainViewport()->WorkSize);

        ImGuiID left_dock = 0;
        ImGuiID right_dock = ImGui::DockBuilderSplitNode(main_viewport_dock, ImGuiDir_Right, 0.2f, NULL, &left_dock);
        ImGui::DockBuilderDockWindow("Work Calendar", left_dock);
        ImGui::DockBuilderDockWindow("Legende", right_dock);
        ImGui::DockBuilderFinish(main_viewport_dock);
    }
    ImGui::DockSpaceOverViewport(main_viewport_dock, ImGui::GetMainViewport(), ImGuiDockNodeFlags_NoTabBar);

    if (ImGui::BeginMainMenuBar()) {
        if (ImGui::BeginMenu(get_localized_string(LS_FILE))) {
            if (ImGui::MenuItem(get_localized_string(LS_OPEN), "Ctrl + O")) {
                interaction_open();
            }

            if (ImGui::MenuItem(get_localized_string(LS_SAVE), "Ctrl + S", false, strlen(save_file_path))) {
                save();
            }

            if (ImGui::MenuItem(get_localized_string(LS_SAVE_AS), "Ctrl + Shift + S")) {
                interaction_save_as();
            }

            ImGui::Separator();
            if (ImGui::MenuItem(get_localized_string(LS_CLOSE_CALENDAR), "Ctrl + X")) {
                interaction_close_calendar();
            }

            ImGui::Separator();
            if (ImGui::MenuItem(get_localized_string(LS_EXIT), NULL)) {
                if(unsaved_changes) {
                    ImGui::OpenPopup(close_popup);
                } else {
                    should_exit = true;
                }
            }
            ImGui::EndMenu();
        }

        if (ImGui::BeginMenu(get_localized_string(LS_VIEW))) {
            ImGui::MenuItem(get_localized_string(LS_LEGEND), NULL, &legend_visible);
            if (ImGui::BeginMenu(get_localized_string(LS_LANGUAGE))) {
                for (int language = 0; language < LANGUAGE_COUNT; language++) {
                    if (ImGui::MenuItem(localized_strings_storage[language][LS_LANGUAGE_NAME], NULL, current_language == language))
                        selected_language = (Language) language;
                }
                ImGui::EndMenu();
            }
            ImGui::EndMenu();
        }

        if (ImGui::BeginMenu(get_localized_string(LS_HELP))) {
            ImGui::MenuItem(get_localized_string(LS_DEMO), NULL, &show_demo_window);
            if (ImGui::MenuItem(get_localized_string(LS_WIKI), NULL)) {
                ImGui::GetPlatformIO().Platform_OpenInShellFn(ImGui::GetCurrentContext(), wiki_url);
            }
            ImGui::Separator();
            if (ImGui::MenuItem(get_localized_string(LS_ABOUT), NULL)) {
                ImGui::OpenPopup(about_popup); about_open = true;
            }
            ImGui::EndMenu();
        }

        ImGui::EndMainMenuBar();
    }

    // save calendar file with password modal dialogue 
    ImGui::SetNextWindowPos(center, ImGuiCond_Appearing, ImVec2(0.5f, 0.5f));
    if (ImGui::BeginPopupModal(get_localized_string(LS_TITLE_ENTER_PASSWORD), NULL, ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_AlwaysAutoResize)) {
        ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 1.0f);

        ImGui::AlignTextToFramePadding();
        ImGui::Text("%s", get_localized_string(LS_PASSWORD));
        ImGui::SameLine();
        ImGui::SetNextItemWidth(-1);
        ImGui::InputText("##Password", password_input_buffer, sizeof(password_input_buffer), ImGuiInputTextFlags_Password);

        ImGui::AlignTextToFramePadding();
        ImGui::Text("%s", get_localized_string(LS_CONFIRM_PASSWORD));
        ImGui::SameLine();
        ImGui::SetNextItemWidth(-1);
        ImGui::InputText("##Confirm_Password", password_confirmation_input_buffer, sizeof(password_confirmation_input_buffer), ImGuiInputTextFlags_Password);

        ImGui::PopStyleVar();

        if (ImGui::Button(get_localized_string(LS_OK), ImVec2(120, 0))) { 
            if (hydro_compare((uint8_t *)password_input_buffer, (uint8_t *) password_confirmation_input_buffer, sizeof(password_input_buffer)) == 0) {
                hydro_pwhash_deterministic(derived_key, sizeof derived_key, password_input_buffer, strlen(password_input_buffer), HYDROGEN_CONTEXT, 
                    master_key, HYDROGEN_OPSLIMIT, HYDROGEN_MEMLIMIT, HYDROGEN_THREADS);
                save();
                ImGui::CloseCurrentPopup(); 
                hydro_memzero(password_input_buffer, sizeof(password_input_buffer));
                hydro_memzero(password_confirmation_input_buffer, sizeof(password_confirmation_input_buffer));
            }
            //TODO color input red + message
        }

        ImGui::SameLine();
        if (ImGui::Button(get_localized_string(LS_CANCEL), ImVec2(120, 0))) { 
            ImGui::CloseCurrentPopup(); 
            hydro_memzero(password_input_buffer, sizeof(password_input_buffer));
            hydro_memzero(password_confirmation_input_buffer, sizeof(password_confirmation_input_buffer));
        }
        
        ImGui::EndPopup();
    }

    // open calendar file with password modal dialogue 
    ImGui::SetNextWindowPos(center, ImGuiCond_Appearing, ImVec2(0.5f, 0.5f));
    if (ImGui::BeginPopupModal(get_localized_string(LS_TITLE_OPEN_PASSWORD), NULL, ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_AlwaysAutoResize)) {
        ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 1.0f);

        ImGui::AlignTextToFramePadding();
        ImGui::Text("%s", get_localized_string(LS_PASSWORD));
        ImGui::SameLine();
        ImGui::SetNextItemWidth(-1);
        ImGui::InputText("##Passwort", password_input_buffer, sizeof(password_input_buffer), ImGuiInputTextFlags_Password);

        ImGui::PopStyleVar();

        if (ImGui::Button(get_localized_string(LS_OK), ImVec2(120, 0))) { 
            hydro_pwhash_deterministic(derived_key, sizeof derived_key, password_input_buffer, strlen(password_input_buffer), HYDROGEN_CONTEXT, 
                master_key, HYDROGEN_OPSLIMIT, HYDROGEN_MEMLIMIT, HYDROGEN_THREADS);
            hydro_memzero(password_input_buffer, sizeof(password_input_buffer));

            ImGui::CloseCurrentPopup(); 
            load();
        }

        ImGui::SameLine();
        if (ImGui::Button(get_localized_string(LS_CANCEL), ImVec2(120, 0))) { 
            close_calendar();
            ImGui::CloseCurrentPopup(); 
            hydro_memzero(password_input_buffer, sizeof(password_input_buffer));
        }
        
        ImGui::EndPopup(); 
    }

    // close and load calendar modal dialogue
    ImGui::SetNextWindowPos(center, ImGuiCond_Appearing, ImVec2(0.5f, 0.5f));
    if (ImGui::BeginPopupModal(get_localized_string(LS_CLOSE_AND_LOAD_CALENDAR), NULL, ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_AlwaysAutoResize)) {
        ImGui::Text("%s", get_localized_string(LS_QUESTION_DO_YOU_REALLY_WANT_TO_CLOSE_THE_CALENDAR));

        ImGui::SetItemDefaultFocus();
        if (ImGui::Button(get_localized_string(LS_YES), ImVec2(120, 0))) { 
            ImGui::CloseCurrentPopup(); 
            close_calendar();

            char *new_save_file_path = open_file_dialog();
            if (new_save_file_path) {
                if (save_file_path) free(save_file_path);
                save_file_path = new_save_file_path;
                ImGui::OpenPopup(open_password_popup);
            }
        }

        ImGui::SameLine();
        if (ImGui::Button(get_localized_string(LS_NO), ImVec2(120, 0))) { 
            ImGui::CloseCurrentPopup(); 
        }
        
        ImGui::EndPopup();
    }

    // close calendar modal dialogue
    ImGui::SetNextWindowPos(center, ImGuiCond_Appearing, ImVec2(0.5f, 0.5f));
    if (ImGui::BeginPopupModal(get_localized_string(LS_CLOSE_CALENDAR), NULL, ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_AlwaysAutoResize)) {
        ImGui::Text("%s", get_localized_string(LS_QUESTION_DO_YOU_REALLY_WANT_TO_CLOSE_THE_CALENDAR));

        ImGui::SetItemDefaultFocus();
        if (ImGui::Button(get_localized_string(LS_YES), ImVec2(120, 0))) { 
            close_calendar();
            ImGui::CloseCurrentPopup(); 
        }

        ImGui::SameLine();
        if (ImGui::Button(get_localized_string(LS_NO), ImVec2(120, 0))) { 
            ImGui::CloseCurrentPopup(); 
        }
        
        ImGui::EndPopup();
    }

    // close application modal dialogue
    ImGui::SetNextWindowPos(center, ImGuiCond_Appearing, ImVec2(0.5f, 0.5f));
    if (ImGui::BeginPopupModal(get_localized_string(LS_EXIT), NULL, ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_AlwaysAutoResize)) {
        ImGui::Text("%s", get_localized_string(LS_QUESTION_DO_YOU_REALLY_WANT_TO_QUIT));

        ImGui::SetItemDefaultFocus();
        if (ImGui::Button(get_localized_string(LS_YES), ImVec2(120, 0))) { 
            should_exit = true;
            ImGui::CloseCurrentPopup(); 
        }

        ImGui::SameLine();
        if (ImGui::Button(get_localized_string(LS_NO), ImVec2(120, 0))) { 
            ImGui::CloseCurrentPopup(); 
        }
        
        ImGui::EndPopup();
    }

    // about modal dialogue
    ImGui::SetNextWindowPos(center, ImGuiCond_Appearing, ImVec2(0.5f, 0.5f));
    ImGui::SetNextWindowSize(ImVec2(640.0f, 480.0f), ImGuiCond_Appearing);
    if (ImGui::BeginPopupModal(get_localized_string(LS_ABOUT), &about_open)) {
        ImGui::TextWrapped("%s", licenses);

        ImGui::EndPopup();
    }

    // load error modal dialogue
    ImGui::SetNextWindowPos(center, ImGuiCond_Appearing, ImVec2(0.5f, 0.5f));
    ImGui::SetNextWindowSize(ImVec2(640.0f, 0), ImGuiCond_Appearing);
    if (ImGui::BeginPopupModal(get_localized_string(LS_TITLE_LOAD_ERROR), NULL, ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_AlwaysAutoResize)) {
        ImGui::TextWrapped(get_localized_string(LS_LOAD_ERROR), save_file_path);
        
        if (ImGui::Button(get_localized_string(LS_OK), ImVec2(120, 0))) { 
            free(save_file_path);
            save_file_path = (char *)calloc(1, 1);
            ImGui::CloseCurrentPopup(); 
        }

        ImGui::EndPopup();
    }

    if (ImGui::Begin("Work Calendar", 0)) {
        ImGui::PushStyleColor(ImGuiCol_TableHeaderBg, {0,0,0,0});
        ImGui::PushStyleColor(ImGuiCol_HeaderHovered, {0,0,0,0});
        ImGui::PushStyleColor(ImGuiCol_HeaderActive, {0,0,0,0});

        if (ImGui::BeginTable("CalendarHeader", 5)) {
            
            ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthStretch);    // Left side
            ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthFixed);      // Prev year
            ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthFixed, year_min_size);      // Year
            ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthFixed);      // Next year
            ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthStretch);    // Right side
            
            ImGui::TableNextRow();

            ImGui::TableSetColumnIndex(0);
            ImGui::TableSetColumnIndex(1);
            if (ImGui::ArrowButton("##left", ImGuiDir_Left)) 
                year--;

            ImGui::TableSetColumnIndex(2);
            ImGui::TextAligned(0.5, -FLT_MIN, "%d", year);  

            ImGui::TableSetColumnIndex(3);
            if (ImGui::ArrowButton("##right", ImGuiDir_Right))  
                year++; 
        
            ImGui::TableSetColumnIndex(4);
            ImGui::EndTable();
        }

        for (int month = 1; month <= 12; month++) {
            ImGui::PushID(month);
            ImGui::PushStyleColor(ImGuiCol_TableBorderStrong, {0,0,0,0});
            ImGui::PushStyleColor(ImGuiCol_TableBorderLight, {0,0,0,0});

            if (ImGui::BeginTable("Month", 1, ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_NoHostExtendX)) {
                ImGui::TableNextRow();
                ImGui::TableSetColumnIndex(0);
                ImGui::TextAligned(0.5, -FLT_MIN, get_localized_string(month_names[month - 1]));

                ImGui::TableNextRow();
                ImGui::TableSetColumnIndex(0);

                //calendar week table
                if (ImGui::BeginTable("CalendarWeek", 1, ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_NoHostExtendX | ImGuiTableFlags_Borders)){
                    ImGui::TableNextRow();
                    ImGui::TableSetColumnIndex(0);
                    ImGui::TextAligned(0.5, -FLT_MIN, get_localized_string(LS_CALENDAR_WEEK_SHORT));

                    for (int day = 1; day <= days_per_month(year, month); day++) {
                        int weekday = weekday_from_day(year, month, day);

                        if (weekday == 0 || day == 1){
                            ImGui::TableNextRow();
                            ImGui::TableSetColumnIndex(0);

                            //if first week has 3 or less days, last week from previous year
                            int calendar_week = calendar_week_from_day(year, month, day);
                            if (calendar_week == 0) {
                                ImGui::TextAligned(0.5, -FLT_MIN, "%d", 53);
                            } else {
                                ImGui::TextAligned(0.5, -FLT_MIN, "%d", calendar_week);
                            }
                        }
                    }

                    ImGui::EndTable();
                }
                ImGui::SameLine(0, 0);

                ImGui::BeginGroup();
                ImGui::PushStyleVarY(ImGuiStyleVar_ItemSpacing, 0);

                if (ImGui::BeginTable("Weekdays", 7, ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_NoHostExtendX | ImGuiTableFlags_Borders)){

                    ImGui::TableSetupColumn(get_localized_string(LS_MONDAY_SHORT));
                    ImGui::TableSetupColumn(get_localized_string(LS_TUESDAY_SHORT));
                    ImGui::TableSetupColumn(get_localized_string(LS_WEDNESDAY_SHORT));
                    ImGui::TableSetupColumn(get_localized_string(LS_THURSDAY_SHORT));
                    ImGui::TableSetupColumn(get_localized_string(LS_FRIDAY_SHORT));
                    ImGui::TableSetupColumn(get_localized_string(LS_SATURDAY_SHORT));
                    ImGui::TableSetupColumn(get_localized_string(LS_SUNDAY_SHORT));
                    ImGui::TableHeadersRow();

                    ImGui::EndTable();
                }
                ImGui::PopStyleColor(2);

                ImGui::PushStyleColor(ImGuiCol_TableBorderStrong, {119/255.0f,119/255.0f,119/255.0f,83/255.0f});
                ImGui::PushStyleColor(ImGuiCol_TableBorderLight, {119/255.0f,119/255.0f,119/255.0f,83/255.0f});

                //days of month table
                if (ImGui::BeginTable("Weekdays", 7, ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_NoHostExtendX | ImGuiTableFlags_Borders)) {
                    int offset = weekday_from_day(year, month, 1);

                    for (int day = 1; day <= days_per_month(year, month); day++) {
                        int weekday = weekday_from_day(year, month, day);

                        if (weekday == 0 || day == 1){
                            ImGui::TableNextRow();
                        }

                        ImGui::TableSetColumnIndex(weekday);
                        ImU32 cell_bg_color_workweek = ImGui::GetColorU32(table_white_bg);
                        ImGui::TableSetBgColor(ImGuiTableBgTarget_CellBg, cell_bg_color_workweek);

                        //weekend coloring
                        if (weekday == 5){
                            ImU32 cell_bg_color_sat = ImGui::GetColorU32(table_saturday_bg);
                            ImGui::TableSetBgColor(ImGuiTableBgTarget_CellBg, cell_bg_color_sat);
                        }

                        if (weekday == 6){
                            ImU32 cell_bg_color_sun = ImGui::GetColorU32(table_sunday_bg);
                            ImGui::TableSetBgColor(ImGuiTableBgTarget_CellBg, cell_bg_color_sun);
                        }

                        //color field with category 
                        for (int i = 0; i < num_categorized_days; i++) {
                            if (categorized_days[i].year  != year)  continue;
                            if (categorized_days[i].month != month) continue;
                            if (categorized_days[i].day   != day)   continue;
                            
                            ImColor color = categories[categorized_days[i].category].color;
                            color.Value.w = 0.5;

                            //sat + sun: add alpha value
                            if (weekday == 5)
                                color.Value.w = color.Value.w  + table_saturday_bg.w;
                            if (weekday == 6)
                                color.Value.w = color.Value.w  + table_sunday_bg.w;

                            ImGui::TableSetBgColor(ImGuiTableBgTarget_CellBg, ImU32(color));
                        }
                        
                        if (current_year == year && current_month == month && current_day == day ) {
                            ImGui::PushFont(inter_bold);
                            ImGui::TextAligned(0.5, -FLT_MIN, "%d", day);
                            ImGui::PopFont();
                        } else {
                            ImGui::TextAligned(0.5, -FLT_MIN, "%d", day);
                        }

                        if (ImGui::IsItemHovered()){
                            if (selected_category != -1) {
                                ImColor hover_color = categories[selected_category].color;
                                hover_color.Value.w = 0.2;
                                ImGui::TableSetBgColor(ImGuiTableBgTarget_CellBg, ImGui::GetColorU32(ImU32(hover_color)));
                            } else {
                                ImGui::TableSetBgColor(ImGuiTableBgTarget_CellBg, ImGui::GetColorU32(table_hover_color));
                            }
                        }

                        //apply selected color to field
                        if (selected_category != -1 && ImGui::IsItemClicked()) {
                            unsaved_changes = true;
                            for (int i = 0; i < num_categorized_days; i++) {
                                if (categorized_days[i].year  != year)  continue;
                                if (categorized_days[i].month != month) continue;
                                if (categorized_days[i].day   != day)   continue;

                                if (categorized_days[i].category == selected_category) {
                                    categorized_days[i] = categorized_days[num_categorized_days-1];
                                    num_categorized_days--;
                                } else {
                                    categorized_days[i] = {
                                        .year = year,
                                        .month = month,
                                        .day = day,

                                        .category = selected_category,
                                    };
                                    num_categorized_days++;
                                }

                                goto color_changed;
                            }

                            categorized_days[num_categorized_days] = {
                                .year = year,
                                .month = month,
                                .day = day,

                                .category = selected_category,
                            };
                            num_categorized_days++;
                        }
                        color_changed:;
                    }

                    ImGui::EndTable();
                }
                ImGui::PopStyleColor(2);
                ImGui::PopStyleVar();
                //weekday header table + days of month table
                ImGui::EndGroup();
                //month table
                ImGui::EndTable();
            }

            if ((month % 4) != 0)
                ImGui::SameLine();

            ImGui::PopID();
        }
        
        ImGui::PopStyleColor(3);
    }
    ImGui::End();
    
    // Legende
    if (legend_visible && ImGui::Begin("Legende", 0)) {
        if (ImGui::BeginTable("Legend", 4, ImGuiTableFlags_SizingStretchProp)) {
            ImGui::TableSetupColumn("Color",  ImGuiTableColumnFlags_WidthFixed);
            ImGui::TableSetupColumn("Name",   ImGuiTableColumnFlags_WidthStretch);
            ImGui::TableSetupColumn("Edit",   ImGuiTableColumnFlags_WidthFixed);
            ImGui::TableSetupColumn("Delete", ImGuiTableColumnFlags_WidthFixed );

            for (size_t i = 0; i < num_categories; i++) {
                auto &category = categories[i];
                ImGui::PushID(i);
                ImGui::TableNextRow();

                ImGui::TableSetColumnIndex(0);
                if (ImGui::Selectable("##Category", selected_category == i, ImGuiSelectableFlags_SpanAllColumns | ImGuiSelectableFlags_AllowOverlap, { 0, style.FramePadding.y * 2 + ImGui::CalcTextSize("M").y })) {
                    selected_category = selected_category == i ? -1 : i;
                }
                ImGui::SameLine();
                ImGui::ColorEdit3(category.name, &category.color.Value.x, ImGuiColorEditFlags_NoLabel | ImGuiColorEditFlags_NoInputs);

                ImGui::TableSetColumnIndex(1);
                if (category.editing) {
                    ImGui::SetNextItemWidth(-1);
                    if (ImGui::InputText("##name", category.name, IM_ARRAYSIZE(category.name), ImGuiInputTextFlags_EnterReturnsTrue)) {
                        if (strcmp(category_name_before_editing, category.name) != 0) {
                            unsaved_changes = true;
                        }
                        free(category_name_before_editing);
                        category.editing = false;
                    }
                } else {
                    ImGui::Text("%s", category.name);
                }

                ImGui::TableSetColumnIndex(2);
                ImGui::PushFont(font_awesome);
                if (ImGui::Button("\uf304")) {
                    if(!category.editing) {
                        category_name_before_editing = _strdup(category.name);
                    } else { 
                        if (strcmp(category_name_before_editing, category.name) != 0) {
                            unsaved_changes = true;
                        }
                        free(category_name_before_editing);
                    }
                    category.editing = !category.editing;
                }
                ImGui::PopFont();

                ImGui::TableSetColumnIndex(3);
                ImGui::PushFont(font_awesome);
                if (ImGui::Button("\uf1f8")) {
                    for (size_t j = 0; j < num_categorized_days; j++) {
                        // Remove categorized days that have the to be deleted category
                        if (categorized_days[j].category == i) {
                            for (size_t k = j; k < num_categorized_days - 1; k++) categorized_days[k] = categorized_days[k + 1];
                            num_categorized_days--;
                            j--;
                        }
                        // Decrement the category index of all categorized days that have an index higher than the one to be removed
                        if (categorized_days[j].category > i) categorized_days[j].category--;
                    }
                    // Remove the category
                    for (size_t j = i; j < num_categories - 1; j++) categories[j] = categories[j + 1];
                    num_categories--;
                    unsaved_changes = true;
                }
                ImGui::PopFont();

                ImGui::PopID();
            }

            ImGui::TableNextRow();
            ImGui::TableSetColumnIndex(0);
            ImGui::PushFont(font_awesome);
            if (ImGui::Button("+")) {
                categories[num_categories] = {};
                num_categories++;
                unsaved_changes = true;
            }
            ImGui::PopFont();

            ImGui::EndTable();
        }
    }
    if (legend_visible)
        ImGui::End();
}

