/*
 * 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 .
 */
/*
 * MoleculeLeafClass.cpp
 *
 *  Created on: Oct 20, 2011
 *      Author: heber
 */
// include config.h
#ifdef HAVE_CONFIG_H
#include 
#endif
#include "CodePatterns/MemDebug.hpp"
#include "MoleculeLeafClass.hpp"
#include "CodePatterns/Log.hpp"
#include "Atom/atom.hpp"
#include "Element/element.hpp"
#include "Fragmentation/Graph.hpp"
#include "Fragmentation/KeySet.hpp"
#include "molecule.hpp"
/** Constructor for MoleculeLeafClass root leaf.
 * \param *Up Leaf on upper level
 * \param *PreviousLeaf NULL - We are the first leaf on this level, otherwise points to previous in list
 */
//MoleculeLeafClass::MoleculeLeafClass(MoleculeLeafClass *Up = NULL, MoleculeLeafClass *Previous = NULL)
MoleculeLeafClass::MoleculeLeafClass(MoleculeLeafClass *PreviousLeaf = NULL) :
  Leaf(NULL),
  previous(PreviousLeaf)
{
  //  if (Up != NULL)
  //    if (Up->DownLeaf == NULL) // are we the first down leaf for the upper leaf?
  //      Up->DownLeaf = this;
  //  UpLeaf = Up;
  //  DownLeaf = NULL;
  if (previous != NULL) {
    MoleculeLeafClass *Walker = previous->next;
    previous->next = this;
    next = Walker;
  } else {
    next = NULL;
  }
};
/** Destructor for MoleculeLeafClass.
 */
MoleculeLeafClass::~MoleculeLeafClass()
{
  //  if (DownLeaf != NULL) {// drop leaves further down
  //    MoleculeLeafClass *Walker = DownLeaf;
  //    MoleculeLeafClass *Next;
  //    do {
  //      Next = Walker->NextLeaf;
  //      delete(Walker);
  //      Walker = Next;
  //    } while (Walker != NULL);
  //    // Last Walker sets DownLeaf automatically to NULL
  //  }
  // remove the leaf itself
  if (Leaf != NULL) {
    Leaf->removeAtomsinMolecule();
    World::getInstance().destroyMolecule(Leaf);
    Leaf = NULL;
  }
  // remove this Leaf from level list
  if (previous != NULL)
    previous->next = next;
  //  } else { // we are first in list (connects to UpLeaf->DownLeaf)
  //    if ((NextLeaf != NULL) && (NextLeaf->UpLeaf == NULL))
  //      NextLeaf->UpLeaf = UpLeaf;  // either null as we are top level or the upleaf of the first node
  //    if (UpLeaf != NULL)
  //      UpLeaf->DownLeaf = NextLeaf;  // either null as we are only leaf or NextLeaf if we are just the first
  //  }
  //  UpLeaf = NULL;
  if (next != NULL) // are we last in list
    next->previous = previous;
  next = NULL;
  previous = NULL;
};
/** Adds \a molecule leaf to the tree.
 * \param *ptr ptr to molecule to be added
 * \param *Previous previous MoleculeLeafClass referencing level and which on the level
 * \return true - success, false - something went wrong
 */
bool MoleculeLeafClass::AddLeaf(molecule *ptr, MoleculeLeafClass *Previous)
{
  return false;
};
/** Fills the root stack for sites to be used as root in fragmentation depending on order or adaptivity criteria
 * Again, as in \sa FillBondStructureFromReference steps recursively through each Leaf in this chain list of molecule's.
 * \param *out output stream for debugging
 * \param *&RootStack stack to be filled
 * \param *AtomMask defines true/false per global Atom::Nr to mask in/out each nuclear site
 * \param &FragmentCounter counts through the fragments in this MoleculeLeafClass
 * \param saturation whether to treat hydrogen special or not
 * \return true - stack is non-empty, fragmentation necessary, false - stack is empty, no more sites to update
 */
bool MoleculeLeafClass::FillRootStackForSubgraphs(KeyStack *&RootStack, bool *AtomMask, int &FragmentCounter, const enum HydrogenSaturation saturation)
{
  if (RootStack != NULL) {
    // find first root candidates
    if (&(RootStack[FragmentCounter]) != NULL) {
      RootStack[FragmentCounter].clear();
      for(molecule::const_iterator iter = Leaf->begin(); iter != Leaf->end(); ++iter) {
        const atom * const Father = (*iter)->GetTrueFather();
        if (AtomMask[Father->getNr()]) // apply mask
          if ((saturation == DontSaturate) || ((*iter)->getType()->getAtomicNumber() != 1)) // skip hydrogen
            RootStack[FragmentCounter].push_front((*iter)->getNr());
      }
      if (next != NULL)
        next->FillRootStackForSubgraphs(RootStack, AtomMask, ++FragmentCounter, saturation);
    } else {
      LOG(1, "Rootstack[" << FragmentCounter << "] is NULL.");
      return false;
    }
    FragmentCounter--;
    return true;
  } else {
    LOG(1, "Rootstack is NULL.");
    return false;
  }
};
/** The indices per keyset are compared to the respective father's Atom::Nr in each subgraph and thus put into \a **&FragmentList.
 * \param *out output stream fro debugging
 * \param *reference reference molecule with the bond structure to be copied
 * \param *KeySetList list with all keysets
 * \param ***ListOfLocalAtoms Lookup table for each subgraph and index of each atom in global molecule, may be NULL on start, then it is filled
 * \param **&FragmentList list to be allocated and returned
 * \param &FragmentCounter counts the fragments as we move along the list
 * \param FreeList true - ***ListOfLocalAtoms is free'd before return, false - it is not
 * \retuen true - success, false - failure
 */
bool MoleculeLeafClass::AssignKeySetsToFragment(molecule *reference, Graph *KeySetList, atom ***&ListOfLocalAtoms, Graph **&FragmentList, int &FragmentCounter, bool FreeList)
{
  bool status = true;
  int KeySetCounter = 0;
  LOG(1, "Begin of AssignKeySetsToFragment.");
  // fill ListOfLocalAtoms if NULL was given
  if (!Leaf->FillListOfLocalAtoms(ListOfLocalAtoms[FragmentCounter], reference->getAtomCount())) {
    LOG(1, "Filling of ListOfLocalAtoms failed.");
    return false;
  }
  // allocate fragment list
  if (FragmentList == NULL) {
    KeySetCounter = Count();
    FragmentList = new Graph*[KeySetCounter];
    for (int i=0;isize() != 0)) { // if there are some scanned keysets at all
    // assign scanned keysets
    if (FragmentList[FragmentCounter] == NULL)
      FragmentList[FragmentCounter] = new Graph;
    KeySet *TempSet = new KeySet;
    for (Graph::iterator runner = KeySetList->begin(); runner != KeySetList->end(); runner++) { // key sets contain global numbers!
      if (ListOfLocalAtoms[FragmentCounter][reference->FindAtom(*((*runner).first.begin()))->getNr()] != NULL) {// as we may assume that that bond structure is unchanged, we only test the first key in each set
        // translate keyset to local numbers
        for (KeySet::iterator sprinter = (*runner).first.begin(); sprinter != (*runner).first.end(); sprinter++)
          TempSet->insert(ListOfLocalAtoms[FragmentCounter][reference->FindAtom(*sprinter)->getNr()]->getNr());
        // insert into FragmentList
        FragmentList[FragmentCounter]->insert(GraphPair(*TempSet, pair (KeySetCounter++, (*runner).second.second)));
      }
      TempSet->clear();
    }
    delete (TempSet);
    if (KeySetCounter == 0) {// if there are no keysets, delete the list
      LOG(1, "KeySetCounter is zero, deleting FragmentList.");
      delete (FragmentList[FragmentCounter]);
    } else
      LOG(1, KeySetCounter << " keysets were assigned to subgraph " << FragmentCounter << ".");
    FragmentCounter++;
    if (next != NULL)
      next->AssignKeySetsToFragment(reference, KeySetList, ListOfLocalAtoms, FragmentList, FragmentCounter, FreeList);
    FragmentCounter--;
  } else
    LOG(1, "KeySetList is NULL or empty.");
  if ((FreeList) && (ListOfLocalAtoms != NULL)) {
    // free the index lookup list
    delete[](ListOfLocalAtoms[FragmentCounter]);
  }
  LOG(1, "End of AssignKeySetsToFragment.");
  return status;
};
/** Translate list into global numbers (i.e. ones that are valid in "this" molecule, not in MolecularWalker->Leaf)
 * \param *out output stream for debugging
 * \param **FragmentList Graph with local numbers per fragment
 * \param &FragmentCounter counts the fragments as we move along the list
 * \param &TotalNumberOfKeySets global key set counter
 * \param &TotalGraph Graph to be filled with global numbers
 */
void MoleculeLeafClass::TranslateIndicesToGlobalIDs(Graph **FragmentList, int &FragmentCounter, int &TotalNumberOfKeySets, Graph &TotalGraph)
{
  LOG(1, "Begin of TranslateIndicesToGlobalIDs.");
  KeySet *TempSet = new KeySet;
  if (FragmentList[FragmentCounter] != NULL) {
    for (Graph::iterator runner = FragmentList[FragmentCounter]->begin(); runner != FragmentList[FragmentCounter]->end(); runner++) {
      for (KeySet::iterator sprinter = (*runner).first.begin(); sprinter != (*runner).first.end(); sprinter++)
        TempSet->insert((Leaf->FindAtom(*sprinter))->GetTrueFather()->getNr());
      TotalGraph.insert(GraphPair(*TempSet, pair (TotalNumberOfKeySets++, (*runner).second.second)));
      TempSet->clear();
    }
    delete (TempSet);
  } else {
    LOG(1, "FragmentList is NULL.");
  }
  if (next != NULL)
    next->TranslateIndicesToGlobalIDs(FragmentList, ++FragmentCounter, TotalNumberOfKeySets, TotalGraph);
  FragmentCounter--;
  LOG(1, "End of TranslateIndicesToGlobalIDs.");
};
/** Simply counts the number of items in the list, from given MoleculeLeafClass.
 * \return number of items
 */
int MoleculeLeafClass::Count() const
{
  if (next != NULL)
    return next->Count() + 1;
  else
    return 1;
};