#pragma once

#ifndef SCENEBROWSER_INCLUDED
#define SCENEBROWSER_INCLUDED

#include <QFrame>
#include <QTreeWidget>
#include <QDateTime>
#include <QItemDelegate>
#include <QCheckBox>
#include <QList>
#include <QModelIndex>
#include "dvitemview.h"
#include "tfilepath.h"
#include "toonzqt/dvdialog.h"
#include "versioncontrol.h"
#include "filebrowser.h"

#include "tthread.h"

class QLineEdit;
class QTreeWidgetItem;
class QSplitter;
class DvDirModelNode;
class DvDirTreeView;
class QFileSystemWatcher;

//-----------------------------------------------------------------------------
class SceneBrowserButtonBar final : public QToolBar {
  Q_OBJECT
  QAction *m_folderBack;
  QAction *m_folderFwd;

public:
  SceneBrowserButtonBar(DvItemViewer *itemViewer, QWidget *parent = 0);

signals:
  void newScene();
};
//-----------------------------------------------------------------------------

class SceneBrowser final : public QFrame, public DvItemListModel {
  Q_OBJECT

public:
  SceneBrowser(QWidget *parent, Qt::WindowFlags flags = Qt::WindowFlags(),
               bool noContextMenu = false, bool multiSelectionEnabled = false);
  ~SceneBrowser();

  void sortByDataModel(DataType dataType, bool isDescendant) override;
  void refreshData() override;

  int getItemCount() const override;
  QVariant getItemData(int index, DataType dataType,
                       bool isSelected = false) override;

  bool canRenameItem(int index) const override;
  void renameItem(int index, const QString &newName) override;

  bool isSceneItem(int index) const override;
  void startDragDrop() override;
  QMenu *getContextMenu(QWidget *parent, int index) override;

  /*!
   This function adds a new type to the filter list;
   if this function is never called, the default filter includes all image
   files, scene files, and palette files.
   */
  void addFilterType(const QString &type);

  /*!
   The setFilterTypes function directly specifies the list of file types
   to be displayed in the file browser.
   */
  void setFilterTypes(const QStringList &types);
  const QStringList &getFilterTypes() const { return m_filter; }
  void removeFilterType(const QString &type);

  void setFolder(const TFilePath &fp, bool expandNode = false,
                 bool forceUpdate = false);
  // Process when inputting a folder that is not registered in the folder tree
  // (e.g., a UNC path in Windows)
  void setUnregisteredFolder(const TFilePath &fp);

  void setHistoryDay(std::string dayDateString);

  TFilePath getFolder() const { return m_folder; }
  std::string getDayDateString() const { return m_dayDateString; }

  static void refreshFolder(const TFilePath &folder);

  static void updateItemViewerPanel();

  // Returns true if the file has been renamed. After the call, fp contains
  // the new path.
  static bool renameFile(TFilePath &fp, QString newName);

  void makeCurrentProjectVisible();

  void enableGlobalSelection(bool enabled);
  void selectNone();

  QSplitter *getMainSplitter() const { return m_mainSplitter; }

  // Enable double-click to open a scene.
  // This is not always desirable (e.g., if a user double-clicks on a file in
  // a "Save As" dialog, they expect the file to be saved, not opened).
  // So it is disabled by default.
  void enableDoubleClickToOpenScenes();

  void enableSingleClickToOpenScenes();

protected:
  int findIndexWithPath(TFilePath path);
  void getExpandedFolders(DvDirModelNode *node,
                          QList<DvDirModelNode *> &expandedNodes);

  bool dropMimeData(QTreeWidgetItem *parent, int index, const QMimeData *data,
                    Qt::DropAction action);

  bool acceptDrop(const QMimeData *data) const override;
  bool drop(const QMimeData *data) override;
  void showEvent(QShowEvent *) override;
  void hideEvent(QHideEvent *) override;

  // Fill the QStringList with files selected in the browser, auxiliary files
  // (palette for tlv, hooks, sceneIcons)
  // Also retrieve the path and return the sceneIconsCount.
  void setupVersionControlCommand(QStringList &files, QString &path,
                                  int &sceneIconsCount);
  void setupVersionControlCommand(QString &file, QString &path);

  void refreshHistoryButtons();

public slots:

  void onTreeFolderChanged();

protected slots:

  void refresh();

  void changeFolder(const QModelIndex &index);
  void onDataChanged(const QModelIndex &topLeft,
                     const QModelIndex &bottomRight);
  void loadResources();
  void onClickedItem(int index);
  void onDoubleClickedItem(int index);
  void onSelectedItems(const std::set<int> &indexes);
  void onSceneSwitched();
  void newScene();

  void onBackButtonPushed();
  void onFwdButtonPushed();
  void onFolderEdited();
  void storeFolderHistory();
  void clearHistory();

  void renameAsToonzLevel();
  void updateAndEditVersionControl();
  void editVersionControl();
  void unlockVersionControl();

  void editFrameRangeVersionControl();
  void unlockFrameRangeVersionControl();

  void putFrameRangeVersionControl();
  void revertFrameRangeVersionControl();

  void showLockInformation();
  void showFrameRangeLockInfo();

  void putVersionControl();
  void revertVersionControl();
  void deleteVersionControl();
  void getVersionControl();
  void getRevisionVersionControl();
  void getRevisionHistory();

  void onVersionControlCommandDone(const QStringList &files);

  void onFileSystemChanged(const QString &folderPath);

  // If filePath is a valid scene file, open it. Otherwise do nothing.
  void tryToOpenScene(const TFilePath &filePath);

signals:

  void filePathClicked(const TFilePath &);
  void filePathDoubleClicked(const TFilePath &);
  // Reuse the list of TFrameId to skip loadInfo() when loading a level
  // with sequential frames.
  void filePathsSelected(const std::set<TFilePath> &,
                         const std::list<std::vector<TFrameId>> &);
  void treeFolderChanged(const TFilePath &);

  // For activating/deactivating the folder history buttons (back button &
  // forward button).
  void historyChanged(bool, bool);

private:
  struct Item {
    QString m_name;
    qlonglong m_fileSize;
    QDateTime m_creationDate;
    QDateTime m_modifiedDate;
    int m_frameCount;
    QString m_fileType;
    TFilePath m_path;
    bool m_validInfo;

    bool m_isFolder;
    bool m_isLink;
    // Calling loadInfo for a level with sequential frames is time-consuming.
    // So keep the list of frameIds from the first time and try to reuse it.
    std::vector<TFrameId> m_frameIds;

    Item() : m_frameCount(0), m_validInfo(false), m_fileSize(0) {}
    Item(const TFilePath &path, bool folder = false, bool link = false,
         QString name = QString(""))
        : m_path(path)
        , m_frameCount(0)
        , m_validInfo(false)
        , m_fileSize(0)
        , m_isFolder(folder)
        , m_isLink(link)
        , m_name(name) {}
  };

private:
  DvDirTreeView *m_folderTreeView;
  QSplitter *m_mainSplitter;
  QLineEdit *m_folderName;
  DvItemViewer *m_itemViewer;
  FrameCountReader m_frameCountReader;

  // Folder history
  QList<QModelIndex> m_indexHistoryList;
  int m_currentPosition;
  int m_currentScroll;

  std::vector<Item> m_items;
  TFilePath m_folder;
  std::string m_dayDateString;
  QStringList m_filter;
  std::map<TFilePath, Item> m_multiFileItemMap;

private:
  void readFrameCount(Item &item);
  void readInfo(Item &item);

  void refreshCurrentFolderItems();

  DvItemListModel::Status getItemVersionControlStatus(
      const SceneBrowser::Item &item);
};

//-----------------------------------------------------------

#endif
