/***************************************************************************
 *   Copyright (C) 2012 by Savoir-Faire Linux                              *
 *   @author: Emmanuel Lepage Vallee <elv1313@gmail.com>                   *
 *                                                                         *
 * This library is free software; you can redistribute it and/or           *
 * modify it under the terms of the GNU Library General Public             *
 * License version 2 as published by the Free Software Foundation.         *
 *                                                                         *
 * This library 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       *
 * Library General Public License for more details.                        *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program.  If not, see <http://www.gnu.org/licenses/>. *
 **************************************************************************/
#include "categorizedtreeview.h"

//Qt
#include <QtWidgets/QStyledItemDelegate>
#include <QtGui/QPainter>
#include <QtGui/QContextMenuEvent>
#include <QtGui/QBrush>
#include <QtGui/QDrag>
#include <QtCore/QMimeData>
#include <QtCore/QEvent>

//KDE
#include <KLocalizedString>

//Ring
#include <call.h>
#include <categorizedcontactmodel.h>
#include <categorizedhistorymodel.h>
#include <mime.h>

///Constructor
CategorizedTreeView::CategorizedTreeView(QWidget *parent)
  : CategorizedTree(parent),m_Type(CategorizedTreeView::ViewType::Other),
  m_InitSignals(false)
{
}

CategorizedTreeView::~CategorizedTreeView()
{

}

void CategorizedTreeView::setModel ( QAbstractItemModel * model )
{
   connect(model,&QAbstractItemModel::rowsInserted,this,&CategorizedTreeView::slotExpandInserted);
   QTreeView::setModel(model);
}

void CategorizedTreeView::contextMenuEvent ( QContextMenuEvent * e ) {
  const QModelIndex index = indexAt(e->pos());

  //There is currently nothing to do when right-clicking empty space
  if (index.isValid()) {
   emit contextMenuRequest(index);
   e->accept();
  }
}


void CategorizedTreeView::dragLeaveEvent( QDragLeaveEvent *e)
{
   if (!m_InitSignals)
      initSignals();
   if (m_HoverIdx.isValid()) {
      ((QAbstractItemModel*)m_HoverIdx.model())->setData(m_HoverIdx,-1,300);
      m_HoverIdx = QModelIndex();
   }
   QTreeView::dragLeaveEvent(e);
}

void CategorizedTreeView::dragEnterEvent( QDragEnterEvent *e)
{
   if (!m_InitSignals)
      initSignals();
   const auto idxAt = indexAt(e->pos());
   const CallModel::DropPayloadType type = payloadType(e->mimeData());
   bool accept = false;
   switch (m_Type) {
      case ViewType::Other:
         break;
      case ViewType::Person:
         accept = CategorizedContactModel::acceptedPayloadTypes() & type;
         break;
      case ViewType::History:
         accept = CategorizedHistoryModel::instance().acceptedPayloadTypes() & type;
         break;
      case ViewType::BookMark:
         break;
      case ViewType::Call:
         accept = CallModel::instance().acceptedPayloadTypes() & type;
         break;
   };
   if (accept) {
      e->acceptProposedAction();
      e->accept();
      if (idxAt.isValid() && idxAt.parent().isValid()) {
         ((QAbstractItemModel*)idxAt.model())->setData(idxAt,1,300);
         m_HoverIdx = idxAt;
      }
   }
}

void CategorizedTreeView::dropEvent( QDropEvent* e )
{
   if (!m_InitSignals)
      initSignals();
   const QModelIndex  newIdx = indexAt(e->pos());
   //HACK client get invalid indexes unless I do this, find out why

   //Clear drop state
   cancelHoverState();

   model()->dropMimeData(e->mimeData(), Qt::TargetMoveAction, newIdx.row(), newIdx.column(), newIdx.parent());
}

void CategorizedTreeView::dragMoveEvent( QDragMoveEvent *e)
{
   if (!m_InitSignals)
      initSignals();
   e->acceptProposedAction();
}

void CategorizedTreeView::setDelegate(QStyledItemDelegate* delegate)
{
   if (!m_InitSignals)
      initSignals();
   setItemDelegate(delegate);
}


void CategorizedTreeView::mouseDoubleClickEvent(QMouseEvent* event)
{
   const auto idxAt = indexAt(event->pos());
   emit itemDoubleClicked(idxAt);
//    if (m_Type != ViewType::Person)
      QTreeView::mouseDoubleClickEvent(event);
}

///This function allow for custom rendering of the drag widget
void CategorizedTreeView::startDrag(Qt::DropActions supportedActions)
{
   if (m_Type == CategorizedTreeView::ViewType::Call) {
//     Q_D(QAbstractItemView);
      const auto index = selectionModel()->currentIndex();
      if (index.isValid()) {
         QModelIndexList list;
         list << index;
         QMimeData *data = model()->mimeData(list);
         if (!data)
            return;

         //Execute the drag
//          QDrag *drag = new QDrag(this);
//          drag->setPixmap(ConferenceDelegate::getDragPixmap(this,index));
//          drag->setMimeData(data);
//          drag->setHotSpot(QCursor::pos() - QCursor::pos());
//          const Qt::DropAction defaultDropAction = Qt::IgnoreAction;
//          drag->exec(supportedActions, defaultDropAction);
      }
   }
   else {
      const auto index = selectionModel()->currentIndex();
      if (index.isValid()) {
         QModelIndexList list;
         list << index;
         QMimeData *data = model()->mimeData(list);
         if (!data)
            return;

         //Create the pixmap
         QStyleOptionViewItem option;
         option.locale = locale();
         option.widget = this;
         option.state = QStyle::State_Selected | QStyle::State_Enabled | QStyle::State_Active | QStyle::State_Small;
         option.rect = QRect(0,0,width(),height());
         QSize size = itemDelegate()->sizeHint(option,index);
         QSize itemSize = size;
         for (int i=0;i<model()->rowCount(index);i++) {
            size.setHeight(size.height()+itemDelegate()->sizeHint(option,index.child(i,0)).height());
         }

         //Setup the painter
         QPixmap pixmap(width(),size.height());
         QPainter customPainter(&pixmap);
         customPainter.eraseRect(option.rect);
         customPainter.setCompositionMode(QPainter::CompositionMode_Clear);
         customPainter.fillRect(option.rect,QBrush(Qt::white));
         customPainter.setCompositionMode(QPainter::CompositionMode_SourceOver);

         //Draw the parent
         option.rect = QRect(0,0,width(),itemSize.height());
         itemDelegate()->paint(&customPainter, option, index);

         //Draw the children
         for (int i=0;i<model()->rowCount(index);i++) {
            itemSize.setHeight(itemDelegate()->sizeHint(option,index.child(i,0)).height());
            option.rect = QRect(10,option.rect.y()+option.rect.height(),width()-20,itemSize.height());
            option.state = QStyle::State_Enabled | QStyle::State_Active | QStyle::State_Small;
            itemDelegate()->paint(&customPainter, option, index.child(i,0));
         }

         //Execute the drag
         QDrag *drag = new QDrag(this);
         drag->setPixmap(pixmap);
         drag->setMimeData(data);
         drag->setHotSpot(QCursor::pos() - QCursor::pos());
         const Qt::DropAction defaultDropAction = Qt::IgnoreAction;
         drag->exec(supportedActions, defaultDropAction);
      }
//       QAbstractItemView::startDrag(supportedActions);
   }
}

bool CategorizedTreeView::edit(const QModelIndex& index, EditTrigger trigger, QEvent* event)
{
   if (state() == QAbstractItemView::EditingState) {
      const Call::LifeCycleState current = qvariant_cast<Call::LifeCycleState>(index.data(static_cast<int>(Call::Role::LifeCycleState)));
      return !(current != Call::LifeCycleState::CREATION);
   }
   return QTreeView::edit(index,trigger,event);
}

CallModel::DropPayloadType CategorizedTreeView::payloadType(const QMimeData* data)
{
   if (data->hasFormat(RingMimes::CALLID))
      return CallModel::DropPayloadType::CALL;
   else if (data->hasFormat(RingMimes::CONTACT))
      return CallModel::DropPayloadType::CONTACT;
   else if (data->hasFormat(RingMimes::HISTORYID))
      return CallModel::DropPayloadType::HISTORY;
   else if (data->hasFormat(RingMimes::PHONENUMBER))
      return CallModel::DropPayloadType::NUMBER;
   else if (data->hasFormat(RingMimes::PLAIN_TEXT))
      return CallModel::DropPayloadType::TEXT;
   else
      return CallModel::DropPayloadType::NONE;
}

void CategorizedTreeView::cancelHoverState()
{
   if (m_HoverIdx.isValid()) {
      //Prevent recursion
      const QModelIndex oldIdx = m_HoverIdx;
      m_HoverIdx = QModelIndex();
      ((QAbstractItemModel*)oldIdx.model())->setData(oldIdx,-1,static_cast<int>(Call::Role::DropState));
   }
}

void CategorizedTreeView::setHoverState(const QModelIndex& idx)
{
   if (idx != m_HoverIdx) {
      cancelHoverState();
      model()->setData(idx,1,static_cast<int>(Call::Role::DropState));
      m_HoverIdx = idx;
   }
}

void CategorizedTreeView::initSignals()
{
   if (model()) {
      connect(model(),&QAbstractItemModel::layoutChanged,this,&CategorizedTreeView::cancelHoverState);
   }
   m_InitSignals = true;
}

void CategorizedTreeView::setDirty(const QRect &rect)
{
   setDirtyRegion(rect);
}

void CategorizedTreeView::slotExpandInserted(const QModelIndex& parentIdx,int start, int end)
{
   for (int i=start;i<=end;i++) {
      setExpanded(model()->index(i,0,parentIdx),true);
   }
}

void CategorizedTreeView::forwardInput(QKeyEvent* e)
{
   keyPressEvent(e);
}

// kate: space-indent on; indent-width 3; replace-tabs on;
