/***************************************************************************
 *   Copyright (C) 2004, 2005 Thomas Nagy                                  *
 *   tnagy2^8@yahoo.fr                                                     *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License version 2        *
 *   as published by the Free Software Foundation (see COPYING)            *
 *                                                                         *
 *   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.                          *
 ***************************************************************************/

#include <qpoint.h>
#include <qevent.h>
#include <qdragobject.h>
#include <qtooltip.h>

#include <kcolordialog.h>
#include <kdebug.h>
#include <klocale.h>

#include "aux.h"

#include "settings.h"
#include "DTreeListView.h"
#include "DTreeListItem.h"
#include "DTreeListPopup.h"

#include "DDataControl.h"

class DTreeListTip : public QToolTip
{
	public:
		DTreeListTip(QWidget *v, DTreeListView *p) : QToolTip (v, 0), m_parent(p) {};
	protected:
		virtual void maybeTip(const QPoint &p);
		DTreeListView *m_parent;
};

void DTreeListTip::maybeTip(const QPoint &p)
{
	if (! m_parent) return;

	DTreeListItem* item = dynamic_cast<DTreeListItem*> (m_parent->itemAt(p));
	if (item)
	{
		tip(m_parent->itemRect(item), item->tipText());
	}
}

	DTreeListView::DTreeListView( QWidget* parent, const char* ) 
: KListView(parent), DGuiView(parent), m_menu(NULL)
{
	addColumn(i18n("Concept List"));
	setResizeMode(KListView::AllColumns);
	setSorting(0);
	setSortOrder(Qt::Ascending);

	setDragEnabled(true);
	setAcceptDrops(true);

	setItemsMovable(true);
	setDropVisualizer(true);

	setSelectionModeExt( KListView::Single );

	setRootIsDecorated(true);

	m_tip = new DTreeListTip(viewport(), this);

	connect( this, SIGNAL( moved( QListViewItem *, QListViewItem *, QListViewItem * ) ),
			this, SLOT( applyMoved( QListViewItem *, QListViewItem * , QListViewItem * ) ) );

	connect( this, SIGNAL(selectionChanged()), this, SLOT(changeSelection()) );
}

DTreeListView::~DTreeListView()
{
	//kdWarning()<<"DTreeListView::~DTreeListView()"<<endl;
	unplug();
}

void DTreeListView::changeSelection()
{
	DTreeListItem *item = dynamic_cast<DTreeListItem*> (selectedItem());
	if (!item)
		dataTree()->setItemSelected(DItem::NOITEM, this);
	else
		dataTree()->setItemSelected(item->Id(), this);
}

void DTreeListView::updateSelectedItem(int id, DGuiView *view)
{
	if (view == this) return;

	DTreeListItem *item = dynamic_cast<DTreeListItem*> (selectedItem());

	disconnect( this, SIGNAL(selectionChanged()), this, SLOT(changeSelection()) );

	if (item)
	{
		if (item->Id() != id) setSelected(item, false);
	}

	DTreeListItem *newitem = (DTreeListItem*) Item(id);
	if (newitem)
	{
		setSelected(newitem, true);
		ensureItemVisible(newitem);
	}

	connect( this, SIGNAL(selectionChanged()), this, SLOT(changeSelection()) );
}

void DTreeListView::settingsChanged()
{
	//kdWarning()<<"DTreeListView::settingsChanged"<<endl;
	unsetPalette();
}

void DTreeListView::contentsMousePressEvent(QMouseEvent* me)
{
	KListView::contentsMousePressEvent(me);

	if (m_menu != NULL)
	{
		m_menu->hide();
		disconnect(m_menu, SIGNAL(activated(int)), this, SLOT(applyChoice(int)));
		delete m_menu;
		m_menu = NULL;
	} 

	if (me->button() == RightButton)
	{

		m_menu = new DTreeListPopup(this);
		m_menu->popup(me->globalPos());
		connect(m_menu, SIGNAL(activated(int)), this, SLOT(applyChoice(int)));
	}
}

void DTreeListView::applyChoice(int sel)
{
	DTreeListItem *selitem = (DTreeListItem*) selectedItem();
	switch (sel)
	{
		case DTreeListPopup::e_item:
			dataTree()->newDelta();
			if (selitem)
				dataTree()->createItem( selitem->Id() );
			else
				dataTree()->createItem();
			break;
		case DTreeListPopup::e_delete:
			if (selitem)
			{
				dataTree()->newDelta();
				dataTree()->removeItem( selitem->Id() );
			}
			break;
		case DTreeListPopup::e_discon_obj:
			if (selitem)
			{
				dataTree()->newDelta();
				dataTree()->disconnectItem( selitem->Id() );
			}
			break;

		case DTreeListPopup::e_discon_subtree:
			if (selitem)
			{
				dataTree()->newDelta();
				dataTree()->killFamily( selitem->Id() );
			}
			break; 

		case DTreeListPopup::e_discon_parent:
			if (selitem)
			{
				dataTree()->newDelta();
				dataTree()->setOrphan( selitem->Id() );
			}
			break;
			
		case Settings::EnumColorMode::custom_:
			{
				QColor myColor;
				int result = KColorDialog::getColor( myColor );

				if ( result == KColorDialog::Accepted )
				{
					dataTree()->newDelta();
					dataItem( selitem->Id() )->setCustomColors(
							myColor,
							QColor( Qt::black ),
							QColor( Qt::black ) );
				}
			}
			break;

		case Settings::EnumColorMode::default_:
		case Settings::EnumColorMode::theme1_:
		case Settings::EnumColorMode::theme2_:
		case Settings::EnumColorMode::theme3_:
		case Settings::EnumColorMode::theme4_:
		case Settings::EnumColorMode::theme5_:
		case Settings::EnumColorMode::theme6_:
			if (!selitem) return;
			dataTree()->newDelta();
			dataItem( selitem->Id() )->setColorScheme( sel );
			dataTree()->notifyChildChange( selitem->Id() );
			break;
		default:
			break;
	}
}

void DTreeListView::createItem( int id )
{
	//kdWarning()<<"DTreeListView::createItem"<<endl;

	if (!dataItem(id))
	{
		kdWarning()<<"Bug: no item given in DTreeListView::createItem"<<endl;
		return;
	}

	DTreeListItem *item = new DTreeListItem(this, id);
	registerItem(item);
}

void DTreeListView::updateItem(int id)
{
	DTreeListItem *item = (DTreeListItem*) Item(id);
	if (!item)
	{
		//kdWarning()<<"DTreeListView::updateItem item not found (loading a document ?) : "<<id<<endl;
		sort();
		return;
	}

	//kdWarning()<<"DTreeListView::updateItem item "<<id<<" "<<item<<endl;
	int parentid = dataItem(id)->Parent();
	if (parentid != id)
	{
		DTreeListItem *child = dynamic_cast<DTreeListItem*> (Item(id));
		DTreeListItem *currentparent = dynamic_cast<DTreeListItem*> (child->parent());
		DTreeListItem *newparent= dynamic_cast<DTreeListItem*> (Item(parentid));

		if (newparent != currentparent)
		{
			if (currentparent)
				currentparent->takeItem(child);
			else
				takeItem(child);

			if (parentid == DItem::NOITEM)
				insertItem(child);
			else if (newparent)
				newparent->insertItem(child);
		}
	}

	item->update();
	item->sortChildItems(1, true);
	sort();
	item->repaint();
	//triggerUpdate();
	//repaintItem(item);
}

void DTreeListView::removeItem(int id)
{
	//kdWarning()<<"DTreeListView::removeItem"<<endl;
	unregisterItem(id);
	DTreeListItem *item = (DTreeListItem*) Item(id);
	if (!item)
		return;
	delete item;
	//takeItem(item);
}

void DTreeListView::plug()
{
	if (!dataTree()) return;
	connect(dataTree(), SIGNAL(settingsChanged()), this, SLOT(settingsChanged()) );
	connect(dataTree(), SIGNAL(itemChanged(int)), this, SLOT(updateItem(int)) );
	connect(dataTree(), SIGNAL(itemCreated(int)), this, SLOT(createItem(int)) );
	connect(dataTree(), SIGNAL(itemRemoved(int)), this, SLOT(removeItem(int)) );
	connect(dataTree(), SIGNAL(refChanged(int, int, bool)), this, SLOT(changeRef(int, int, bool)) );
	connect(dataTree(), SIGNAL(itemSelected(int, DGuiView*)), this, SLOT(updateSelectedItem(int, DGuiView*)) );

	// load the document settings
	settingsChanged();
}

void DTreeListView::unplug()
{
	if (!dataTree()) return;
	disconnect(dataTree(), SIGNAL(settingsChanged()), this, SLOT(settingsChanged()) );
	disconnect(dataTree(), SIGNAL(itemChanged(int)), this, SLOT(updateItem(int)) );
	disconnect(dataTree(), SIGNAL(itemCreated(int)), this, SLOT(createItem(int)) );
	disconnect(dataTree(), SIGNAL(itemRemoved(int)), this, SLOT(removeItem(int)) );
	disconnect(dataTree(), SIGNAL(refChanged(int, int, bool)), this, SLOT(changeRef(int, int, bool)) );
	disconnect(dataTree(), SIGNAL(itemSelected(int, DGuiView*)), this, SLOT(updateSelectedItem(int, DGuiView*)) );
}

void DTreeListView::keyPressEvent(QKeyEvent *e)
{
	DTreeListItem *item = (DTreeListItem*) selectedItem();
	if (!item) return;

	disconnect( this, SIGNAL( moved( QListViewItem *, QListViewItem *, QListViewItem * ) ),
			this, SLOT( applyMoved( QListViewItem *, QListViewItem * , QListViewItem * ) ) );

	int id = item->Id();

	if (e->key() == Qt::Key_Delete)
	{
		if (item)
		{
			clearSelection();
			if (id != DItem::NOITEM) dataTree()->newDelta();
			dataTree()->removeItem( id );
		}
	}
	else if (e->key() == Qt::Key_O)
	{
		//kdWarning()<<"demote !!"<<endl;
		if (item)
		{
			DTreeListItem *parent = (DTreeListItem*) item->itemAbove();
			if (parent)
			{
				dataTree()->newDelta();
				dataTree()->setOrphan(id);
				dataTree()->linkItems(parent->Id(), id);
				updateItem(id);
			}
		}
	}
	else if (e->key() == Qt::Key_P)
	{
		//kdWarning()<<"promote !!"<<endl;
		if (item)
		{
			int parent = dataItem(id)->Parent();

			dataTree()->newDelta();
			dataTree()->setOrphan(id);

			// now link the item to the parent of its parent
			if (parent != DItem::NOITEM)
			{
				dataTree()->linkItems( dataItem( parent )->Parent(), id );
			}
		}
	}

	connect( this, SIGNAL( moved( QListViewItem *, QListViewItem *, QListViewItem * ) ),
			this, SLOT( applyMoved( QListViewItem *, QListViewItem * , QListViewItem * ) ) );
}

void DTreeListView::applyMoved( QListViewItem* current, QListViewItem*, QListViewItem* afternow )
{
	if (!current) return;

	DTreeListItem *item = NULL;
	int idcur = DItem::NOITEM, idparent = DItem::NOITEM;

	item = (DTreeListItem*) current;
	if (item) idcur = item->Id();

	item = (DTreeListItem*) current->parent();
	if (item) idparent = item->Id();

	dataTree()->newDelta();
	
	// set the item parent
	dataTree()->setOrphan( idcur );

	// link to the new parent
	if (idparent != DItem::NOITEM) dataTree()->linkItems( idparent, idcur);

	// now move the data item to the position suggested by the drop (sort)
	DTreeListItem *prev = (DTreeListItem*) afternow;
	int idprev = DItem::NOITEM;
	if (prev) idprev = prev->Id();

	//kdWarning()<<"id of the parent : "<<idparent<<" || id of the prev : "<<idprev<<endl;

	// find the rank of the prev item
	DDataItem* dataitem_prev   = (DDataItem*) (dataTree()->Item(idprev));
	DDataItem* dataitem_parent = (DDataItem*) (dataTree()->Item(idparent));

	if (dataitem_parent)  
	{  
		if (idprev == DItem::NOITEM || idprev == idparent || !dataitem_prev)
		{
			if (idparent != DItem::NOITEM)
				dataitem_parent->setChildIdx(idcur, 0);
			updateItem( idcur );
			return;
		}

		int prevposition = dataitem_parent->childIdx(idprev);

		dataitem_parent->setChildIdx( idcur, prevposition+1);

		// tell the views that the family had a reorganization party
		dataTree()->notifyChildren(idparent);
	}
	//kdWarning()<<"cur : "<<idcur<<" || parent : "<<idparent<<endl;
	//kdWarning()<<"DTreeListView::applyMoved : calling updateItem of "<<idcur<<endl;
	updateItem( idcur );
	setSortOrder(Qt::Ascending);
	sort();
}

void DTreeListView::changeRef(int, int, bool add)
{
	// TODO
	kdDebug()<<"DTreeListView::changeRef (not implemented yet)"<<endl;
}

#include "DTreeListView.moc"
