#ifndef EXECPLUGIN_H
#define EXECPLUGIN_H

#include <sys/time.h>
#include <pango/pangocairo.h>

#include "area.h"
#include "common.h"
#include "timer.h"

extern bool debug_executors;

// Architecture:
// Panel panel_config contains an array of Execp, each storing all config options and all the state variables.
// Only these run commands.
//
// Tint2 maintains an array of Panels, one for each monitor. Each stores an array of Execp which was initially copied
// from panel_config. Each works as a frontend to the corresponding Execp in panel_config as backend, using the
// backend's config and state variables.

typedef struct ExecpBackend {
    // Config:
    // Command to execute at a specified interval
    char *command;
    // Interval in seconds
    int interval;
    int monitor;
    // 1 if first line of output is an icon path
    gboolean has_icon;
    gboolean cache_icon;
    int icon_w;
    int icon_h;
    gboolean has_user_tooltip;
    char *tooltip;
    gboolean centered;
    gboolean has_font;
    PangoFontDescription *font_desc;
    Color font_color;
    int continuous;
    gboolean has_markup;
    char *lclick_command;
    char *mclick_command;
    char *rclick_command;
    char *uwheel_command;
    char *dwheel_command;
    // paddingxlr = horizontal padding left/right
    // paddingx = horizontal padding between childs
    int paddingxlr, paddingx, paddingy;
    Background *bg;

    // Backend state:
    Timer timer;
    int child_pipe_stdout;
    int child_pipe_stderr;
    pid_t child;

    // Command output buffer
    char *buf_stdout;
    ssize_t buf_stdout_length;
    ssize_t buf_stdout_capacity;
    char *buf_stderr;
    ssize_t buf_stderr_length;
    ssize_t buf_stderr_capacity;

    // Text extracted from the output buffer
    char *text;
    // Icon path extracted from the output buffer
    char *icon_path;
    Imlib_Image icon;
    gchar tooltip_text[512];

    // The time the last command was started
    time_t last_update_start_time;
    // The time the last output was obtained
    time_t last_update_finish_time;
    // The time it took to execute last command
    time_t last_update_duration;

    // List of Execp which are frontends for this backend, one for each panel
    GList *instances;
    GTree *cmd_pids;
} ExecpBackend;

typedef struct ExecpFrontend {
    // Frontend state:
    int iconx;
    int icony;
    int textx;
    int texty;
    int textw;
    int texth;
} ExecpFrontend;

typedef struct Execp {
    Area area;
    // All elements have the backend pointer set. However only backend elements have ownership.
    ExecpBackend *backend;
    // Set only for frontend Execp items.
    ExecpFrontend *frontend;
    bool dummy;
} Execp;

// Called before the config is read and panel_config/panels are created.
// Afterwards, the config parsing code creates the array of Execp in panel_config and populates the configuration fields
// in the backend.
// Probably does nothing.
void default_execp();

// Creates a new Execp item with only the backend field set. The state is NOT initialized. The config is initialized to
// the default values.
// This will be used by the config code to populate its backedn config fields.
Execp *create_execp();

void destroy_execp(void *obj);

// Called after the config is read and panel_config is populated, but before panels are created.
// Initializes the state of the backend items.
// panel_config.panel_items is used to determine which backend items are enabled. The others should be destroyed and
// removed from panel_config.execp_list.
void init_execp();

// Called after each on-screen panel is created, with a pointer to the panel.
// Initializes the state of the frontend items. Also adds a pointer to it in backend->instances.
// At this point the Area has not been added yet to the GUI tree, but it will be added right away.
void init_execp_panel(void *panel);

// Called just before the panels are destroyed. Afterwards, tint2 exits or restarts and reads the config again.
// Releases all frontends and then all the backends.
// The frontend items are not freed by this function, only their members. The items are Areas which are freed in the
// GUI element tree cleanup function (remove_area).
void cleanup_execp();

// Called on draw, obj = pointer to the front-end Execp item.
void draw_execp(void *obj, cairo_t *c);

// Called on resize, obj = pointer to the front-end Execp item.
// Returns 1 if the new size is different than the previous size.
gboolean resize_execp(void *obj);

// Called on mouse click event.
void execp_action(void *obj, int button, int x, int y, Time time);

void execp_cmd_completed(Execp *obj, pid_t pid);

// Called to check if new output from the command can be read.
// No command might be running.
// Returns 1 if the output has been updated and a redraw is needed.
gboolean read_execp(void *obj);

// Called for Execp front elements when the command output has changed.
void execp_update_post_read(Execp *execp);

void execp_default_font_changed();

void handle_execp_events();

#endif // EXECPLUGIN_H
