// Created on: 2017-06-16
// Created by: Natalia ERMOLAEVA
// Copyright (c) 2017 OPEN CASCADE SAS
//
// This file is part of Open CASCADE Technology software library.
//
// This library is free software; you can redistribute it and/or modify it under
// the terms of the GNU Lesser General Public License version 2.1 as published
// by the Free Software Foundation, with special exception defined in the file
// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
// distribution for complete text of the license and disclaimer of any warranty.
//
// Alternatively, this file may be used under the terms of Open CASCADE
// commercial license or contractual agreement.

#include <inspector/TInspector_OpenFileDialog.hxx>

#include <inspector/TInspector_OpenButton.hxx>
#include <inspector/TInspector_OpenFileViewModel.hxx>

#include <inspector/TInspector_Communicator.hxx>

#include <Standard_WarningsDisable.hxx>
#include <QApplication>
#include <QCompleter>
#include <QDir>
#include <QFileDialog>
#include <QFileSystemModel>
#include <QItemSelectionModel>
#include <QGroupBox>
#include <QHBoxLayout>
#include <QHeaderView>
#include <QLabel>
#include <QLineEdit>
#include <QScrollBar>
#include <QTableView>
#include <QToolButton>
#include <QPushButton>
#include <QVBoxLayout>
#include <QWidget>
#include <Standard_WarningsRestore.hxx>

static const int ICON_SIZE = 40;

static const int OPEN_DIALOG_WIDTH  = 550;
static const int OPEN_DIALOG_HEIGHT = 200;

static const int MARGIN_DIALOG  = 4;
static const int SPACING_DIALOG = 2;

static const int RECENT_FILES_CACHE_SIZE = 10;

TInspector_Communicator* MyCommunicator;

// =======================================================================
// function : changeMargins
// purpose :
// =======================================================================
void changeMargins(QBoxLayout* theLayout)
{
  theLayout->setContentsMargins(MARGIN_DIALOG, MARGIN_DIALOG, MARGIN_DIALOG, MARGIN_DIALOG);
  theLayout->setSpacing(SPACING_DIALOG);
}

// =======================================================================
// function : Constructor
// purpose :
// =======================================================================
TInspector_OpenFileDialog::TInspector_OpenFileDialog(QWidget*           theParent,
                                                     const QStringList& theRecentlyOpenedFiles)
    : QDialog(theParent),
      myRecentlyOpenedFiles(theRecentlyOpenedFiles)
{
  setWindowTitle(tr("Open File"));

  QVBoxLayout* aDialogLay = new QVBoxLayout(this);
  changeMargins(aDialogLay);

  // Samples View
  QGroupBox* aSamplesBox = new QGroupBox(this);
  aSamplesBox->setTitle(tr("Recent files"));
  aDialogLay->addWidget(aSamplesBox);
  QVBoxLayout* aSampleLay = new QVBoxLayout(aSamplesBox);
  changeMargins(aSampleLay);
  mySamplesView = createTableView(theRecentlyOpenedFiles);
  aSampleLay->addWidget(mySamplesView);

  // Select file
  QGroupBox* aSelectFileBox = new QGroupBox(this);
  aSelectFileBox->setTitle(tr("Select file"));
  aDialogLay->addWidget(aSelectFileBox);
  QGridLayout* aSelectFileLay = new QGridLayout(aSelectFileBox);
  aSelectFileLay->setContentsMargins(MARGIN_DIALOG, MARGIN_DIALOG, MARGIN_DIALOG, MARGIN_DIALOG);

  mySelectedName                     = new QLineEdit(aSelectFileBox);
  QCompleter*       aCompleter       = new QCompleter();
  QFileSystemModel* aFileSystemModel = new QFileSystemModel;
  aFileSystemModel->setRootPath(QDir::rootPath());
  aCompleter->setModel(aFileSystemModel);
  mySelectedName->setCompleter(aCompleter);
  aSelectFileLay->addWidget(mySelectedName, 1, 0);

  QToolButton* aSelectFileBtn = new QToolButton(aSelectFileBox);
  aSelectFileBtn->setIcon(QIcon(":folder_open.png"));
  aSelectFileLay->addWidget(aSelectFileBtn, 1, 1);

  connect(aSelectFileBtn, SIGNAL(clicked()), this, SLOT(onSelectClicked()));
  connect(mySelectedName, SIGNAL(returnPressed()), this, SLOT(onApplySelectClicked()));

  resize(OPEN_DIALOG_WIDTH, OPEN_DIALOG_HEIGHT);
}

// =======================================================================
// function : OpenFile
// purpose :
// =======================================================================
QString TInspector_OpenFileDialog::OpenFile(QWidget*           theParent,
                                            const QStringList& theRecentlyOpenedFiles)
{
  QString                    aFileName;
  TInspector_OpenFileDialog* aDialog =
    new TInspector_OpenFileDialog(theParent, theRecentlyOpenedFiles);
  if (aDialog->exec() == QDialog::Accepted)
    aFileName = aDialog->GetFileName();

  return aFileName;
}

// =======================================================================
// function : Communicator
// purpose :
// =======================================================================
TInspector_Communicator* TInspector_OpenFileDialog::Communicator()
{
  if (!MyCommunicator)
    MyCommunicator = new TInspector_Communicator();
  return MyCommunicator;
}

// =======================================================================
// function : GetPluginRecentlyOpenedFiles
// purpose :
// =======================================================================
void TInspector_OpenFileDialog::GetPluginRecentlyOpenedFiles(
  const TCollection_AsciiString& thePluginName,
  TInspector_Communicator*       theCommunicator,
  QStringList&                   theFileNames)
{
  Handle(TInspectorAPI_PluginParameters) aParameters = theCommunicator->GetPluginParameters();
  TInspectorAPI_PreferencesDataMap       aPreferencesItem;
  aParameters->GetPreferences(thePluginName, aPreferencesItem);

  for (TInspectorAPI_IteratorOfPreferencesDataMap anItemIt(aPreferencesItem); anItemIt.More();
       anItemIt.Next())
  {
    if (!anItemIt.Key().IsEqual("recently_opened_files"))
      continue;
#include <Standard_WarningsDisable.hxx>
    theFileNames = QString(anItemIt.Value().ToCString()).split(";", QString::SkipEmptyParts);
#include <Standard_WarningsRestore.hxx>
    if (theFileNames.size() > RECENT_FILES_CACHE_SIZE)
      for (int i = 0; i < theFileNames.size() - RECENT_FILES_CACHE_SIZE; i++)
        theFileNames.removeFirst();
    break;
  }
}

// =======================================================================
// function : SetPluginRecentlyOpenedFiles
// purpose :
// =======================================================================
void TInspector_OpenFileDialog::SetPluginRecentlyOpenedFiles(
  const TCollection_AsciiString& thePluginName,
  TInspector_Communicator*       theCommunicator,
  QStringList&                   theFileNames)
{
  Handle(TInspectorAPI_PluginParameters) aParameters = theCommunicator->GetPluginParameters();

  TInspectorAPI_PreferencesDataMap aPreferencesItem;
  aParameters->GetPreferences(thePluginName, aPreferencesItem);
  aPreferencesItem.Bind("recently_opened_files",
                        TCollection_AsciiString(theFileNames.join(";").toUtf8().data()));

  aParameters->SetPreferences(thePluginName, aPreferencesItem);
}

// =======================================================================
// function : onSampleSelectionChanged
// purpose :
// =======================================================================
void TInspector_OpenFileDialog::onSampleSelectionChanged(const QItemSelection& theSelected,
                                                         const QItemSelection&)
{
  QItemSelectionModel* aSelectionModel = (QItemSelectionModel*)sender();
  if (!aSelectionModel)
    return;
  if (theSelected.isEmpty())
    return;

  QModelIndex anIndex = theSelected.first().indexes().first();
  if (!anIndex.isValid())
    return;

  myFileName = aSelectionModel->model()->data(anIndex, Qt::ToolTipRole).toString();
  accept();
}

// =======================================================================
// function : onSelectClicked
// purpose :
// =======================================================================
void TInspector_OpenFileDialog::onSelectClicked()
{
  QString anEnteredPath;
  QString aDirName = mySelectedName->text();
  if (!aDirName.isEmpty())
  {
    QDir aDir(aDirName);
    if (aDir.exists())
      anEnteredPath = aDirName;
  }

  QString aFileName = QFileDialog::getOpenFileName(0, "Open document", anEnteredPath);

  if (aFileName.isEmpty())
    return; // do nothing, left the previous value

  myFileName = aFileName;
  accept();
}

// =======================================================================
// function : onApplySelectClicked
// purpose :
// =======================================================================
void TInspector_OpenFileDialog::onApplySelectClicked()
{
  QString aFileName = mySelectedName->text();

  QFileInfo aFileInfo(aFileName);
  if (!aFileInfo.exists() || !aFileInfo.isFile())
    return;

  myFileName = mySelectedName->text();
  accept();
}

// =======================================================================
// function : createTableView
// purpose :
// =======================================================================
QTableView* TInspector_OpenFileDialog::createTableView(const QStringList& theFileNames)
{
  QTableView* aTableView = new QTableView(this);
  aTableView->setFrameStyle(QFrame::NoFrame);
  QPalette aPalette     = aTableView->viewport()->palette();
  QColor   aWindowColor = aPalette.color(QPalette::Window);
  aPalette.setBrush(QPalette::Base, aWindowColor);
  aTableView->viewport()->setPalette(aPalette);

  aTableView->horizontalHeader()->setVisible(false);
  aTableView->verticalHeader()->setVisible(false);
  aTableView->setGridStyle(Qt::NoPen);
  aTableView->setModel(createModel(theFileNames));
  aTableView->setItemDelegateForRow(
    0,
    new TInspectorEXE_OpenFileItemDelegate(aTableView, aPalette.color(QPalette::Highlight)));
  aTableView->viewport()->setAttribute(Qt::WA_Hover);
  int aCellHeight = ICON_SIZE + aTableView->verticalHeader()->defaultSectionSize();
  aTableView->setRowHeight(0, aCellHeight);
  int aScrollHeight = aTableView->horizontalScrollBar()->sizeHint().height();
  aTableView->setMinimumHeight(aCellHeight + aScrollHeight);
  QItemSelectionModel* aSelectionModel = new QItemSelectionModel(aTableView->model());
  connect(aSelectionModel,
          SIGNAL(selectionChanged(const QItemSelection&, const QItemSelection&)),
          this,
          SLOT(onSampleSelectionChanged(const QItemSelection&, const QItemSelection&)));
  aTableView->setSelectionModel(aSelectionModel);

  return aTableView;
}

// =======================================================================
// function : createModel
// purpose :
// =======================================================================
QAbstractItemModel* TInspector_OpenFileDialog::createModel(const QStringList& theFileNames)
{
  TInspector_OpenFileViewModel* aModel = new TInspector_OpenFileViewModel(this);
  aModel->Init(theFileNames);
  return aModel;
}