/***************************************************************************
 *   Copyright (C) 2005-08 by the Quassel Project                          *
 *   devel@quassel-irc.org                                                 *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) version 3.                                           *
 *                                                                         *
 *   This program 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 General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/

#include "chatviewsearchcontroller.h"

#include <QAbstractItemModel>
#include <QPainter>

#include "chatitem.h"
#include "chatlinemodel.h"
#include "chatscene.h"
#include "messagemodel.h"

ChatViewSearchController::ChatViewSearchController(QObject *parent)
  : QObject(parent),
    _scene(0),
    _caseSensitive(false),
    _searchSenders(false),
    _searchMsgs(true),
    _searchOnlyRegularMsgs(true)
{
}

void ChatViewSearchController::setSearchString(const QString &searchString) {
  QString oldSearchString = _searchString;
  _searchString = searchString;
  if(_scene) {
    if(!searchString.startsWith(oldSearchString) || oldSearchString.isEmpty()) {
      // we can't reuse our all findings... cler the scene and do it all over
      updateHighlights();
    } else {
      // reuse all findings
      updateHighlights(true);
    }
  }
}

 void ChatViewSearchController::setScene(ChatScene *scene) {
  Q_ASSERT(scene);
  if(scene == _scene)
    return;

  if(_scene) {
    disconnect(_scene, 0, this, 0);
    qDeleteAll(_highlightItems);
    _highlightItems.clear();
  }

  _scene = scene;
  if(!scene)
    return;

  connect(_scene, SIGNAL(destroyed()), this, SLOT(sceneDestroyed()));
  updateHighlights();
 }



void ChatViewSearchController::updateHighlights(bool reuse) {
  if(!_scene)
    return;

  QAbstractItemModel *model = _scene->model();
  Q_ASSERT(model);


  QList<ChatLine *> chatLines;
  if(reuse) {
    foreach(SearchHighlightItem *highlightItem, _highlightItems) {
      ChatLine *line = dynamic_cast<ChatLine *>(highlightItem->parentItem());
      if(!line || chatLines.contains(line))
	continue;
      chatLines << line;
    }
  }

  qDeleteAll(_highlightItems);
  _highlightItems.clear();
  Q_ASSERT(_highlightItems.isEmpty());

  if(searchString().isEmpty() || !(_searchSenders || _searchMsgs))
    return;

  if(reuse) {
    QModelIndex index;
    foreach(ChatLine *line, chatLines) {
      if(_searchOnlyRegularMsgs) {
	index = model->index(line->row(), 0);
	if(!checkType((Message::Type)index.data(MessageModel::TypeRole).toInt()))
	  continue;
      }
      highlightLine(line);
    }
  } else {
    // we have to crawl through the data
    QModelIndex index;
    QString plainText;
    int rowCount = model->rowCount();
    for(int row = 0; row < rowCount; row++) {
      ChatLine *line = _scene->chatLine(row);

      if(_searchOnlyRegularMsgs) {
	index = model->index(row, 0);
	if(!checkType((Message::Type)index.data(MessageModel::TypeRole).toInt()))
	  continue;
      }
      highlightLine(line);
    }
  }
}

void ChatViewSearchController::highlightLine(ChatLine *line) {
  QList<ChatItem *> checkItems;
  if(_searchSenders)
    checkItems << &(line->item(MessageModel::SenderColumn));

  if(_searchMsgs)
    checkItems << &(line->item(MessageModel::ContentsColumn));

  foreach(ChatItem *item, checkItems) {
    foreach(QRectF wordRect, item->findWords(searchString(), caseSensitive())) {
      _highlightItems << new SearchHighlightItem(wordRect.adjusted(item->x(), 0, item->x(), 0), line);
    }
  }
}

void ChatViewSearchController::sceneDestroyed() {
  // WARNING: don't call any methods on scene!
  _scene = 0;
  // the items will be automatically deleted when the scene is destroyed
  // so we just have to clear the list;
  _highlightItems.clear();
}

void ChatViewSearchController::setCaseSensitive(bool caseSensitive) {
  if(_caseSensitive == caseSensitive)
    return;

  _caseSensitive = caseSensitive;

  // we can reuse the original search results if the new search
  // parameters are a restriction of the original one
  updateHighlights(caseSensitive);
}

void ChatViewSearchController::setSearchSenders(bool searchSenders) {
  if(_searchSenders == searchSenders)
    return;

  _searchSenders = searchSenders;
  // we can reuse the original search results if the new search
  // parameters are a restriction of the original one
  updateHighlights(!searchSenders);
}

void ChatViewSearchController::setSearchMsgs(bool searchMsgs) {
  if(_searchMsgs == searchMsgs)
    return;

  _searchMsgs = searchMsgs;

  // we can reuse the original search results if the new search
  // parameters are a restriction of the original one
  updateHighlights(!searchMsgs);
}

void ChatViewSearchController::setSearchOnlyRegularMsgs(bool searchOnlyRegularMsgs) {
  if(_searchOnlyRegularMsgs == searchOnlyRegularMsgs)
    return;

  _searchOnlyRegularMsgs = searchOnlyRegularMsgs;

  // we can reuse the original search results if the new search
  // parameters are a restriction of the original one
  updateHighlights(searchOnlyRegularMsgs);
}

SearchHighlightItem::SearchHighlightItem(QRectF wordRect, QGraphicsItem *parent)
  : QGraphicsItem(parent),
    _boundingRect(QRectF(-wordRect.width() / 2, -wordRect.height() / 2, wordRect.width(), wordRect.height()))
{
  setPos(wordRect.x() + wordRect.width() / 2 , wordRect.y() + wordRect.height() / 2);
  scale(1.2, 1.2);
}

void SearchHighlightItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) {
  Q_UNUSED(option);
  Q_UNUSED(widget);

  painter->setPen(QPen(Qt::black, 1.5));
  //painter->setBrush(QColor(127, 133, 250));
  painter->setBrush(QColor(254, 237, 45));
  painter->setRenderHints(QPainter::Antialiasing);
  painter->drawRoundedRect(boundingRect(), 30, 30, Qt::RelativeSize);
}
