/***************************************************************************
**
**  This file is part of QGpGuiTools.
**
**  This library is free software; you can redistribute it and/or
**  modify it under the terms of the GNU Lesser General Public
**  License as published by the Free Software Foundation; either
**  version 2.1 of the License, or (at your option) any later version.
**
**  This file is distributed in the hope that it will be useful, but WITHOUT
**  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
**  FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
**  License for more details.
**
**  You should have received a copy of the GNU Lesser General Public
**  License along with this library; if not, write to the Free Software
**  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
**
**  See http://www.geopsy.org for more information.
**
**  Created: 2008-03-28
**  Copyright: 2008-2019
**    Marc Wathelet
**    Marc Wathelet (LGIT, Grenoble, France)
**
***************************************************************************/

#include "ExpandTabWidget.h"
#include "ExpandTabTitle.h"
#include "Settings.h"

namespace QGpGuiTools {

/*!
  \class ExpandTabWidget ExpandTabWidget.h
  \brief Brief description of class still missing

  Full description of class still missing
*/

/*!
  Description of constructor still missing
*/
ExpandTabWidget::ExpandTabWidget(QWidget * parent)
    : QWidget(parent)
{
  TRACE;
  _vboxLayout=new QVBoxLayout(this);
  _vboxLayout->setSpacing(0);
  _vboxLayout->setContentsMargins(0, 0, 0 ,0);
}

ExpandTabWidget::~ExpandTabWidget()
{
}

ExpandTabTitle * ExpandTabWidget::find(QWidget * w, int& index)
{
  int n=_vboxLayout->count();
  for(index=0; index<n; index++ ) {
    ExpandTabTitle * t=static_cast<ExpandTabTitle *>(_vboxLayout->itemAt(index)->widget());
    if(t->content()==w) return t;
    if(t->docked()) index++;
  }
  return 0;
}

void ExpandTabWidget::addWidget(QString title, QWidget * w)
{
  TRACE;
  ExpandTabTitle * t=new ExpandTabTitle(this);
  t->setTitle(title);
  w->layout()->setContentsMargins(9, 9, 9 ,9);
  t->setContent(w);
  t->setObjectName(w->objectName());
  connect(t, SIGNAL(moveUp()), this, SLOT(moveWidgetUp()));
  connect(t, SIGNAL(moveDown()), this, SLOT(moveWidgetDown()));
  connect(t, SIGNAL(dock()), this, SLOT(dockWidget()));
  connect(t, SIGNAL(addActions(QMenu *)), this, SLOT(addContextActions(QMenu *)));
  connect(t, SIGNAL(resize(int)), this, SLOT(resize(int)));
  _vboxLayout->addWidget(t);
  _vboxLayout->addWidget(w); // docked by default
}

void ExpandTabWidget::takeWidget(QWidget * w)
{
  TRACE;
  int index;
  ExpandTabTitle * t=find(w, index);
  if(t) {
    if(t->docked()) {
      delete _vboxLayout->takeAt(index+1); // Content: QLayoutItem deleted, widget remains
    }
    delete _vboxLayout->takeAt(index);     // Title item, widget still there
    t->content()->setParent(0);
    delete t;
  }
}

QList<QWidget *> ExpandTabWidget::takeWidgets()
{
  TRACE;
  QList<QWidget *> wList;
  while(!_vboxLayout->isEmpty()) {
    ExpandTabTitle * t=static_cast<ExpandTabTitle *>(_vboxLayout->itemAt(0)->widget());
    if(t->docked()) {
      delete _vboxLayout->takeAt(1);   // Content: QLayoutItem deleted, widget remains
    }
    delete _vboxLayout->takeAt(0);     // Title item, widget still there
    wList.append(t->content());
    t->content()->setParent(0);
    delete t;
  }
  return wList;
}

void ExpandTabWidget::moveWidgetUp()
{
  TRACE;
  ExpandTabTitle * t=qobject_cast<ExpandTabTitle *>(sender());
  if(!t) return;

  int index=_vboxLayout->indexOf(t);
  if(index>0) {
    delete _vboxLayout->takeAt(index); // Title
    if(t->docked())
      delete _vboxLayout->takeAt(index); // Content
    ExpandTabTitle * tbefore=qobject_cast<ExpandTabTitle *>(_vboxLayout->itemAt(index-1)->widget());
    if(tbefore && !tbefore->docked()) {
      if(t->docked())
        _vboxLayout->insertWidget(index-1, t->content());
      _vboxLayout->insertWidget(index-1, t);
    } else {
      if(t->docked())
        _vboxLayout->insertWidget(index-2, t->content());
      _vboxLayout->insertWidget(index-2, t);
    }
  }
}

void ExpandTabWidget::moveWidgetDown()
{
  TRACE;
  ExpandTabTitle * t=qobject_cast<ExpandTabTitle *>(sender());
  if(!t) return;

  int index=_vboxLayout->indexOf(t);
  // Check if last item
  bool notLastItem;
  if(t->docked()) {
    notLastItem=index<_vboxLayout->count()-2;
  } else {
    notLastItem=index<_vboxLayout->count()-1;
  }
  if(notLastItem) {
    delete _vboxLayout->takeAt(index); // Title
    if(t->docked())
      delete _vboxLayout->takeAt(index); // Content
    ExpandTabTitle * tafter=qobject_cast<ExpandTabTitle *>(_vboxLayout->itemAt(index+1)->widget());
    if(tafter && !tafter->docked()) {
      if(t->docked())
        _vboxLayout->insertWidget(index+1, t->content());
      _vboxLayout->insertWidget(index+1, t);
    } else {
      if(t->docked())
        _vboxLayout->insertWidget(index+2, t->content());
      _vboxLayout->insertWidget(index+2, t);
    }
  }
}

void ExpandTabWidget::dockWidget(ExpandTabTitle * t)
{
  if(!t) {
    t=qobject_cast<ExpandTabTitle *>(sender());
    if(!t) return;
  }

  int index=_vboxLayout->indexOf(t);
  if(index<_vboxLayout->count()) {
    if(t->docked()) {
      _vboxLayout->takeAt(index+1); // Content
      QWidget * c=t->content();
      c->layout()->invalidate();
      c->setWindowTitle(_titlePrefix + t->title());
      c->setParent(QApplication::activeWindow());
      c->setWindowFlags(Qt::Tool);
      int h=c->height();
      c->setMinimumSize(c->minimumSize().width(), 0);
      Settings::getRect(c, objectName()+c->objectName());
      c->resize(c->width(), h);
      t->setDocked(false);
      t->setExpanded(true);
    } else {
      QWidget * c=t->content();
      Settings::setRect(c, objectName()+c->objectName());
      c->setMinimumSize(c->minimumSize().width(), c->height());
      _vboxLayout->insertWidget(index+1, c);
      c->setWindowFlags(Qt::Widget);
      t->setDocked(true);
    }
  }
}

void ExpandTabWidget::resize(int dy)
{
  TRACE;
  ExpandTabTitle * t=qobject_cast<ExpandTabTitle *>(sender());
  if(!t) return;
  int index=_vboxLayout->indexOf(t);
  if(index>=_vboxLayout->count()) return;
  if(index<2) return; // Do not resize first title
  ExpandTabTitle * tBefore=qobject_cast<ExpandTabTitle *>(_vboxLayout->itemAt(index-2)->widget());
  if(!tBefore || !tBefore->docked()) return;
  // Now we are sure that tBefore ->content() can be resized
  QWidget * w=_vboxLayout->itemAt(index-1)->widget();
  QSize minSize=w->minimumSize();
  int h=minSize.height();
  if(h==0) h=w->height();
  h += dy;
  if(h<w->minimumSizeHint().height()) h=w->minimumSizeHint().height();
  if(h>w->maximumSize().height()) h=w->maximumSize().height();
  w->setMinimumSize(minSize.width(), h);
}

bool ExpandTabWidget::isDocked(QWidget * w)
{
  int index;
  ExpandTabTitle * t=find(w, index);
  return t ? t->docked() : false;
}

void ExpandTabWidget::restoreState(const QByteArray& state)
{
  TRACE;
  QDataStream s(const_cast<QByteArray *>(&state), QIODevice::ReadOnly);
  int n;
  s >> n;
  if(n<=0) return;
  QList<ExpandTabTitle *> wList=findChildren<ExpandTabTitle *>();
  // Tranfer to a Hash table to map from ObjectName to object pointers
  QHash<QString, ExpandTabTitle *> name2ptr;
  for(QList<ExpandTabTitle *>::iterator it=wList.begin(); it!=wList.end(); ++it) {
    name2ptr.insert((*it)->objectName(), *it);
  }
  // Reset layout to allow re-ordering of widgets
  delete _vboxLayout;
  _vboxLayout=new QVBoxLayout(this);
  _vboxLayout->setSpacing(0);
  _vboxLayout->setContentsMargins(0, 0, 0 ,0);
  for(int i=0; i<n; i++ ) {
    bool expanded, docked;
    int h;
    QString name;
    s >> expanded;
    s >> docked;
    s >> h;
    s >> name;
    if(name2ptr.contains(name)) {
      ExpandTabTitle * t=name2ptr[name];
      _vboxLayout->addWidget(t);
      t->setExpanded(expanded);
      QWidget * w=t->content();
      if(docked) {
        _vboxLayout->addWidget(t->content());
        if(! (w->windowFlags() & Qt::Widget)) w->setWindowFlags(Qt::Widget);
        w->setMinimumSize(w->minimumSize().width(), h);
        t->setDocked(true);
      } else {
        QWidget * w=t->content();
        w->setWindowTitle(_titlePrefix + t->title());
        w->setParent(QApplication::activeWindow());
        if(! (w->windowFlags() & Qt::Tool)) w->setWindowFlags(Qt::Tool);
        Settings::getRect(t->content(), objectName()+t->content()->objectName());
        w->resize(w->width(), h);
        t->setDocked(false);
        t->setExpanded(true);
      }
      name2ptr.remove(name);
    }
  }
  // In case of error in widget list, there may be some remaining widgets, we add them at the end
  for(QHash<QString, ExpandTabTitle *>::iterator it=name2ptr.begin();it!=name2ptr.end(); ++it) {
    ExpandTabTitle * t=it.value();
    _vboxLayout->addWidget(t);
    _vboxLayout->addWidget(t->content());
    t->setExpanded(true);
    t->setDocked(true);
  }
}

QByteArray ExpandTabWidget::saveState() const
{
  TRACE;
  QByteArray state;
  QDataStream s(&state, QIODevice::WriteOnly);
  int n=_vboxLayout->count();
  s << n;
  for(int i=0;i<n;i++) {
    ExpandTabTitle * t=qobject_cast<ExpandTabTitle *>(_vboxLayout->itemAt(i)->widget());
    if(t) {
      s << t->expanded();
      s << t->docked();
      s << t->content()->height();
      s << t->objectName();
      if(t->docked()) {
        i++;
      } else {
        Settings::setRect(t->content(), objectName()+t->content()->objectName());
      }
    }
  }
  return state;
}

void ExpandTabWidget::expandAll()
{
  QList<ExpandTabTitle *> wList=findChildren<ExpandTabTitle *>();
  for(QList<ExpandTabTitle *>::iterator it=wList.begin(); it!=wList.end(); ++it) {
    (*it)->setExpanded(true);
  }
}

void ExpandTabWidget::collapseAll()
{
  QList<ExpandTabTitle *> wList=findChildren<ExpandTabTitle *>();
  for(QList<ExpandTabTitle *>::iterator it=wList.begin(); it!=wList.end(); ++it) {
    (*it)->setExpanded(false);
  }
}

uint ExpandTabWidget::key() const
{
  uint k=0;
  int n=_vboxLayout->count();
  for(int i=0; i<n;i++) {
    ExpandTabTitle * t=qobject_cast<ExpandTabTitle *>(_vboxLayout->itemAt(i)->widget());
    if(t) {
      QString name=t->content()->objectName();
      k+=qHash(name);
      if(t->docked()) i++;
    }
  }
  return k;
}

void ExpandTabWidget::addContextActions(QMenu * m)
{
  ExpandTabTitle * t=qobject_cast<ExpandTabTitle *>(sender());
  if(!t) return;

  m->addAction(tr( "Expand all" ), this, SLOT(expandAll()) );
  m->addAction(tr( "Collapse all" ), this, SLOT(collapseAll()) );
  m->addSeparator();
  /*for(QList<QWidget *
  QAction * a=new QAction(title, this);
  connect(a, SIGNAL(triggered()), this, SLOT(scrollTo()) );
  QByteArray wPtr(( const char * ) & w, sizeof(QWidget * ));
  a->setData(wPtr);
  m->addAction(a);*/
}

} // namespace QGpGuiTools
