/***************************************************************************
 *   Copyright (C) 2004 by Hans Oischinger                                 *
 *   hans.oischinger@kdemail.net                                           *
 *                                                                         *
 *   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) any later version.                                   *
 *                                                                         *
 *   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.,                                       *
 *   51 Franklin Steet, Fifth Floor, Boston, MA 02110-1301, USA.             *
 ***************************************************************************/
#include "elementtreeview.h"

// Core
#include "core/direktorinstance.h"
#include "core/elementdatabase.h"
#include "core/documentwidget.h"

// Elements
#include "elements/elementnode.h"
#include "elements/vectorelement.h"
#include "elements/elementselection.h"
#include "elements/elementtreeiterator.h"

// Qt
#include <qptrdict.h>

// KDE
#include <kdebug.h>

ElementTreeView::ElementTreeView(QWidget *parent, const char *name)
    : KListView(parent, name)
{
  setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored);
  addColumn( "Element" );
  addColumn( "Id" );
  setSorting(-1);
  setSelectionMode(QListView::Extended);

  Kast::self()->elementDB().addElementListener(this);
  Kast::self()->elementDB().selection().addElementSelectionListener(this);
  connect( this, SIGNAL(selectionChanged()), SLOT(selectionChangedInside()) );
}

ElementTreeView::~ElementTreeView()
{
  Kast::self()->elementDB().selection().removeElementSelectionListener(this);
}

void ElementTreeView::setSelected( QListViewItem * item, bool selected )
{
  // kdDebug() << k_funcinfo << endl;

  if (selected)
    m_selectedItems.append(item);
  else
    m_selectedItems.remove(item);
  KListView::setSelected(item, selected);
}

void ElementTreeView::selectionChangedOutside()
{
  kdDebug() << k_funcinfo << endl;
  blockSignals(true);

  // Deselect old ones
  QPtrList<QListViewItem> tempSelItemsList(m_selectedItems); // copy or we get out of sync lists
  QPtrListIterator<QListViewItem> it( tempSelItemsList );
  while ( it.current() )
  {
    setSelected( it.current(), false );
    it.current()->repaint();
    ++it;
  }

  // Select new ones
  QPtrListIterator<ElementNode> itr( Kast::self()->elementDB().selection().elements() );
  for( ; itr.current(); ++itr )
  {
    ElementTreeViewItem* item = m_elementsToItems.find( itr.current() );
    if ( item )
    {
      ensureItemVisible(item);
      setSelected( item, true );
      item->repaint();
    }
    else
      kdWarning() << "ElementTreeView::selectionChangedOutside() - Element from Selection not found" << endl;
  }
  blockSignals(false);
  emit contentsChanged();
}

void ElementTreeView::selectionChangedInside()
{
  kdDebug() << k_funcinfo << endl;

  QPtrList<ElementNode> newSelection;
  QListViewItemIterator it( this );
  while ( it.current() )
  {
    if ( it.current()->isSelected() )
    {
      ElementTreeViewItem* selItem = static_cast<ElementTreeViewItem*>(it.current());
      selItem->element()->setSelected( true );
      newSelection.append( selItem->element() );
    }
    else
      static_cast<ElementTreeViewItem*>(it.current())->element()->setSelected(false);
    ++it;
  }
  Kast::self()->elementDB().selection().clear(false);
  Kast::self()->elementDB().selection().append( newSelection, false );
  Kast::self()->elementDB().selection().notifyChange();
  emit contentsChanged();
}

void ElementTreeView::appendTreeNode( ElementNode* e, ElementTreeViewItem* parent, ElementTreeViewItem* after, bool addNeighbours )
{
  if (!e)
    return;

  if ( m_elementsToItems.find(e) )
  {
    // Element already in list
    return;
  }

  ElementTreeViewItem* last;
  last = new ElementTreeViewItem( e, parent, after, e->readAbleType(), e->id() );
  last->setExpandable(e->hasChildNodes());

  // Add to dictionary
  m_elementsToItems.insert(e, last);

  if (e->getFirstChild())
  {
    // Ignore UseElement's children (they are only cloned Def's and Symbols)
    if( !e->isA("UseElement") )
      appendTreeNode(e->getFirstChild(), last, 0, true);
  }
  if (addNeighbours && e->getNext())
    appendTreeNode(e->getNext(), parent, last, true);
}

void ElementTreeView::onElementInserted( ElementNode* e )
{
  kdDebug() << k_funcinfo << endl;

  if ( m_elementsToItems.find(e) )
  {
    // Element already in list
    return;
  }

  if ( !e->getParent() )
  {
    ElementTreeViewItem* rootItem = new ElementTreeViewItem( e, this, e->readAbleType(), e->id());
    m_elementsToItems.insert(e, rootItem);
    appendTreeNode(e->getFirstChild(), rootItem, 0, true );
    rootItem->setExpandable(true);
    rootItem->setOpen(true);
  }
  else
  {

    ElementTreeViewItem* parentItem = m_elementsToItems.find(e->getParent());
    ElementTreeViewItem* prevItem = m_elementsToItems.find(e->getPrev());
    if ( parentItem )
      appendTreeNode( e, parentItem, prevItem );
  }
  emit contentsChanged();
}

void ElementTreeView::onElementRemoved( ElementNode* element )
{
  blockSignals(true); // blocksignals or we will change the elementSelection from in-&outside
  kdDebug() << k_funcinfo << endl;

  ElementTreeViewItem* item = m_elementsToItems.find(element);
  QListViewItemIterator it( item );
  while ( it.current() )
  {
    // Remove from dictionary first, then delete
    m_elementsToItems.remove( element );
    ++it;
  }
  delete item;
  blockSignals(false);
  emit contentsChanged();
}

void ElementTreeView::onElementModified( ElementNode *e )
{
  kdDebug() << "ElementTreeView::onElementModified()" << endl;
  ElementTreeViewItem* item = m_elementsToItems.find(e);
  if (item)
  {
    // item.setText(0,e->readAbleType()); // Unlikely to change?!
    item->setText(1,e->id());
  } else
    kdWarning() << "ElementTreeView::onElementModified() - Element not found!!!" << endl;
    emit contentsChanged();
}

void ElementTreeView::onSelectionModified()
{
  selectionChangedOutside();
}





ElementTreeViewItem::ElementTreeViewItem(ElementNode* element, QListView *parent) : KListViewItem(parent)
{
  init( element );
}

ElementTreeViewItem::ElementTreeViewItem(ElementNode* element, QListViewItem *parent) : KListViewItem(parent)
{
  init( element );
}

ElementTreeViewItem::ElementTreeViewItem(ElementNode* element, QListView *parent, QListViewItem *after) :
    KListViewItem(parent, after)
{
  init( element );
}

ElementTreeViewItem::ElementTreeViewItem(ElementNode* element, QListViewItem *parent, QListViewItem *after) :
    KListViewItem(parent, after)
{
  init( element );
}

ElementTreeViewItem::ElementTreeViewItem(ElementNode* element, QListView *parent,
    QString label1, QString label2, QString label3, QString label4,
    QString label5, QString label6, QString label7, QString label8)
    : KListViewItem( parent, label1, label2, label3, label4, label5, label6, label7, label8)
{
  init( element );
}

ElementTreeViewItem::ElementTreeViewItem(ElementNode* element, QListViewItem *parent,
    QString label1, QString label2, QString label3, QString label4,
    QString label5, QString label6, QString label7, QString label8)
    : KListViewItem( parent, label1, label2, label3, label4, label5, label6, label7, label8)
{
  init( element );
}

ElementTreeViewItem::ElementTreeViewItem(ElementNode* element, QListView *parent, QListViewItem *after,
    QString label1, QString label2, QString label3, QString label4,
    QString label5, QString label6, QString label7, QString label8)
    : KListViewItem( parent, after, label1, label2, label3, label4, label5, label6, label7, label8)
{
  init( element );
}

ElementTreeViewItem::ElementTreeViewItem(ElementNode* element, QListViewItem *parent, QListViewItem *after,
    QString label1, QString label2, QString label3, QString label4,
    QString label5, QString label6, QString label7, QString label8)
    : KListViewItem( parent, after, label1, label2, label3, label4, label5, label6, label7, label8)
{
  init( element );
}

ElementTreeViewItem::~ElementTreeViewItem()
{}

void ElementTreeViewItem::init( ElementNode* element )
{
  m_element = element;
}

#include "elementtreeview.moc"
