/***************************** LICENSE START ***********************************

 Copyright 2012 ECMWF and INPE. This software is distributed under the terms
 of the Apache License version 2.0. In applying this license, ECMWF does not
 waive the privileges and immunities granted to it by virtue of its status as
 an Intergovernmental Organization or submit itself to any jurisdiction.

 ***************************** LICENSE END *************************************/

#include <QApplication>
#include <QBrush>
#include <QColor>
#include <QDebug>
#include <QHBoxLayout>
#include <QLabel>
#include <QMimeData>
#include <QMouseEvent>
#include <QPainter>
#include <QPushButton>
#include <QSlider>
#include <QStringList>
#include <QTextDocument>

#include "MvPath.hpp"
#include "Presentable.h"
#include "SuperPage.h"
#include "Page.h"
#include "Root.h"

#include "MvQContentsModel.h"

//===============================
//
//  MvQContentsNode
//
//===============================


MvQContentsNode::MvQContentsNode(Presentable&, MvQContentsNode* parent, Type type)
{
    //presentable_=pr;
    parent_ = parent;
    if (type == DisplayTitleType) {
        name_ = QObject::tr("Global settings");
    }
    else {
        name_ = QObject::tr("Plot");
        //name_=QString::fromStdString(pr.Name());
    }
    type_ = type;
}

MvQContentsNode::MvQContentsNode(MvIcon& pr, MvQContentsNode* parent, Type type)
{
    //presentable_=pr;
    parent_             = parent;
    name_               = (const char*)pr.IconName();
    Cached iconFileName = MakeIconPath(pr.IconClass());
    pixmap_             = QPixmap::fromImage(QImage((const char*)iconFileName, "xpm")).scaled(QSize(22, 22), Qt::KeepAspectRatio, Qt::SmoothTransformation);
    type_               = type;
}

MvQContentsNode::MvQContentsNode(QString str, MvQContentsNode* parent, Type type)
{
    //presentable_=pr;
    parent_ = parent;
    name_   = str;
    type_   = type;
}

MvQContentsNode* MvQContentsNode::addChild(Presentable& sp, Type type)
{
    MvQContentsNode* node = new MvQContentsNode(sp, this, type);
    children_ << node;
    return node;
}

MvQContentsNode* MvQContentsNode::addChild(MvIcon& icon, Type type)
{
    MvQContentsNode* node = new MvQContentsNode(icon, this, type);
    children_ << node;
    return node;
}

MvQContentsNode* MvQContentsNode::addChild(QString str, Type type)
{
    MvQContentsNode* node = new MvQContentsNode(str, this, type);
    children_ << node;
    return node;
}


//===============================
//
//  MvQContentsTree
//
//===============================

MvQContentsTree::MvQContentsTree()
{
    root_ = new MvQContentsNode(Root::Instance(), 0, MvQContentsNode::NoType);
    Root::Instance().Visit(*this);
}

void MvQContentsTree::Visit(SuperPage& sp)
{
    //Create a nofde for the superpage
    MvQContentsNode* node = root_->addChild(sp, MvQContentsNode::DisplayTitleType);

    //Get the list of visdefs and mtexts
    MvIconList objList = iconList(sp);
    MvListCursor cr;
    for (cr = objList.begin(); cr != objList.end(); cr++) {
        node->addChild(*cr, MvQContentsNode::IconType);
    }
}

void MvQContentsTree::Visit(Page& page)
{
    //need to find the parent!!!!!!!!!
    MvQContentsNode* node = root_->addChild(page, MvQContentsNode::PageTitleType);

    // Retrieve the Icon Data Base
    MvIconDataBase& dataBase = page.IconDataBase();

    // Create the View icon associated to the Page
    MvRequest reqview = page.Request().getSubrequest("VIEW");
    //ensure ( reqview != 0 );
    MvIcon viewIcon(reqview);
    node->addChild(viewIcon, MvQContentsNode::IconType);

    // Describe the objects associated to the Page
    MvIconList objList = iconList(page);
    MvListCursor cr;
    for (cr = objList.begin(); cr != objList.end(); cr++) {
        node->addChild(*cr, MvQContentsNode::IconType);
    }


    // Retrieve DataUnits related to the Page
    MvIconList duList;
    //dataBase.DataUnitListByPresentableId (page.Id(), duList );
    dataBase.RetrieveIcon(PRES_DATAUNIT_REL, page.Id(), duList);

    MvListCursor duCursor;
    MvQContentsNode* duNode;

    int dataCnt = 1;
    for (duCursor = duList.begin(); duCursor != duList.end(); duCursor++) {
        // Find out the visdefs associated to this dataunit
        objList.clear();
        dataBase.RetrieveVisDefList((*duCursor), objList);

        duNode = node->addChild("Data " + QString::number(dataCnt), MvQContentsNode::DataTitleType);
        duNode->addChild(*duCursor, MvQContentsNode::IconType);
        //duNode->addData(*duCursor);
        for (cr = objList.begin(); cr != objList.end(); cr++) {
            duNode->addChild(*cr, MvQContentsNode::IconType);
            //duNode->addData(*cr);
        }

        dataCnt++;
    }
}

MvIconList MvQContentsTree::iconList(Presentable& treeNode)
{
    // Retrieve the Icon Data Base
    MvIconDataBase& dataBase = treeNode.IconDataBase();

    // Find the list of objects associated to the Presentable
    MvIconList objList;
    //dataBase.VisDefListByPresentableId ( treeNode.Id(), objList );
    //dataBase.TextListByPresentableId ( treeNode.Id(), objList );
    dataBase.RetrieveIcon(PRES_VISDEF_REL, treeNode.Id(), objList);
    dataBase.RetrieveIcon(PRES_TEXT_REL, treeNode.Id(), objList);

    return objList;
}


//======================================
// Item delegate
//======================================

MvQContentsDelegate::MvQContentsDelegate(QWidget* parent) :
    QStyledItemDelegate(parent)
{
}

void MvQContentsDelegate::paint(QPainter* painter, const QStyleOptionViewItem& option,
                                const QModelIndex& index) const
{
    if (index.data(Qt::UserRole).toInt() > 0) {
        QStyleOptionViewItemV4 options = option;
        initStyleOption(&options, index);

        //const QStyle *style = vopt.widget ? vopt.widget->style() : QApplication::style();

        painter->save();

        if (index.data(Qt::UserRole).toInt() == 1) {
            //painter->fillRect(options.rect, QColor(188,215,255));
            //painter->fillRect(options.rect, QColor(233,233,255));
            painter->fillRect(options.rect, QColor(187, 199, 203));
            painter->setPen(QColor(255, 255, 255));
            //painter->setPen(QColor(200,200,200));
            //painter->drawRect(options.rect);
        }
        else if (index.data(Qt::UserRole).toInt() == 2) {
            painter->fillRect(options.rect, QColor(194, 224, 233));
            //painter->fillRect(options.rect, QColor(245,245,255));
            //painter->fillRect(options.rect, QColor(188,215,255));
            painter->setPen(QColor(255, 255, 255));
            //painter->setPen(QColor(200,200,200));
            //painter->drawRect(options.rect);
        }
        else if (index.data(Qt::UserRole).toInt() == 3) {
            //painter->fillRect(options.rect, QColor(245,245,255));
            painter->fillRect(options.rect, QColor(239, 239, 239));
            painter->setPen(QColor(255, 255, 255));
            //painter->drawRect(options.rect);
        }

        //painter->setPen(QColor(221,221,221));
        painter->drawRect(options.rect);

        //painter->setPen(QColor(200,200,200));
        //painter->drawLine(options.rect.topLeft(),options.rect.topRight());
        //painter->drawLine(options.rect.bottomLeft(),options.rect.bottomRight());

        QTextDocument doc;
        doc.setHtml(options.text);

        options.text = "";
        options.widget->style()->drawControl(QStyle::CE_ItemViewItem, &options, painter);

        painter->translate(options.rect.left(), options.rect.top());
        QRect clip(0, 0, options.rect.width(), options.rect.height());
        doc.drawContents(painter, clip);

        painter->restore();
    }
    else {
        QStyledItemDelegate::paint(painter, option, index);
    }


    /*	QStyleOptionViewItemV4 vopt(option);
   	initStyleOption(&vopt, index);

	//Save painter state
	painter->save();
	
	//Draw separator line
	painter->setPen(QColor(230,230,230));
	painter->drawLine(option.rect.bottomLeft(),option.rect.bottomRight());

	//restore painter state
	painter->restore();*/

    /*if(index.column() == 0)
	{
		QStyleOptionViewItemV4 vopt(option);
   		initStyleOption(&vopt, index);
   
    		const QStyle *style = vopt.widget ? vopt.widget->style() : QApplication::style();
    		const QWidget* widget = vopt.widget;

		int height=option.rect.height();

		//vopt.text=QString();
		//vopt.icon=QIcon();		

		//We render everything with the default method
  		style->drawControl(QStyle::CE_ItemViewItem, &vopt, painter, widget);
	
		//Get current values from model
		QString txt=index.data(Qt::DisplayRole).toString();
		QPixmap pixmap=index.data(Qt::DecorationRole).value<QPixmap>();
		QBrush bg=index.data(Qt::BackgroundRole).value<QBrush>();
	
		//Save painter state
		painter->save();

		//Highlight
		//if (option.state & QStyle::State_HasFocus)
             	//	painter->fillRect(option.rect, option.palette.highlight());
	
	        //QRect checkRect = style->subElementRect(QStyle::SE_ItemViewItemCheckIndicator,&vopt, widget);
                QRect iconRect = style->subElementRect(QStyle::SE_ItemViewItemDecoration, &vopt, widget);
                //QRect textRect = style-> subElementRect(QStyle::SE_ItemViewItemText, &vopt, widget);

		//Draw icon border
		painter->setPen(QColor(230,230,230));
		painter->drawRect(iconRect);

		//Text
		//QString text=index.data(Qt::DisplayRole).toString();
		//QRect textRect(iconRect.x()+iconRect.width()+10,option.rect.y()+5,
		//	       option.rect.width()-(iconRect.x()+iconRect.width()+5)-10, height/2-5);
		
		//painter->setPen(Qt::black);
		//painter->drawText(textRect,Qt::AlignLeft,text);

		//Draw separator line
		painter->setPen(QColor(230,230,230));
		painter->drawLine(option.rect.bottomLeft(),option.rect.bottomRight());

		//restore painter state
		painter->restore();			
	}		
	else
	{		
		QStyledItemDelegate::paint(painter,option,index);
	}*/
}

/*QSize MvQLayerDelegate::sizeHint(const QStyleOptionViewItem & option, const QModelIndex & index ) const
{
	QSize size=QStyledItemDelegate::sizeHint(option,index);
	size.setHeight(itemHeight_);
	return size;
}*/

QSize MvQContentsDelegate::sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const
{
    if (index.data(Qt::UserRole).toInt() == 1 || index.data(Qt::UserRole).toInt() == 2 || index.data(Qt::UserRole).toInt() == 3) {
        QStyleOptionViewItemV4 options = option;
        initStyleOption(&options, index);

        QTextDocument doc;
        doc.setHtml(options.text);
        doc.setTextWidth(options.rect.width());
        return QSize(doc.idealWidth(), doc.size().height()) + QSize(0, 6);
    }

    return QStyledItemDelegate::sizeHint(option, index) + QSize(0, 6);
}

//===============================
//
//  MvQContentsModel
//
//===============================


MvQContentsModel::MvQContentsModel()
{
    root_ = 0;
}

void MvQContentsModel::dataIsAboutToChange()
{
    beginResetModel();
}

void MvQContentsModel::setRootNode(MvQContentsNode* root)
{
    root_ = root;

    //Reset the model (views will be notified)
    endResetModel();
}


int MvQContentsModel::columnCount(const QModelIndex& /* parent */) const
{
    return 1;
}

int MvQContentsModel::rowCount(const QModelIndex& parent) const
{
    if (!root_)
        return 0;

    MvQContentsNode* parentNode = nodeFromIndex(parent);
    if (!parentNode)
        return 0;


    //qDebug() << "rowNum" << parent << parentNode->children().count();

    return parentNode->children().count();

    /*Presentable *parentNode=nodeFromIndex(parent);
	if(!parentNode)
		return 0;

	qDebug() << "rowNum" << parent << parentNode->NrOfChildren();
	
	return parentNode->NrOfChildren(); */
}


QVariant MvQContentsModel::data(const QModelIndex& index, int role) const
{
    if (!index.isValid() ||
        (role != Qt::DisplayRole && role != Qt::ToolTipRole && role != Qt::DecorationRole &&
         role != Qt::BackgroundRole && role != Qt::UserRole)) {
        return QVariant();
    }

    MvQContentsNode* node = nodeFromIndex(index);
    if (!node)
        return QVariant();

    //qDebug() << "data" << index << node->name();

    if (role == Qt::ToolTipRole) {
        //QString s="Title: " + node->displayValue() + "<br>" +
        //	  "Name:  " + node->value();

        //return s;
        return QVariant();
    }
    else if (role == Qt::DecorationRole) {
        if (!node->pixmap().isNull())
            return node->pixmap();
        else
            return QVariant();
    }
    /*else if(role  == Qt::BackgroundRole)
	{
	  	if(node->parent() && node->parent()->name() == "Data")
		{
		  	return QBrush(QColor(245,245,255));
		}
		else
			return QVariant();
		
	}*/
    else if (role == Qt::UserRole) {
        if (node->type() == MvQContentsNode::DisplayTitleType) {
            return 1;
        }
        else if (node->type() == MvQContentsNode::PageTitleType) {
            return 2;
        }
        else if (node->type() == MvQContentsNode::DataTitleType) {
            return 3;
        }
        else {
            return 0;
        }
    }
    else {
        if (node->type() == MvQContentsNode::DataTitleType ||
            node->type() == MvQContentsNode::DisplayTitleType ||
            node->type() == MvQContentsNode::PageTitleType) {
            return "<b>" + node->name() + "</b>";
        }
        else {
            return node->name();
        }
    }

    return QVariant();
}


QVariant MvQContentsModel::headerData(const int section, const Qt::Orientation orient, const int role) const
{
    if (orient != Qt::Horizontal || role != Qt::DisplayRole)
        return QAbstractItemModel::headerData(section, orient, role);

    switch (section) {
        case 0:
            return "Layer title";
    }

    return QVariant();
}

QModelIndex MvQContentsModel::index(int row, int column, const QModelIndex& parent) const
{
    if (!root_ || row < 0 || column < 0) {
        return QModelIndex();
    }


    MvQContentsNode* parentNode = nodeFromIndex(parent);
    MvQContentsNode* childNode  = parentNode->children().at(row);

    if (!childNode)
        return QModelIndex();

    //qDebug() << "index" <<  row << column << parent << createIndex(row,column,childNode);
    return createIndex(row, column, childNode);
}

MvQContentsNode* MvQContentsModel::nodeFromIndex(const QModelIndex& index) const
{
    if (index.isValid()) {
        //qDebug() << "NodeFromIndex" << index <<  static_cast<Presentable*>(index.internalPointer())->Name().c_str();
        return static_cast<MvQContentsNode*>(index.internalPointer());
    }
    else {
        //qDebug() << "NodeFromIndex root" << index << root_->Name().c_str();
        return root_;
    }
}

QModelIndex MvQContentsModel::parent(const QModelIndex& child) const
{
    //qDebug() << "parent" << child;

    MvQContentsNode* node = nodeFromIndex(child);
    if (!node || node == root_)
        return QModelIndex();

    MvQContentsNode* parentNode = node->parent();
    if (!parentNode || parentNode == root_)
        return QModelIndex();
    //else
    //qDebug() << "child's parent" << parentNode->name();

    MvQContentsNode* grandParentNode = parentNode->parent();
    if (!grandParentNode)
        return QModelIndex();
    else {
        //qDebug() << "grandParent" << grandParentNode->name();
    }

    int row = grandParentNode->children().indexOf(parentNode);
    //qDebug() << "parent return" << createIndex(row,0,parentNode);


    return createIndex(row, 0, parentNode);
}

QModelIndex MvQContentsModel::indexFromNode(MvQContentsNode* node) const
{
    if (node != 0 && node->parent() != 0) {
        int row = node->parent()->children().indexOf(node);
        if (row != -1) {
            return createIndex(row, 0, node);
            //qDebug() << "indexFromNode" << node->name() << createIndex(row,0,node);
        }
    }

    return QModelIndex();
}
