/*
 * Project: MoleCuilder
 * Description: creates and alters molecular systems
 * Copyright (C)  2013 University of Bonn. All rights reserved.
 * Copyright (C)  2013 Frederik Heber. 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 .
 */
/*
 * FragmentationShortRangeResults.cpp
 *
 *  Created on: Mar 07, 2013
 *      Author: heber
 */
// include config.h
#ifdef HAVE_CONFIG_H
#include 
#endif
#include "CodePatterns/MemDebug.hpp"
#include "FragmentationShortRangeResults.hpp"
#include 
#include 
#include 
#include 
#include "CodePatterns/Assert.hpp"
#include "CodePatterns/Log.hpp"
#include "Fragmentation/KeySetsContainer.hpp"
#include "Fragmentation/parseKeySetFile.hpp"
#include "Fragmentation/Summation/Converter/DataConverter.hpp"
#include "Fragmentation/Summation/Containers/createMatrixNrLookup.hpp"
#include "Fragmentation/Summation/Containers/extractJobIds.hpp"
#include "Fragmentation/Summation/AllLevelOrthogonalSummator.hpp"
#include "Fragmentation/Summation/IndexSetContainer.hpp"
#include "Fragmentation/Summation/OrthogonalSumUpPerLevel.hpp"
#include "Fragmentation/Summation/SubsetMap.hpp"
#include "Fragmentation/Summation/SumUpPerLevel.hpp"
#include "Helpers/defs.hpp"
FragmentationShortRangeResults::FragmentationShortRangeResults(
    const std::map &fragmentData,
    const KeySetsContainer& _KeySet,
    const KeySetsContainer& _ForceKeySet,
    std::vector &_ValueMask) :
    KeySet(_KeySet),
    ForceKeySet(_ForceKeySet)
{
  initLookups(fragmentData,_ValueMask);
  // convert KeySetContainer to IndexSetContainer
  container.reset(new IndexSetContainer(KeySet));
  // create the map of all keysets
  subsetmap.reset(new SubsetMap(*container));
}
void FragmentationShortRangeResults::initLookups(
    const std::map &fragmentData,
    std::vector &_ValueMask)
{
  // create lookup from job nr to fragment number
  size_t MPQCFragmentCounter = 0;
  const std::vector mpqcjobids = extractJobIds(fragmentData);
  MPQCMatrixNrLookup =
      createMatrixNrLookup(mpqcjobids, MPQCFragmentCounter, _ValueMask);
}
void FragmentationShortRangeResults::operator()(
    const std::map &fragmentData)
{
  MaxLevel = subsetmap->getMaximumSetLevel();
  LOG(1, "INFO: Summing up results till level " << MaxLevel << ".");
  /// convert all MPQCData to MPQCDataMap_t
  {
    ASSERT( ForceKeySet.KeySets.size() == fragmentData.size(),
        "FragmentationShortRangeResults::FragmentationShortRangeResults() - ForceKeySet's KeySets and fragmentData differ in size.");
    OrthogonalSumUpPerLevel(
        fragmentData, MPQCMatrixNrLookup, container, subsetmap,
        Result_Energy_fused, Result_perIndexSet_Energy);
    OrthogonalSumUpPerLevel(
        fragmentData, MPQCMatrixNrLookup, container, subsetmap,
        Result_Fragment_fused, Result_perIndexSet_Fragment);
    SumUpPerLevel(
        fragmentData, MPQCMatrixNrLookup, container, subsetmap,
        Result_Time_fused, Result_perIndexSet_Time);
    // force has extra data converter
    std::map MPQCData_Force_fused;
    convertDatatoForceMap(fragmentData, ForceKeySet, MPQCData_Force_fused);
    Result_Force_fused.resize(MaxLevel); // we need the results of correct size already
    AllLevelOrthogonalSummator forceSummer(
                subsetmap,
                MPQCData_Force_fused,
                container->getContainer(),
                MPQCMatrixNrLookup,
                Result_Force_fused,
                Result_perIndexSet_Force);
    boost::mpl::for_each(boost::ref(forceSummer));
  }
}
const FragmentationShortRangeResults::summedshortrange_t
FragmentationShortRangeResults::getSummedShortRangeResults() const
{
  summedshortrange_t results;
  typedef std::map<
      IndexSet::ptr, 
      std::pair 
      >::const_iterator maptype_citer_t;
  for (maptype_citer_t resultiter = Result_perIndexSet_Energy.begin();
      resultiter != Result_perIndexSet_Energy.end(); ++resultiter) {
    MPQCData values;
    values.energies.total = boost::fusion::at_key(resultiter->second.first);
    MPQCData contributions;
    contributions.energies.total = boost::fusion::at_key(resultiter->second.second);
    results.insert( std::make_pair( resultiter->first, std::make_pair(values, contributions) ) );
  }
  return results;
}