#include <gtk/gtk.h>
#include <gtk/gtkx.h>
#include <locale.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <libintl.h>
#include <getopt.h>
#include <libintl.h>
#include <vte/vte.h>
#include <sys/types.h>
#include <sys/select.h>
#include <pwd.h>
#include <libublsettings.h> 
#include <libublsettings-gtk3.h> 
#include <libublsettingsui-gtk3.h> 
#ifdef WEBKIT_INCLUDE
    #include <webkit2/webkit2.h>
#endif 
#include "ubl-strings.h"
// #include <polkit/polkit.h>

#define WIKI_LINK "https://wiki.ublinux.ru/software/programs_and_utilities/all/ubl-settings-logging"

#define _(String) gettext(String)

#define glade_path "/com/ublinux/ui/ubl-settings-logging.glade"
#define glade_add_path "/com/ublinux/ui/ubl-settings-logging-add.glade"
#define glade_add_path_path "/com/ublinux/ui/ubl-settings-logging-add-path.glade"
#define glade_inspector_path "/com/ublinux/ui/ubl-settings-logging-inspector.glade"
#define glade_journald_path "/com/ublinux/ui/ubl-settings-logging-journald.glade"
#define glade_logrotate_path "/com/ublinux/ui/ubl-settings-logging-logrotate.glade"
#define glade_logrotate_table_path "/com/ublinux/ui/ubl-settings-logging-logrotate-table.glade"
#define glade_rules_path "/com/ublinux/ui/ubl-settings-logging-rules.glade"
#define glade_filechooser_path "/com/ublinux/ui/ubl-settings-logging-filechooser.glade"
#define glade_terminal_path "/com/ublinux/ui/ubl-settings-logging-terminal.glade"
#define glade_saving_path "/com/ublinux/ui/ubl-settings-logging-saving.glade"
#define banner_path "/com/ublinux/images/ubl-settings-logging-banner.png"
#define CssPath "/com/ublinux/css/ubl-settings-logging.css"
#define config_path yon_char_unite(yon_ubl_user_get_home_directory(),"/.config/",LocaleName,"/",LocaleName,".conf",NULL)
#define journals_list_path "resource:///com/ublinux/csv/journals_list.csv"
#define services_list_path "resource:///com/ublinux/csv/logging_services.csv"
#define icon_path "com.ublinux.ubl-settings-logging"

#define logrotate_config_command "ls /etc/logrotate.d/ |sed -e 's/  */\\n/g'"
#define journald_size_command "journalctl --disk-usage | grep -oE \"[0-9]{1,}.[0-9]{1,}[A-Z]\""
#define logrotate_size_command(paths) yon_debug_output("%s\n",yon_char_unite("du ",paths," |grep -oE '^[0-9]{1,}'",NULL))
#define logrotate_config_path "/etc/logrotate.d/"
#define custom_logs_saving_file_path yon_char_unite(yon_ubl_user_get_home_directory(),"/.config/",LocaleName,"/logwatcher.csv",NULL)

#define read_log_command(command) yon_debug_output("%s\n",yon_char_unite("sed -r \"s/\\x1B\\[([0-9]{1,3}(;[0-9]{1,2};?)?)?[mGK]//g\" ",command,NULL))

#define LocalePath "/usr/share/locale" 
#define LocaleName "ubl-settings-logging"

#define config_get_command(source) yon_char_unite("ubconfig --source ",source," get [logging] LOGROTATE[*] JOURNALD[*]",NULL)
#define config_get_default_command ""

#define config_get_global_only_parameters ""
#define config_get_local_only_parameters ""

#define JOURNALD(key) yon_char_unite("JOURNALD[",key,"]",NULL)
#define JOURNALD_parameter_command(target) yon_char_unite("ubconfig --source system get [logging] JOURNALD[",target,"]",NULL)
#define LOGROTATE(key) yon_char_unite("LOGROTATE[",key,"]",NULL)
#define LOGROTATE_parameter_command(target) yon_char_unite("ubconfig --source system get [logging] LOGROTATE[",target,"]",NULL)

#define get_journal_output_command "clear;journalctl --no-pager"
#define get_journal_output_since_boot_command "clear;journalctl --no-pager -b"
#define get_journal_output_followed_command "clear;journalctl --no-pager -f"
#define get_journal_output_kernel_command "clear;journalctl --no-pager -k"
#define get_journal_output_prioritied_command "clear;journalctl --no-pager -p err..alert"
#define get_journal_all_boots_command "clear;journalctl --no-pager --list-boots"
#define get_journal_all_units_command "clear;systemd-analyze blame --no-pager"
#define get_journal_init_tree_command "clear;systemd-analyze critical-chain --no-pager"

#define get_file_folder_size(path) yon_char_append("du -hsc ",path)
#define get_all_files_in_path(path) yon_char_append("find ",path)

#define journald_lower_size_command(new_size) yon_char_append("journalctl --rotate; journalctl --vacuum-size=",new_size)
#define journald_lower_time_command(new_time) yon_char_append("journalctl --rotate; journalctl --vacuum-time=",new_time)

#define group_list_path "/etc/group"

#define edit_icon_name "com.ublinux.libublsettings-ui.edit-symbolic"
#define add_icon_name "com.ublinux.libublsettingsui-gtk3.increase-symbolic"
#define remove_icon_name "com.ublinux.libublsettingsui-gtk3.trash-symbolic"
#define minus_icon_name "com.ublinux.libublsettingsui-gtk3.decrease-symbolic"

#define import_icon_name "com.ublinux.libublsettingsui-gtk3.back-symbolic"
#define settings_icon_name "com.ublinux.libublsettingsui-gtk3.settings-symbolic"
#define start_icon_name "com.ublinux.libublsettingsui-gtk3.play-symbolic"
#define stop_icon_name "com.ublinux.libublsettingsui-gtk3.stop-symbolic"
#define enable_icon_name "com.ublinux.libublsettingsui-gtk3.flag-symbolic"
#define disable_icon_name "com.ublinux.libublsettingsui-gtk3.flag-empy-symbolic"

#define check_command_is_legit(command) !system(yon_char_unite("bash -c \"set -u; command -v ",command,"\"",NULL))

#define yon_add_space_if_exists(string) yon_char_is_empty(string) ? "" : yon_char_append(",",string)
typedef char* string;
string version_application;

char *local;

typedef struct {
    GSourceFunc func;
    void *data;
} queue_func;

typedef struct {
    template_config_fields
    config_str launch_arguments;
    int launch_size;
    char **envp;

    int save_config;
    
    GtkListStore *logrotate_list;
    GtkListStore *logrotate_apps_list;

    config_str groups;
    int groups_size;

    config_str *saved_logs;

    GPermission *permissions;

    pthread_t inspector_thread;
    int remove_thread;
    // PolkitAuthorizationResult *authorization_result;
    // PolkitSubject *process;

    queue_func** queue;
    int queue_size;

    GMutex authorized_mutex;
} config;

typedef struct {
    //Standard
	template_window_fields

    GtkWidget *MainTree;
    GtkWidget *InspectButton;
    GtkWidget *ConfigureButton;
    GtkWidget *AddButton;
    GtkWidget *RemoveButton;


    GtkWidget *Notebook;
    GtkWidget *ServicesTree;
    GtkWidget *ServicesEditButton;
    GtkWidget *ServicesControlButton;
    GtkListStore *list;
    GtkListStore *ServicesList;
    GtkWidget *UpgradePermissionsMenuItem;
    GtkWidget *PermissionsLock;
    // Custom 
    rmb_menu_window *LogsRMBMenu;
    rmb_menu_window *ServicesRMBMenu;
} main_window;


typedef struct {
    GtkWidget *Window;

    GtkWidget *HatText;
    GtkWidget *HeaderText;
    GtkWidget *InfoText;
    GtkWidget *AlwaysOpenCheck;

    GtkWidget *CloseButton;
    GtkWidget *AcceptButton;
} documentation_confirmation_window;

typedef struct {
    GtkWidget *MainWindow;
    GtkWidget *StatusBox;
    GtkWidget *HeaderLabel;
    GtkWidget *adjustment1;
    GtkWidget *adjustment2;
    GtkWidget *CancelButton;
    GtkWidget *SaveButton;
    GtkWidget *LogTypeCombo;
    GtkWidget *LogDescriptionEntry;
    GtkWidget *editingBox;
    GtkWidget *logSizeLabel;
    GtkWidget *LogrotateButton;
    GtkWidget *MetalogButton;
    GtkWidget *SyslogButton;
    GtkWidget *JournaldButton;
    GtkWidget *LogSizeLabel;
    GtkWidget *StatisticsFrame;
    GtkWidget *ControlSectionBox;
    GtkWidget *LogPathsBox;
    GtkWidget *NameEntry;

    char *log_name;
} add_log_window;

typedef struct {
    GtkWidget *MainWindow;
    GtkWidget *TitleLabel;
    GtkWidget *plugBox;
    GtkWidget *ShowSinceBootButton;
    GtkWidget *NewMessagesButton;
    GtkWidget *ShowKernelButton;
    GtkWidget *ShowPriorityButton;
    GtkWidget *UpdateButton;
    GtkWidget *ShowAllBootsButton;
    GtkWidget *ShowAllUnitsButton;
    GtkWidget *ShowInitTreeButton;
    GtkWidget *LoggingNotebook;
    GtkWidget *JournalActionsBox;
    GtkListStore *list;
    GtkWidget *JournaldTree;
    dictionary *terminals;
    int last_mode;
    char *journal_name;
    int journal_size;
config_str journal_paths;

} inspector_window;

typedef struct {
    GtkWidget *Window;

    GtkWidget *UserReadCheck;
    GtkWidget *UserWriteCheck;
    GtkWidget *UserExecuteCheck;
    GtkWidget *GroupReadCheck;
    GtkWidget *GroupWriteCheck;
    GtkWidget *GroupExecuteCheck;
    GtkWidget *PublicReadCheck;
    GtkWidget *PublicWriteCheck;
    GtkWidget *PublicExecuteCheck;
    GtkWidget *FinalEntry;
    GtkWidget *CancelButton;
    GtkWidget *SaveButton;
} logrotate_rules_window;

typedef struct {
    GtkWidget *FileChooser;
    GtkWidget *FileOrDirCheck;
    GtkWidget *CancelButton;
    GtkWidget *AcceptButton;
    GtkWidget *StatusBox;
} logrotate_filechooser_window;

typedef struct {
    GtkWidget *Window;
    GtkWidget *AppsMainTree;
    GtkWidget *AppsConfigureButton;
    GtkWidget *MainTree;
    GtkWidget *AddButton;
    GtkWidget *RemoveButton;
    GtkWidget *ConfigureButton;
    GtkWidget *CancelButton;
    GtkWidget *SaveButton;
    GtkWidget *StatusBox;
    rmb_menu_window *Menu;
    rmb_menu_window *AppsMenu;
} logrotate_window;

typedef struct {
    GtkWidget *MainWindow;
    GtkWidget *StatusBox;
    GtkWidget *CancelButton;
    GtkWidget *SaveButton;
    GtkWidget *ResetButton;
    GtkWidget *LogNameLabel;
    GtkWidget *LogDescriptionLabel;
    GtkWidget *LogStorageCombo;
    GtkWidget *LogCompressionCombo;
    GtkWidget *LogCompressionEntry;
    GtkWidget *LogCompressionSizeCombo;
    GtkWidget *DivideJournalFilesCombo;
    GtkWidget *LogIntervalCheck;
    GtkWidget *LogIntervalSpin;
    GtkWidget *LogIntervalAmountCheck;
    GtkWidget *LogIntervalAmountSpin;
    GtkWidget *LogSizeMaxCheck;
    GtkWidget *LogSizeMaxSpin;
    GtkWidget *LogSizeMaxCombo;
    GtkWidget *RotationSizeMaxCheck;
    GtkWidget *RotationSizeMaxSpin;
    GtkWidget *RotationSizeMaxCombo;
    GtkWidget *LogFreeSpaceCheck;
    GtkWidget *LogFreeSpaceSpin;
    GtkWidget *LogFreeSpaceCombo;
    GtkWidget *RedirectCombo;
    GtkWidget *RedirectTTYEntry;
    GtkWidget *ForwardedTypeCombo;
    GtkWidget *LogSizeLabel;
    GtkWidget *LowerSizeEntry;
    GtkWidget *LowerSizeCombo;
    GtkWidget *LowerSizeButton;
    GtkWidget *LowerTimeEntry;
    GtkWidget *LowerTimeCombo;
    GtkWidget *LowerTimeButton;
    GtkWidget *headerTopic;

    char *paths;
} journald_window;

typedef struct {
    GtkWidget *MainWindow;
    GtkWidget *StatusBox;

    GtkWidget *CancelButton;
    GtkWidget *SaveButton;
    GtkWidget *LogNameEntry;
    GtkWidget *LogDescriptionEntry;
    GtkWidget *LogPathsTree;
    GtkWidget *LogPathEditButton;
    GtkWidget *LogPathAddButton;
    GtkWidget *LogPathRemoveButton;
    GtkWidget *RotationPeriodCheck;
    GtkWidget *RotationPeriodMainCombo;
    GtkWidget *RotationPeriodAdditionalCombo;
    GtkWidget *JournalMaxSizeCheck;
    GtkWidget *JournalMaxSizeSpin;
    GtkWidget *JournalMaxSizeCombo;
    GtkWidget *FileAmountCheck;
    GtkWidget *FileAmountSpin;
    GtkWidget *FileAmountCombo;
    GtkWidget *FileAmountEntry;
    GtkWidget *FileAmountButton;
    GtkWidget *RotationCheck;
    GtkWidget *RotationAtUserCombo;
    GtkWidget *RotationAtGroupCombo;
    GtkWidget *ErrorProcessingCombo;
    GtkWidget *JournalEmptyCombo;
    GtkWidget *DoNotRotateYoungerCheck;
    GtkWidget *DoNotRotateYoungerSpin;
    GtkWidget *DeleteOlderCheck;
    GtkWidget *DeleteOlderSpin;
    GtkWidget *RotateSizeMaxAfterTimeCheck;
    GtkWidget *RotateSizeMaxAfterTimeSpin;
    GtkWidget *RotateSizeMaxAfterTimeCombo;
    GtkWidget *RotateSizeMaxBeforeTimeCheck;
    GtkWidget *RotateSizeMaxBeforeTimeSpin;
    GtkWidget *RotateSizeMaxBeforeTimeCombo;
    GtkWidget *CreateLogCombo;
    GtkWidget *CreateLogUserCombo;
    GtkWidget *CreateGroupCombo;
    GtkWidget *CreateLogEntry;
    GtkWidget *CreateLogButton;
    GtkWidget *CutCheck;
    GtkWidget *CompressionCombo;
    GtkWidget *QueueCombo;
    GtkWidget *SaveOriginalCombo;
    GtkWidget *SaveOriginalEntry;
    GtkWidget *AddDateCombo;
    GtkWidget *OldNumberCombo;
    GtkWidget *OldNumberEntry;
    GtkWidget *EmailCombo;
    GtkWidget *EmailEntry;
    GtkWidget *EmailContentsCombo;
    GtkWidget *ManualInputEntry;
    GtkWidget *LogSizeLabel;
    GtkWidget *headerTopic;
    GtkListStore *list;
    GtkCellRenderer *PathCell;
    GtkWidget *SharedScenariosCheck;
    GtkWidget *CommandBeforeOnceEntry;
    GtkWidget *CommandAfterOnceEntry;
    GtkWidget *CommandBeforeEntry;
    GtkWidget *CommandAfterEntry;
    GtkWidget *EndworkCommandEntry;
    char *paths;
} logrotate_configure_window;

typedef struct {
    GtkWidget *Window;
    GtkWidget *HeaderTopic;
    GtkWidget *HeaderImage;
    GtkWidget *StatusBox;
    GtkWidget *ParametersTree;
    GtkCellRenderer *ToggleCell;
    GtkWidget *CancelButton;
    GtkWidget *SaveButton;
    GtkListStore *list;
    YON_CONFIG_TYPE type;
} saving_window;

typedef int (*RmbCheck)(void*);

main_window *setup_window();
void on_save_window_parameter_switched(GtkCellRendererToggle *self, gchar *path, saving_window *window);
char *yon_size_get_letter_from_int(int size);
int yon_size_get_int_from_letter(char size);
// void yon_polkit_authorized_action(GCallback *func);
void yon_logs_custom_save(main_window *widgets);
void update_loaded_logrotate();
int yon_load_proceed(YON_CONFIG_TYPE type);
void on_load_global();
void on_load_local();
void on_config_custom_load(GtkWidget *,main_window *widgets);
void on_save_global_local();
void on_save_global();
void on_save_local();
void on_config_custom_save(GtkWidget *, main_window *);
void on_save_done(main_window *widgets, config_str output, int size);
void on_save_failed(main_window *, config_str , int );
void on_inspector_jornald_read_async(inspector_window *window);
void on_inspector_update(GtkWidget *self, inspector_window *window);
GtkWidget *yon_inspector_add_terminal(inspector_window *window,char *page_name,int mode);
void on_inspector_close(GtkWidget *self, inspector_window *window);
void on_inspector_open(GtkWidget *self, main_window *widgets);
void on_logrotate_configuration_path_filechooser_selection_changed(GtkWidget *self, logrotate_filechooser_window *dialog);
void on_logrotate_filechooser_file_dir_toggled(GtkWidget *self, logrotate_filechooser_window *dialog);
void on_logrotate_configuration_path_filechooser_save_edit(GtkWidget *self, dictionary *dict);
void on_logrotate_configuration_path_filechooser_save(GtkWidget *self, dictionary *dict);
void on_logrotate_configuration_path_filechooser_open(GtkWidget *self, logrotate_configure_window *window);
void on_logrotate_configuration_path_add(GtkWidget *self, logrotate_configure_window *window);
void on_path_editing_done(GtkCellRendererText* self,gchar* gtkpath,gchar* new_text,logrotate_configure_window *window);
void on_path_editing_cancel(GtkCellRendererText* self,logrotate_configure_window *window);
void on_logrotate_configuration_path_edit(GtkWidget *self, logrotate_configure_window *window);
void on_logrotate_configuration_path_remove(GtkWidget *self, logrotate_configure_window *window);
void on_combo_activate_first(GtkComboBox *self, GtkWidget *target);
void on_combo_activate_second(GtkComboBox *self, GtkWidget *target);
void on_file_amount_checked(GtkToggleButton *self, logrotate_configure_window *window);
void on_rules_accept(GtkWidget *self, dictionary *dict);
void on_rules_update(GtkWidget *self, logrotate_rules_window *window);
void on_rules_open(GtkWidget *self,GtkEntry *entry);
void on_filechooser_mode_switch(GtkWidget *self, logrotate_filechooser_window *window);
void on_filechooser_save(GtkWidget *self, dictionary *dict);
void on_filechooser_open(GtkWidget *self, logrotate_configure_window *window);
void on_logrotate_period_check_toggled(GtkToggleButton *self,logrotate_configure_window *window);
void on_logrotate_paths_cursor_changed(GtkWidget *self, logrotate_configure_window *window);
int on_logrotate_check_repeats(GtkWidget *self, logrotate_configure_window *window);
void on_logrotate_save(GtkWidget *self, dictionary *dict);
logrotate_configure_window *yon_logrotate_window_new(char *paths, logrotate_window *dialog, char *log_name);
void on_logrotate_add(GtkWidget *self, logrotate_window *dialog);
void on_logrotate_edit(GtkWidget *self, logrotate_window *window);
void on_logrotate_remove(GtkWidget *self, logrotate_window *window);
void on_logrotate_apps_configure(GtkWidget *self, logrotate_window *window);
void on_log_edit_logrotate_settings(GtkWidget *self, dictionary *dict);
void on_logrotate_tab_selection_changed(GtkWidget *self, logrotate_window *window);
void on_logrotate_applications_tab_selection_changed(GtkWidget *self, logrotate_window *window);
void on_logrotate_tab_open(GtkWidget *self, main_window *widgets);
void yon_combo_compress_check(GtkComboBox *self, journald_window *window);
void on_journald_reset(GtkWidget *self, journald_window *window);
void on_journald_save(GtkWidget *self, journald_window *window);
void on_journald_size_lower_size(GtkWidget *, journald_window *window);
void on_journald_size_lower_time(GtkWidget *, journald_window *window);
journald_window *yon_journald_open(GtkWidget *self, main_window *widgets);
void on_journald_open(GtkWidget *self, main_window *widgets);
void on_log_save(GtkWidget *self, dictionary *dict);
add_log_window *on_add_open(main_window *widgets);
void on_log_path_remove(GtkWidget *self, add_log_window *window);
void on_log_path_filechooser_selection_changed(GtkWidget *self, logrotate_filechooser_window *dialog);
void on_log_path_filechooser_toggled(GtkWidget *self, logrotate_filechooser_window *dialog);
void on_log_path_filechooser_save(GtkWidget *self, dictionary *dict);
void on_log_path_filechooser_open(GtkWidget *self, GtkEntry *entry);
void on_log_path_choose(GtkWidget *self,add_log_window *window);
void on_log_path_append(GtkWidget *self, add_log_window *window);
void on_log_add(GtkWidget *self, main_window *widgets);
void on_log_edit(GtkWidget *self,main_window *widgets);
void on_log_remove(GtkWidget *self, main_window *widgets);
void on_service_edit(GtkWidget *self,main_window *widgets);
void on_main_window_tree_selection_changed(GtkWidget *self,main_window *widgets);
void on_main_window_services_tree_selection_changed(GtkWidget *self,main_window *widgets);
void on_start_stop_clicked(GtkButton *self, main_window *widgets);
void on_enable_disable_clicked(GtkButton *self, main_window *widgets);
void on_permissions_changed();
void config_init();
void yon_main_window_complete(template_main_window **window);
void on_logrotate_apps_configure_activate(GtkWidget *, GtkTreePath*, GtkTreeViewColumn*,logrotate_window *window);
void on_logrotate_edit_activate(GtkWidget*,GtkTreePath*,GtkTreeViewColumn*, logrotate_window *window);
void on_logrotate_closed(GtkWidget *,logrotate_window *window);
void on_rules_changed(GtkEditable *editable, const gchar *text, gint length, gint *position);
void on_service_manage(GtkWidget *,main_window *widgets);
void yon_journald_size_update(journald_window *window);
int main(int argc, char *argv[]);