/*
 * Project: MoleCuilder
 * Description: creates and alters molecular systems
 * Copyright (C)  2010-2012 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 .
 */
/*
 * ShapeRegistry.cpp
 *
 *  Created on: Sep 13, 2012
 *      Author: ankele
 */
// include config.h
#ifdef HAVE_CONFIG_H
#include 
#endif
#include "CodePatterns/MemDebug.hpp"
#include "ShapeRegistry.hpp"
#include "CodePatterns/Singleton_impl.hpp"
#include "CodePatterns/Registry_impl.hpp"
#include "CodePatterns/Observer/Channels.hpp"
#include "ShapeFactory.hpp"
ShapeRegistry::ShapeRegistry() :
  Observable::Observable("ShapeRegistry")
{
  Channels *OurChannel = new Channels;
  NotificationChannels.insert( std::make_pair(static_cast(this), OurChannel) );
  // add instance for each notification type
  for (size_t type = 0; type < NotificationType_MAX; ++type)
    OurChannel->addChannel(type);
  _lastchanged = NULL;
}
void ShapeRegistry::selectShape(const std::string& name)
{
  OBSERVE;
  NOTIFY(SelectionChanged);
  ASSERT(isPresentByName(name),"Shape selected that was not in the registry");
  selectedShapes[name] = getByName(name);
}
void ShapeRegistry::selectShape(Shape* s)
{
  ASSERT(s,"Invalid pointer in selection of shape");
  selectShape(s->getName());
}
void ShapeRegistry::unselectShape(const std::string& name)
{
  OBSERVE;
  NOTIFY(SelectionChanged);
  ASSERT(isPresentByName(name),"Shape unselected that was not in the registry");
  selectedShapes.erase(name);
}
void ShapeRegistry::unselectShape(Shape* s)
{
  ASSERT(s,"Invalid pointer in unselection of shape");
  unselectShape(s->getName());
}
void ShapeRegistry::selectAllShapes()
{
  OBSERVE;
  NOTIFY(SelectionChanged);
  const_iterator iter;
  for (iter = getBeginIter(); iter != getEndIter(); iter ++)
    if (!isSelected(iter->first))
      selectedShapes[iter->first] = iter->second;
}
void ShapeRegistry::unselectAllShapes()
{
  OBSERVE;
  NOTIFY(SelectionChanged);
  selectedShapes.clear();
}
void ShapeRegistry::invertShapeSelection()
{
  OBSERVE;
  NOTIFY(SelectionChanged);
  std::map inverted;
  const_iterator iter;
  for (iter = getBeginIter(); iter != getEndIter(); iter ++)
    if (!isSelected(iter->first))
      inverted[iter->first] = iter->second;
  selectedShapes = inverted;
}
bool ShapeRegistry::isSelected(const std::string& name) const
{
  return selectedShapes.find(name) != selectedShapes.end();
}
bool ShapeRegistry::isSelected(Shape* s) const
{
  ASSERT(s,"Invalid pointer in selection query of shape");
  return isSelected(s->getName());
}
int ShapeRegistry::countSelectedShapes() const
{
  size_t count = 0;
  for (const_iterator iter = selectedShapes.begin(); iter != selectedShapes.end(); ++iter)
    count++;
  return count;
}
std::vector ShapeRegistry::getSelectedShapes() const
{
  std::vector returnShapes;
  returnShapes.resize(countSelectedShapes());
  int count = 0;
  for (const_iterator iter = selectedShapes.begin(); iter != selectedShapes.end(); ++iter)
    returnShapes[count++] = iter->second;
  return returnShapes;
}
ShapeRegistry::~ShapeRegistry()
{
  cleanup();
}
std::string ShapeRegistry::getDefaultNameForShape(const std::string &baseName) const
{
  int n = 1;
  while(true){
    std::string name = baseName + toString(n);
    if (!isPresentByName(name))
      return name;
    n ++;
  }
  return "";
}
void ShapeRegistry::addShape(Shape s)
{
  OBSERVE;
  Shape *instance = new Shape(s);
  registerInstance(instance);
  _lastchanged = instance;
  NOTIFY(ShapeInserted);
}
void ShapeRegistry::removeShape(const std::string &name)
{
  selectedShapes.erase(name);
  Shape *instance = getByName(name);
  {
    OBSERVE;
    _lastchanged = instance;
    NOTIFY(ShapeRemoved);
  }
  unregisterInstance(instance);
  delete(instance);
}
CONSTRUCT_SINGLETON(ShapeRegistry)
CONSTRUCT_REGISTRY(Shape)