// 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/DFBrowser_TreeLevelLine.hxx>

#include <inspector/DFBrowser_SearchLine.hxx>
#include <inspector/DFBrowser_Window.hxx>
#include <inspector/DFBrowser_TreeLevelLineDelegate.hxx>
#include <inspector/DFBrowser_TreeLevelLineModel.hxx>

#include <inspector/DFBrowserPane_Tools.hxx>

#include <inspector/TreeModel_ModelBase.hxx>
#include <inspector/TreeModel_Tools.hxx>

#include <Standard_WarningsDisable.hxx>
#include <QAbstractItemModel>
#include <QFrame>
#include <QGridLayout>
#include <QHeaderView>
#include <QItemSelectionModel>
#include <QPainter>
#include <QScrollBar>
#include <QTableView>
#include <QToolButton>
#include <QWidget>
#include <Standard_WarningsRestore.hxx>

const int HISTORY_SIZE = 10;
const int MARGIN_SIZE  = 2;

// =======================================================================
// function : Constructor
// purpose :
// =======================================================================
DFBrowser_TreeLevelLine::DFBrowser_TreeLevelLine(QWidget* theParent)
    : QObject(theParent),
      mySelectionProcessingBlocked(false),
      myCurrentHistoryIndex(-1)
{
  myMainWindow         = new QWidget(theParent);
  QGridLayout* aLayout = new QGridLayout(myMainWindow);
  aLayout->setContentsMargins(MARGIN_SIZE, MARGIN_SIZE, MARGIN_SIZE, MARGIN_SIZE);

  myBackwardButton = new QToolButton(myMainWindow);
  myBackwardButton->setIcon(QIcon(":/icons/treeline_backward.png"));
  myBackwardButton->setToolTip(tr("Backward"));
  connect(myBackwardButton, SIGNAL(clicked()), this, SLOT(onActionClicked()));
  aLayout->addWidget(myBackwardButton, 0, 0);

  myForwardButton = new QToolButton(myMainWindow);
  myForwardButton->setIcon(QIcon(":/icons/treeline_forward.png"));
  myForwardButton->setToolTip(tr("Forward"));
  connect(myForwardButton, SIGNAL(clicked()), this, SLOT(onActionClicked()));
  aLayout->addWidget(myForwardButton, 0, 1);

  myTableView = new QTableView(myMainWindow);
  myTableView->horizontalHeader()->setVisible(false);
  QHeaderView* aVHeader = myTableView->verticalHeader();
  aVHeader->setVisible(false);
  int aDefCellSize = aVHeader->minimumSectionSize() + TreeModel_Tools::HeaderSectionMargin();
  aVHeader->setDefaultSectionSize(aDefCellSize);
  aLayout->addWidget(myTableView, 0, 2);

  myTableView->setFixedHeight(aDefCellSize);
  myTableView->horizontalHeader()->setMinimumSectionSize(5); // it will be resized by context
  myTableView->setHorizontalScrollMode(QAbstractItemView::ScrollPerItem);
  myTableView->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); //! TEMPORARY
  myTableView->setShowGrid(false);

  DFBrowser_TreeLevelLineModel* aHModel = new DFBrowser_TreeLevelLineModel(myTableView);
  myTableView->setModel(aHModel);

  QItemSelectionModel* aSelectionModel = new QItemSelectionModel(aHModel);
  myTableView->setSelectionMode(QAbstractItemView::SingleSelection);
  myTableView->setSelectionModel(aSelectionModel);
  connect(aSelectionModel,
          SIGNAL(selectionChanged(const QItemSelection&, const QItemSelection&)),
          this,
          SLOT(onTableSelectionChanged(const QItemSelection&, const QItemSelection&)));

  // highlight for items
  myTableView->viewport()->setAttribute(Qt::WA_Hover);
  myTableView->setItemDelegate(new DFBrowser_TreeLevelLineDelegate(myTableView));

  aLayout->setColumnStretch(2, 1);

  myUpdateButton = new QToolButton(myMainWindow);
  myUpdateButton->setIcon(QIcon(":/icons/treeline_update.png"));
  myUpdateButton->setToolTip(tr("Update Tree Model"));
  connect(myUpdateButton, SIGNAL(clicked()), this, SLOT(onActionClicked()));
  aLayout->addWidget(myUpdateButton, 0, 3);

  mySearchLine = new DFBrowser_SearchLine(myMainWindow);
  aLayout->addWidget(mySearchLine, 0, 4);

  updateActionsState();
}

// =======================================================================
// function : clear
// purpose :
// =======================================================================
void DFBrowser_TreeLevelLine::ClearHistory()
{
  myHistoryIndices.clear();
  setCurrentHistoryIndex(-1);
}

// =======================================================================
// function : onSelectionChanged
// purpose :
// =======================================================================
void DFBrowser_TreeLevelLine::OnTreeViewSelectionChanged(const QItemSelection& theSelected,
                                                         const QItemSelection&)
{
  QModelIndexList aSelectedIndices = theSelected.indexes();
  QModelIndex     aSelectedIndex   = TreeModel_ModelBase::SingleSelected(aSelectedIndices, 0);

  if (!mySelectionProcessingBlocked) // we're processing action click
    setForwardIndex(aSelectedIndex);

  bool isBlocked = mySelectionProcessingBlocked;
  // block selection processing in order to avoid circling by processing table selection changing
  mySelectionProcessingBlocked = true;
  DFBrowser_TreeLevelLineModel* aModel =
    dynamic_cast<DFBrowser_TreeLevelLineModel*>(myTableView->model());
  aModel->Init(aSelectedIndex);
  myTableView->selectionModel()->clearSelection();
  myTableView->resizeColumnsToContents();

  myTableView->scrollTo(myTableView->model()->index(0, myTableView->model()->columnCount() - 1));

  mySelectionProcessingBlocked = isBlocked;
}

// =======================================================================
// function : onTableSelectionChanged
// purpose :
// =======================================================================
void DFBrowser_TreeLevelLine::onTableSelectionChanged(const QItemSelection& theSelected,
                                                      const QItemSelection&)
{
  if (mySelectionProcessingBlocked)
    return;

  DFBrowser_TreeLevelLineModel* aTableModel =
    dynamic_cast<DFBrowser_TreeLevelLineModel*>(myTableView->model());
  if (!aTableModel)
    return;

  QModelIndex aSelectedIndex =
    TreeModel_ModelBase::SingleSelected(theSelected.indexes(), 0, Qt::Vertical);
  emit indexSelected(aTableModel->GetTreeViewIndex(aSelectedIndex));
}

// =======================================================================
// function : onActionClicked
// purpose :
// =======================================================================
void DFBrowser_TreeLevelLine::onActionClicked()
{
  QToolButton* aSender = (QToolButton*)sender();
  if (aSender == myBackwardButton || aSender == myForwardButton)
  {
    bool aBlocked                = mySelectionProcessingBlocked;
    mySelectionProcessingBlocked = true;
    QModelIndex anIndex;
    if (aSender == myBackwardButton)
    {
      anIndex = getBackwardIndex();
      if (anIndex.isValid())
        setCurrentHistoryIndex(myCurrentHistoryIndex - 1);
    }
    else
    {
      anIndex = getForwardIndex();
      if (anIndex.isValid())
        setCurrentHistoryIndex(myCurrentHistoryIndex + 1);
    }
    if (anIndex.isValid())
      emit indexSelected(anIndex);
    mySelectionProcessingBlocked = aBlocked;
  }
  else if (aSender == myUpdateButton)
    emit updateClicked();
}

// =======================================================================
// function : getBackwardIndex
// purpose :
// =======================================================================
QModelIndex DFBrowser_TreeLevelLine::getBackwardIndex()
{
  return myCurrentHistoryIndex > 0 ? myHistoryIndices[myCurrentHistoryIndex - 1] : QModelIndex();
}

// =======================================================================
// function : getForwardIndex
// purpose :
// =======================================================================
QModelIndex DFBrowser_TreeLevelLine::getForwardIndex()
{
  return (myCurrentHistoryIndex >= 0 && myCurrentHistoryIndex + 1 < myHistoryIndices.count())
           ? myHistoryIndices[myCurrentHistoryIndex + 1]
           : QModelIndex();
}

// =======================================================================
// function : setForwardIndex
// purpose :
// =======================================================================
void DFBrowser_TreeLevelLine::setForwardIndex(const QModelIndex& theIndex)
{
  while (myCurrentHistoryIndex != myHistoryIndices.count() - 1)
    myHistoryIndices.removeLast();

  myHistoryIndices.append(theIndex);
  if (myHistoryIndices.size() > HISTORY_SIZE)
    myHistoryIndices.removeFirst();

  setCurrentHistoryIndex(myHistoryIndices.count() - 1);
}

// =======================================================================
// function : setCurrentHistoryIndex
// purpose :
// =======================================================================
void DFBrowser_TreeLevelLine::setCurrentHistoryIndex(const int theIndexId)
{
  myCurrentHistoryIndex = theIndexId;
  updateActionsState();
}

// =======================================================================
// function : updateActionsState
// purpose :
// =======================================================================
void DFBrowser_TreeLevelLine::updateActionsState()
{
  if (myCurrentHistoryIndex < 0)
  {
    myBackwardButton->setEnabled(false);
    myForwardButton->setEnabled(false);
  }
  else
  {
    myBackwardButton->setEnabled(myCurrentHistoryIndex > 0);
    myForwardButton->setEnabled(myCurrentHistoryIndex < myHistoryIndices.size() - 1);
  }
}