#ifndef MOC_EDITOR_H
#define MOC_EDITOR_H

#include <QWidget>
#include <QtWidgets>
#include <QStandardItemModel>
#include "disp_qt.h"
#include "moc_config.h"
#include "mpxplay.h"
#include "playlist/playlist.h"

QT_BEGIN_NAMESPACE
class MainWindow;
class PlaylistEditorTable;
class EditorDriveline;
QT_END_NAMESPACE

#ifndef MPXPLAY_WIN32
#define DISPQT_DRIVELINE_USE_QTDRIVES 1
#endif

#define DISPQT_EDITOR_MERGE_ARTISTTITLE 1 // do not disable yet
#define DISPQT_EDITOR_TABLE_COL_MAX 4

#define DISPQT_TABLE_LINES_HEIGHT 16
#define DISPQT_MENU_LINES_HEIGHT  20

#define DISPQT_MOUSE_WHEEL_MOVE_ROWS_VSCROLLBAR 10
#define DISPQT_MOUSE_WHEEL_MOVE_ROWS_TABLE       3

#define DISPQT_FLAG_MOUSE_BTN_LEFT_PRESSED   (1 << 0)
#define DISPQT_FLAG_MOUSE_BTN_RIGHT_PRESSED  (1 << 1)
#define DISPQT_FLAG_MOUSE_BTN_MIDDLE_PRESSED (1 << 2)
#define DISPQT_FLAG_MOUSE_BTN_ALL            (DISPQT_FLAG_MOUSE_BTN_LEFT_PRESSED | DISPQT_FLAG_MOUSE_BTN_RIGHT_PRESSED | DISPQT_FLAG_MOUSE_BTN_MIDDLE_PRESSED)

#define DISPQT_FLAG_KEYMOD_ALT     (1 << 4)
#define DISPQT_FLAG_KEYMOD_CTRL    (1 << 5)
#define DISPQT_FLAG_KEYMOD_SHIFT   (1 << 6)
#define DISPQT_FLAG_KEYMOD_ALL     (DISPQT_FLAG_KEYMOD_ALT | DISPQT_FLAG_KEYMOD_CTRL | DISPQT_FLAG_KEYMOD_SHIFT)

// custom (editor) flags shall begin at bit 16.
#define DISPQT_FLAGS_CUSTOM_MASK (~((1 << 16) - 1))

#define DISPQT_QT_SORTORDER_ASCENDING  Qt::AscendingOrder
#define DISPQT_QT_SORTORDER_DESCENDING Qt::DescendingOrder

#define DISPQT_CONFIG_DESKTOPMODE_FULLREDRAW (DTM_EDIT_VERTICAL)
#define DISPQT_CONFIG_EDITORFLAGS_FULLREDRAW (DISPQT_CONFIG_EDITORFLAG_SHOWPANELS_ALL | DISPQT_CONFIG_EDITORFLAG_SHOW_DRIVELINE \
				| DISPQT_CONFIG_EDITORFLAG_COLUMNS_MANUALSIZE | DISPQT_CONFIG_EDITORFLAG_DISABLE_SCROLLBAR)
#define DISPQT_CONFIG_EDITORFLAGS_COLORCFG (DISPQT_CONFIG_EDITORFLAG_TRANSLUCENT_INWINDOW | DISPQT_CONFIG_EDITORFLAG_TRANSLUCENT_ONVIDEO | DISPQT_CONFIG_EDITORFLAG_TRANSPARENT_BACK)

struct dispqt_editor_lineselect_request_s {
	unsigned long flags;
	unsigned int sidenum;
	unsigned int tabnum;
	int linenum;
};

#define DISPQT_EDITOR_FLAG_SETFOCUS       (1 << 16)
#define DISPQT_EDITOR_FLAG_SETSIDE        (1 << 17)
#define DISPQT_EDITOR_FLAG_ABSOLUTEPOS    (1 << 18)
#define DISPQT_EDITOR_FLAG_NOCENTER       (1 << 19)
#define DISPQT_EDITOR_FLAG_DOUBLECLICK    (1 << 20)
#define DISPQT_EDITOR_FLAG_MOVESIDE       (1 << 21)
#define DISPQT_EDITOR_FLAG_SCROLLSIDE     (1 << 22)
#define DISPQT_EDITOR_FLAG_CONTENTREFRESH (1 << 23)

enum {DISPQT_EDITOR_CBCMD_SET_SIDE = 0, DISPQT_EDITOR_CBCMD_TAB_ADD, DISPQT_EDITOR_CBCMD_TAB_DEL, DISPQT_EDITOR_CBCMD_TAB_LOCK, DISPQT_EDITOR_CBCMD_SAVELISTAS,
	  DISPQT_EDITOR_CBCMD_RELOAD, DISPQT_EDITOR_CBCMD_DIRSWITCH, DISPQT_EDITOR_CBCMD_RANDOMIZE, DISPQT_EDITOR_CBCMD_CLEARLIST, DISPQT_EDITOR_CBCMD_SORT};

#define DISPQT_EDITOR_TABLE_MOUSEPRESS_TIMEMS 1000

#define DISPQT_ERROR_OK                      0
#define DISPQT_ERROR_EDITORTABLE_ARGS       -1  // invalid arguments
#define DISPQT_ERROR_EDITORTABLE_UNINIT     -2  // windows are uninitialized (wait for it)
#define DISPQT_ERROR_EDITORTABLE_NOTEXISTS  -3  // resource does not exist (disabled)
#define DISPQT_ERROR_EDITORTABLE_BUSY       -5  // resource is busy (wait for it)
#define DISPQT_ERROR_EDITORTABLE_MISSING    -8  // resource is missing (but should exist)
#define DISPQT_ERROR_EDITORTABLE_MEMORY    -10

struct dispqt_editor_callbackdata_s {
	unsigned int cbcmd;    // DISPQT_EDITOR_CBCMD_
	unsigned int flags;    // DISPQT_EDITOR_FLAG_
	int  mode;             // for addtab
	int  sidenum;
	int  tabnum;
	int  dest_sidenum;     // for addtab
	int  linenum;          // for editortable_seekevent_cb
};

#define DISPQT_EDITOR_MODELCONFIGFLAG_EDITSIDE (1 << 0)  // this tab is the current selected tab on the side
#define DISPQT_EDITOR_MODELCONFIGFLAG_EDITTAB  (1 << 1)  // this tab is the current selected tab on the side
#define DISPQT_EDITOR_MODELCONFIGFLAG_PLAYTAB  (1 << 2)  // this tab is the current play tab

struct dispqt_playlisteditor_model_config_s{
	unsigned int flags;        // DISPQT_EDITOR_TABHEADINFO_FLAG_
	unsigned int sidenum;      // psi->sidenum
	unsigned int tabnum;       // psi->tabnum
	unsigned long editsidetype;   // side infobits
	unsigned long editloadtype;   // PLL_ bits for side
	unsigned int id3ordernum_primary; // psi->id3ordernum_primary
	int  filenum_displayed;    // number of displayed (filtered) filenames
	int  filenum_entry_diff;   // diff number of editor_from and first playlist entry
	int  editorhighline_row;   // diff number of editorhighline and editor_from
	int number_of_rows;        // number of displayed entries in editor
	unsigned int *rows_flags;  // DISPQT_COLORTEXTID_EDITOR_
	char **filenames;          // list of filenames displayed in editor
	unsigned int nb_drives;    // number of drives
	char **drivenames;         // list of drive names displayed in drive combobox
	mpxp_filesize_t drive_free_space;  // free space of current drive in GB
	mpxp_filesize_t drive_total_space; // total space of current drive in GB
	char head_filename[64];    // filename displayed in tab head
	char head_fullname[256];   // filename displayed in tab tooltip
};

struct dispqt_playlisteditor_tabrefresh_config_s{
	int nb_tabs_on_side[PLAYLIST_MAX_SIDES];
	struct dispqt_playlisteditor_model_config_s tab_infos[PLAYLIST_MAX_SIDES][PLAYLIST_MAX_TABS_PER_SIDE];
};

class PlaylistEditortableHeader : public QHeaderView
{
Q_OBJECT
public:
	PlaylistEditortableHeader(MainWindow *main_window = 0, QWidget *parent = 0, unsigned int sidenum = 0);
	~PlaylistEditortableHeader(){};
	void update_header(struct dispqt_playlisteditor_model_config_s *pmc);
	int last_index;

public slots:
	void sectionClickHandler(int index);

private:
	MainWindow *main_window;
	unsigned int side_num, sort_control;
};

class PlaylistEditortableVScrollbar : public QScrollBar
{
Q_OBJECT
public:
	PlaylistEditortableVScrollbar(MainWindow *main_window = 0, QWidget *parent = 0, unsigned int sidenum = 0);
	~PlaylistEditortableVScrollbar(){};

	void config_settings(struct dispqt_playlisteditor_model_config_s *pmc, unsigned int page_step);
	void vscrollbar_enable(void);
	void refresh_settings(void);

	void setMinimum(int minval) {this->vscrollbar_enable();}
	void setMaximum(int maxval) {this->vscrollbar_enable();}
	void setSingleStep(int siglestep) {this->vscrollbar_enable();}
	void setPageStep(int pagestep) {this->vscrollbar_enable();}
	void setTracking(bool enable) {this->vscrollbar_enable();}
	void setSliderDown(bool enable) {this->vscrollbar_enable();}
	void setSliderPosition(int newpos) {this->vscrollbar_enable();}

	int sliderPosition() { this->vscrollbar_enable(); return this->last_pos; }
	int value() const { return this->last_pos; }
	void triggerAction(SliderAction action) { this->vscrollbar_enable(); }

public Q_SLOTS:
	void own_slot_action_handler(int action);
	void own_slot_setrange(int min, int max) {this->vscrollbar_enable(); }

	void action_handle(int action) { this->vscrollbar_enable(); }
	void setValue(int newpos) { this->vscrollbar_enable();}
	void setRange(int min, int max) { this->vscrollbar_enable();}
    void setEnabled(bool enable) { this->vscrollbar_enable();}
    void setDisabled(bool disable) { this->vscrollbar_enable();}

protected:
    void keyPressEvent(QKeyEvent *event);
    void sliderChange(SliderChange change) { this->vscrollbar_enable(); }
    void mousePressEvent(QMouseEvent *);
    void mouseReleaseEvent(QMouseEvent *);
    void wheelEvent(QWheelEvent *);
    void mouseMoveEvent(QMouseEvent *);
    void resizeEvent(QResizeEvent *e) { this->refresh_settings(); e->accept();}
    void changeEvent(QEvent *e) {this->vscrollbar_enable(); e->accept();}
    bool event(QEvent *e);

private:
    MainWindow *main_window;
    QWidget *parent_widget;
	unsigned int side_num;
	int last_pos, range_max, page_step;
	bool enabled, locked, mouse_is_pressed;
	int mouse_presspos_y, mouse_lastpos;
	QMutex mutex_vscrollbar;
};

class PlaylistEditorModel : public QStandardItemModel
{
public:
	PlaylistEditorModel(int rows = 1, int columns = 3, QObject *parent = 0);
	inline void editormodel_set_parent_table(PlaylistEditorTable *parent) { this->parent_table = parent; }

	void sort(int column, Qt::SortOrder order = Qt::AscendingOrder) {}
	QVariant data(const QModelIndex& index, int role) const;

private:
	PlaylistEditorTable *parent_table; // to get colors
};

class PlaylistEditorItemdelegate : public QItemDelegate
{
public:
	PlaylistEditorItemdelegate(QObject *parent);
	bool is_lucent_enabled;

	void paint(QPainter* in_painter, const QStyleOptionViewItem& in_options, const QModelIndex& in_index ) const;

private:
	PlaylistEditorTable *parent_table; // to get colors
};

class PlaylistEditorTable : public QTableView
{
	Q_OBJECT

public:
	PlaylistEditorTable(MainWindow *main_window = 0, QWidget *parent = 0, unsigned int sidenum = 0);
	~PlaylistEditorTable();
	void pmcdata_update(struct dispqt_playlisteditor_model_config_s *pmc_new, bool allocated);
	void table_config_apply(void);
	bool table_config_font(void);
	void table_config_color(bool);
	void table_setsizes(void);
	int  table_refresh_create(struct playlist_side_info *psi, void **model_ptr, void **pmc_ptr);
	void table_refresh_apply(PlaylistEditorModel *model_new, struct dispqt_playlisteditor_model_config_s *pmc);
	void table_line_select(int linenum);
	inline int line_count(void) { return (this->number_of_rows); }
	void keyPressEvent(QKeyEvent *event);
	void keyboardSearch(const QString& search) {};
	inline struct dispqt_playlisteditor_model_config_s *editortable_get_pmc(void) { return this->pmc_ptr;} // to pass to editor.cpp
	inline const QColor get_colors_editor(unsigned int i) { if(i >= DISPQT_COLORTEXTID_EDITOR_MAX) i = 0; return this->colors_editor[i]; }
	inline const QColor *get_colors_editor_ptr(unsigned int i) { if(i >= DISPQT_COLORTEXTID_EDITOR_MAX) i = 0; return &this->colors_editor[i]; }
	PlaylistEditortableHeader *header_view;
	PlaylistEditortableVScrollbar *vscrollbar;

	void scrollTo(const QModelIndex &index, ScrollHint hint = EnsureVisible) {}
	void sortByColumn(int column, Qt::SortOrder order) {}

Q_SIGNALS:
	void signal_seekevent_cbinit(unsigned long flags, int row_number);

public slots:
	void seekevent_cb_init(unsigned long flags, int row_number);

public Q_SLOTS:
	void sortByColumn(int column) {}

protected slots:
	void resizeEvent(QResizeEvent *event);
	void wheelEvent(QWheelEvent* event);
	void mouseMoveEvent(QMouseEvent *event);
	void mousePressEvent(QMouseEvent *event);
	void mouseReleaseEvent(QMouseEvent *event);
	void mouseDoubleClickEvent(QMouseEvent *event);

private slots:
	void table_mousepress_timeout(void);

protected:
	bool focusNextPrevChild(bool next);
	void scrollContentsBy(int dx, int dy) {}

private:
	struct dispqt_playlisteditor_model_config_s *pmcdata_allocate(int number_of_rows, struct dispqt_playlisteditor_model_config_s *pmc_ref);
	void pmcdata_dealloc(struct dispqt_playlisteditor_model_config_s *pmc);
	inline int table_calc_nb_rows(int new_pixelheight) { return (new_pixelheight/ this->row_height); }
	//inline int table_calc_nb_rows(int new_pixelheight) { return ((new_pixelheight + this->row_height / 4) / this->row_height); }
	void table_config_resize(int new_pixelheight);
	PlaylistEditorModel *model_create(QWidget *parent, int number_of_rows);
	void linedata_update(PlaylistEditorModel *model, struct playlist_side_info *psi, struct playlist_entry_info *pei, int pos);
	MainWindow *main_window;
	QWidget *parent_widget;
	PlaylistEditorModel *editor_tab_model_curr;
	PlaylistEditorItemdelegate *editor_item_delegate;
	struct dispqt_playlisteditor_model_config_s *pmc_ptr;
	QTimer *timer_mousepress;
	int number_of_rows, row_index, row_cursor, row_height;
	unsigned int side_num, tab_num;
	unsigned int last_desktmode, exec_flags, exec_row_number;
	bool is_color_refresh, is_font_refresh, is_table_refresh, last_activeside_flag;
	QString str_font_name, str_color_name[DISPQT_COLORTEXTID_EDITOR_MAX];
	QFont font_editor;
	char font_name_curr[128];
	QPalette color_palette_active, color_palette_inactive;
	QColor colors_editor[DISPQT_COLORTEXTID_EDITOR_MAX];
	QMutex mutex_editortable, mutex_resize;
};

class PlaylistEditorTabBar : public QTabBar
{
Q_OBJECT
public:
	PlaylistEditorTabBar(MainWindow *main_window, QWidget *parent, unsigned int sidenum = 0);
	void tabbar_config_style_apply(void);
	void keyboardSearch(const QString& search) {};

protected:
	void keyPressEvent(QKeyEvent *event);
	void wheelEvent(QWheelEvent* event);
	void mousePressEvent(QMouseEvent *event);

private:
	MainWindow *main_window;
	QWidget *parent_widget;
	unsigned int side_num;
};

class PlaylistEditorTabs : public QTabWidget
{
	Q_OBJECT

public:
	PlaylistEditorTabs(MainWindow *main_window = 0 , QWidget *parent = 0, unsigned int sidenum = 0);
	void editortabs_config_apply(void);
	void editortabs_config_style_apply(void);
//	void tab_load_dir_or_files(int sidenum, int tabnum, bool directory);
	void tab_create(struct dispqt_playlisteditor_model_config_s *pmc);
	void tab_delete(struct dispqt_playlisteditor_model_config_s *pmc);
	bool tab_select(unsigned int tabnum);
	void tab_header_apply_info(struct dispqt_playlisteditor_model_config_s *pmc);
	int  table_refresh_create(struct playlist_side_info *psi);
	void line_select_request(struct playlist_side_info *psi, struct playlist_entry_info *pei);
	PlaylistEditorTable *tabs_get_table(int tabnum);
	void keyboardSearch(const QString& search) {};
	PlaylistEditorTabBar *editor_tab_bar;

public Q_SLOTS:
	void showContextMenu(const QPoint &point);
	void tab_head_contexmenu_lockedfunc_msg(void);
	void tab_head_contextmenuaction_duplicate(void);
	void tab_head_contextmenuaction_copyToOtherSide(void);
	void tab_head_contextmenuaction_locktab(void);
	void tab_head_contextmenuaction_newEmptyTab(void);
	void tab_head_contextmenuaction_remove(void);
	void tab_head_contextmenuaction_loadfiles(void);
	void tab_head_contextmenuaction_loaddir(void);
	void tab_head_contextmenuaction_loadurl(void);
	void tab_head_contextmenuaction_savelistas(void);
	void tab_head_contextmenuaction_reload(void);
	void tab_head_contextmenuaction_dirswitch(void);
	void tab_head_contextmenuaction_randomize(void);
	void tab_head_contextmenuaction_clearlist(void);
	void tab_head_contextmenuaction_sort_col_0(void);
	void tab_head_contextmenuaction_sort_col_1(void);
	void tab_head_contextmenuaction_sort_col_2(void);
	void tab_head_contextmenuaction_sort_col_3(void);

Q_SIGNALS:
	void signal_tab_head_lockedfuncmsg(void);

private slots:
	void table_refresh_apply(void);
	void line_select_apply(void);

protected:
	void keyPressEvent(QKeyEvent *event);

private:
	void tab_head_contextmenu_add_vary_texts(void);
	void tab_head_contextmenuaction_sort_col_n(unsigned int col);

	MainWindow *main_window;
	QWidget *parent_widget;
	unsigned int side_num, selected_tab_num, sort_last_prikey_col;
	QAction *action_table_refresh, *action_line_select;
	unsigned int act_tablerefresh_userdataid_model, act_tablerefresh_userdataid_pmc, act_lineselect_userdataid_reqinfo;
	QMenu *tab_head_contextmenu;
	QAction *tab_head_menuact_tabname, *tab_head_menuact_duplicate, *tab_head_menuact_copyToOtherSide;
	QAction *tab_head_menuact_locktab, *tab_head_menuact_newEmptyTab, *tab_head_menuact_remove;
	QAction *tab_head_menuact_loadfiles, *tab_head_menuact_loaddir, *tab_head_menuact_loadurl, *tab_head_menuact_savelistas;
	QAction *tab_head_menuact_reload, *tab_head_menuact_dirswitch, *tab_head_menuact_randomize, *tab_head_menuact_clearlist;
	QAction *tab_head_menuact_sort[DISPQT_EDITOR_TABLE_COL_MAX];
	PlaylistEditorTable *editor_tab_tables[PLAYLIST_MAX_TABS_PER_SIDE];
	int editor_tab_indexes[PLAYLIST_MAX_TABS_PER_SIDE];
	QMutex mutex_editortabs;
};

class PlaylistEditorWidget : public QWidget
{
	Q_OBJECT

public:
	PlaylistEditorWidget(MainWindow *main_window = 0, QWidget *parent = 0);
	void editor_delete_all(void);
	void editor_config_apply(bool on_video);
	void editor_config_style_apply(bool lucent_enable);
	void editor_config_style_onvideo_switch(bool on_video);
	void set_default_focus(struct playlist_side_info *psi);
	void tab_changed_handler(struct dispqt_playlisteditor_model_config_s *pmc);
	int  table_refresh_create(struct playlist_side_info *psi);
	void line_select_request(struct playlist_side_info *psi, struct playlist_entry_info *pei);
	int  editortable_line_count(struct playlist_side_info *psi);
	void editortabs_editlisteventcb_init(unsigned int cmd, unsigned int mode, int sidenum, int tabnum, int dest_sidenum);
	void keyPressEvent(QKeyEvent *event);
	void keyboardSearch(const QString& search) {};
	struct dispqt_playlisteditor_model_config_s *tab_get_pmc(PlaylistEditorTabs **pet_ptr, int sidenum, int tabnum);

	PlaylistEditorTabs *editor_tab_widget[PLAYLIST_MAX_SIDES];
	EditorDriveline *editor_drive_line[PLAYLIST_MAX_SIDES];

	unsigned int act_tabsrefresh_userdataid_tabrefreshcfg;
	QAction *action_tabs_refresh;

public slots:
	void tab_headers_refresh_apply(void);

private:
	void editor_build_all(bool initial);
	void editor_config_transparent_back(bool on_video);
	MainWindow *main_window;
	QBoxLayout *PlaylistEditorLayout;
	QVBoxLayout *editor_side_layout[PLAYLIST_MAX_SIDES];
	unsigned int last_desktopmode, last_editorflags;
	QMutex mutex_editorwidget;
};

void mpxplay_dispqt_editor_tab_header_create_info(struct playlist_side_info *psi, struct dispqt_playlisteditor_model_config_s *pmc, bool full);
int  mpxplay_dispqt_editor_tab_headers_refresh_create(struct mainvars *mvp, PlaylistEditorWidget *pew);
void mpxplay_dispqt_editor_event_callback(void *passdata);

#endif // MOC_EDITOR_H
