#include <glib.h>
#include <gst/gst.h>
#include <gst/video/video.h>

#include <fstream>

#include "cuda_runtime_api.h"
#include "face_nv_infer_server_manager.hpp"
#include "gstds_example_manager.hpp"
#include "gstnvdsmeta.h"
#include "message_handling.hpp"
#include "nv_ds_logger_manager.hpp"
#include "nv_infer_server_manager.hpp"
#include "nv_message_broker.hpp"
#include "nv_message_converter.hpp"
#include "nv_osd_manager.hpp"
#include "nv_tracker_manager.hpp"
#include "nv_video_convert_manager.hpp"
#include "queue_manager.hpp"
#include "rtsp_streaming_manager.hpp"
#include "sink_manager.hpp"
#include "source_bin.hpp"
#include "streammux_manager.hpp"
#include "tee_manager.hpp"
#include "tiler_manager.hpp"

class PipelineManager {
   private:
    gboolean g_run_forever = FALSE;
    GMainLoop *loop = NULL;
    GstElement *pipeline = NULL;
    GMutex eos_lock;
    StreammuxManager *streammux_manager = new StreammuxManager();
    GstdsExampleManager *gstds_example_manager = new GstdsExampleManager();
    TilerManager *tiler_manager = new TilerManager();
    NvVideoConvertManager *nv_video_convert_manager =
        new NvVideoConvertManager();
    NvOsdManager *nv_osd_manager = new NvOsdManager();
    NvDsLoggerManager *nv_ds_logger_manager = new NvDsLoggerManager();
    SinkManager *sink_manager = new SinkManager();
    MessageHandling *message_handling = new MessageHandling();
    RtspStreamingManager *rtsp_streaming_manager = new RtspStreamingManager();
    NvInferServerManager *nv_infer_server_manager = new NvInferServerManager();
    NvTrackerManager *nv_tracker_manager = new NvTrackerManager();
    FaceNvInferServerManager *face_nv_infer_server_manager =
        new FaceNvInferServerManager();
    NvMessageConverter *nv_messgae_converter_manager = new NvMessageConverter();
    NvMessageBroker *nv_messgae_broker_manager = new NvMessageBroker();
    TeeManager *tee_manager = new TeeManager();
    static double fps_buffer_probe;
    static double fps_probe;
    static double fps_osd;
    std::ofstream csv_fp;

    void set_row_csv_fps(const std::string &, double);

    typedef struct {
        TilerManager *tiler_manager;
    } DataPointer;

   public:
    int current_device = -1;
    struct cudaDeviceProp prop;
    bool dynamic_add_remove;

    QueueManager queue_array[5];
    PipelineManager();
    PipelineManager(int, char **);
    int create_pipeline();
    bool create_pipeline_elements(int, char **);
    bool connect_tee_to_queue();
    bool setup_pipeline();
    bool playing_pipeline(int, char **);
    bool status_playing;
    void set_cuda_device();
    static guint64 frame_count_osd_sink;
    static guint64 frame_count_fps_probe;
    static guint64 frame_count_buffer_probe;
    const gchar *new_mux_str;
    gboolean use_new_mux;
    GstPad *pgie_src_pad = NULL;
    GstPad *sgie_src_pad = NULL;
    static std::chrono::time_point<std::chrono::steady_clock>
        last_time_osd_sink;
    static std::chrono::time_point<std::chrono::steady_clock>
        last_time_fps_probe;
    static std::chrono::time_point<std::chrono::steady_clock>
        last_time_buffer_probe;
    static gboolean event_thread_func(gpointer);
    static gboolean check_pipeline_state(gpointer);
    static GstPadProbeReturn buffer_probe(GstPad *, GstPadProbeInfo *,
                                          gpointer);
    static GstPadProbeReturn probe_fps(GstPad *, GstPadProbeInfo *, gpointer);
    static GstPadProbeReturn osd_sink_pad_buffer_probe(GstPad *,
                                                       GstPadProbeInfo *,
                                                       gpointer);
    void get_fps_buffer_probe();
    void get_fps_probe();
    void get_fps_osd();
    bool check_playing_pipeline();
    ~PipelineManager();
};