/*
 * Project: MoleCuilder
 * Description: creates and alters molecular systems
 * Copyright (C)  2010-2012 University of Bonn. All rights reserved.
 * 
 *
 *   This file is part of MoleCuilder.
 *
 *    MoleCuilder 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.
 *
 *    MoleCuilder 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 MoleCuilder.  If not, see .
 */
/*
 * QtElementList.cpp
 *
 *  Created on: Mar 6, 2012
 *      Author: ankele
 */
// include config.h
#ifdef HAVE_CONFIG_H
#include 
#endif
#include "Views/Qt4/QtElementList.hpp"
#include "UIElements/Qt4/InstanceBoard/QtObservedInstanceBoard.hpp"
#include 
#include "CodePatterns/MemDebug.hpp"
#include "Atom/atom.hpp"
#include "Atom/AtomObserver.hpp"
#include "Element/element.hpp"
#include "Element/periodentafel.hpp"
#include "Descriptors/AtomTypeDescriptor.hpp"
#include 
#include "Actions/SelectionAction/Atoms/AtomByElementAction.hpp"
#include "Actions/SelectionAction/Atoms/NotAtomByElementAction.hpp"
using namespace std;
const int QtElementList::COLUMNCOUNT = COLUMNTYPES_MAX;
const char *QtElementList::COLUMNNAMES[QtElementList::COLUMNCOUNT]={"Number","Name","Symbol","Mass","Occurrence"};
QtElementList::QtElementList(QtObservedInstanceBoard *_board, QWidget * _parent) :
    QTreeWidget (_parent),
    Observer("QtElementList"),
    board(_board)
{
  setColumnCount(COLUMNCOUNT);
  setSelectionMode(QAbstractItemView::MultiSelection);
  QStringList header;
	for(int i=0; ibegin(),i=0;
        iter != periode->end();
        ++i,++iter) {
      const element *e = iter->second;
      int count = 0;
      count = const_cast(World::getInstance()).
          getAllAtoms(AtomByType(e)).size();
      QTreeWidgetItem *treeItem = new QTreeWidgetItem(this);
      treeItem->setText(NUMBER, QString::number(e->getAtomicNumber()));
      treeItem->setText(NAME, QString(e->getName().c_str()));
      treeItem->setText(SYMBOL, QString(e->getSymbol().c_str()));
      treeItem->setText(MASS, QString::number(e->getMass()));
      setOccurrence(*treeItem, count);
      elementSelection.push_back(treeItem->isSelected());
//      insertTopLevelItem(e->getAtomicNumber()-1, treeItem);
    }
	}
	dirty = true;
	AtomObserver::getInstance().signOn(this, atom::ElementChanged);
  connect(this,SIGNAL(itemSelectionChanged()),this,SLOT(rowSelected()));
  connect(this,SIGNAL(needsRefill(const atomId_t)),this,SLOT(refill(const atomId_t)), Qt::QueuedConnection);
//  connect(this,SIGNAL(changed()),this,SLOT(update()));
}
QtElementList::~QtElementList()
{
  AtomObserver::getInstance().signOff(this, atom::ElementChanged);
}
void QtElementList::update(Observable *publisher)
{
  ASSERT(0, "QtElementList::update() - is not enlisted to any general update.");
}
void QtElementList::recieveNotification(Observable *publisher, Notification_ptr notification)
{
  if (notification->getChannelNo() == atom::ElementChanged) {
    dirty = true;
    emit needsRefill(dynamic_cast(publisher)->getId());
  } else
    ASSERT(0, "QtElementList::recieveNotification() - we are not enlisted to any other instance's channel.");
}
void QtElementList::updateElement(const QtObservedAtom::ptr &_atom)
{
  const atomicNumber_t newelement = _atom->getAtomElement();
  atomicNumber_t oldelement = -1;
  const atomId_t atomid = _atom->getAtomIndex();
  QTreeWidgetItem *newtreeItem = topLevelItem(newelement-1);
  ASSERT( newtreeItem != NULL,
      "QtElementList::updateElement() - new element item not present.");
//  if (newtreeItem == NULL) {
//    // add new item
//    const element& e = _atom.getElement();
//    newtreeItem = new QTreeWidgetItem();
//    newtreeItem->setText(NUMBER, QString::number(e.getAtomicNumber()));
//    newtreeItem->setText(NAME, QString(e.getName().c_str()));
//    newtreeItem->setText(SYMBOL, QString(e.getSymbol().c_str()));
//    newtreeItem->setText(MASS, QString::number(e.getMass()));
//    setOccurrence(*newtreeItem, 0);
//    elementSelection.push_back(newtreeItem->isSelected());
//    insertTopLevelItem(newelement-1, newtreeItem);
//  }
  AtomElementMap_t::iterator iter = AtomElementMap.find(atomid);
  if (iter == AtomElementMap.end()) {
    AtomElementMap.insert( std::make_pair(atomid, -1));
    iter = AtomElementMap.find(atomid);
  } else
    oldelement = iter->second;
  iter->second = newelement;
  // reduce old occurence
  if (oldelement != (atomicNumber_t)-1) {
    QTreeWidgetItem *oldtreeItem = topLevelItem(oldelement-1);
    ASSERT( oldtreeItem != NULL,
        "QtElementList::updateElement() - old element item not present.");
    const int count_old = oldtreeItem->text(OCCURRENCE).toInt();
    setOccurrence(*oldtreeItem, count_old-1);
  }
  // increase new occurence
  const int count_new = newtreeItem->text(OCCURRENCE).toInt();
  setOccurrence(*newtreeItem, count_new+1);
}
void QtElementList::setOccurrence(QTreeWidgetItem &_item, const int count)
{
  ASSERT (count >= 0,
      "QtElementList::setOccurrence() - count for an elment < 0.");
  if (count > 0) {
    _item.setText(OCCURRENCE, QString::number(count));
    if (_item.isDisabled())
      _item.setDisabled(false);
  } else {
    _item.setText(OCCURRENCE, "none");
    _item.setDisabled(true);
  }
}
void QtElementList::refill(const atomId_t _atomid)
{
  refill_mutex.lock();
  const QtObservedAtom::ptr walker = board->getObservedAtom(_atomid);
  if (walker)
    updateElement(walker);
  else {
    AtomElementMap_t::iterator iter = AtomElementMap.find(_atomid);
    if (iter != AtomElementMap.end()) {
      QTreeWidgetItem *oldtreeItem = topLevelItem(iter->second-1);
      const int count_old = oldtreeItem->text(OCCURRENCE).toInt();
      setOccurrence(*oldtreeItem, count_old-1);
      AtomElementMap.erase(iter);
    }
  }
  refill_mutex.unlock();
}
void QtElementList::paintEvent(QPaintEvent * event)
{
//  if (dirty)
//    refill();
  QTreeWidget::paintEvent(event);
}
void QtElementList::subjectKilled(Observable *publisher) {
}
void QtElementList::rowSelected()
{
  //std::cout << "rowSelected\n";
  periodentafel *&periode = World::getInstance().getPeriode();
  for (int i=0;iisSelected();
    if (newSelection != elementSelection[i]){
      elementSelection[i] = newSelection;
      int atomicNumber = item->text(NUMBER).toInt();
      const element *e = periode->FindElement(atomicNumber);
      if (newSelection)
        MoleCuilder::SelectionAtomByElement(e);
      else
        MoleCuilder::SelectionNotAtomByElement(e);
    }
  }
}