#pragma once
#include "../QTreeWidgetItemCustom.h"
#include "Unit.h"
#include <QtCore/QString>
#include <PerceptualState/PerceptualState.h>

class LocationWrapper
{
public:
  LocationWrapper(const Location* location)
    : m_key(location)
    , m_name(QString::fromStdString(toString(location)))
  {
  }

  virtual ~LocationWrapper() {}

  virtual void display(QTreeWidget* parent) const
  {
    QTreeWidgetItemKey* item = new QTreeWidgetItemKey(parent, m_key);
    displayIn(item);
  }

  virtual void display(QTreeWidgetItem* parent) const
  {
    QTreeWidgetItemKey* item = new QTreeWidgetItemKey(parent, m_key);
    displayIn(item);
  }

  static LocationWrapper* createWrapper(const AutoPopulatedLocation* location);

  virtual size_t getNbUnits() const = 0;

protected:
  virtual void displayIn(QTreeWidgetItemKey* item) const;

  // Only the address is used, cause the pointer itself may have been deleted
  const void* const m_key;

  const QString m_name;
};

class LocationDisplayUnitsWrapper : public LocationWrapper
{
public:
  LocationDisplayUnitsWrapper(const AutoPopulatedLocation* location)
    : LocationWrapper(location)
  {
    std::pair<AutoPopulatedLocation::unit_const_iterator, AutoPopulatedLocation::unit_const_iterator> ownBuildings = location->getOwnUnits();
    for (; ownBuildings.first != ownBuildings.second; ++ownBuildings.first)
    {
      m_units.insert(m_units.end(), UnitRecordWrapper(*ownBuildings.first));
    }

    std::pair<AutoPopulatedLocation::unit_const_iterator, AutoPopulatedLocation::unit_const_iterator> enemyBuildings = location->getEnemyUnits();
    for (; enemyBuildings.first != enemyBuildings.second; ++enemyBuildings.first)
    {
      m_units.insert(m_units.end(), UnitRecordWrapper(*enemyBuildings.first));
    }

    std::pair<AutoPopulatedLocation::unit_const_iterator, AutoPopulatedLocation::unit_const_iterator> neutralUnits = location->getNeutralUnits();
    for (; neutralUnits.first != neutralUnits.second; ++neutralUnits.first)
    {
      m_units.insert(m_units.end(), UnitRecordWrapper(*neutralUnits.first));
    }
  }
  virtual size_t getNbUnits() const
  {
    return m_units.size();
  }
protected:
  virtual void displayIn(QTreeWidgetItemKey* item) const;

  std::list<UnitRecordWrapper> m_units;
};

class LocationDecompositionWrapper : public LocationWrapper
{
public:
  LocationDecompositionWrapper(const CompositeLocation* location)
    : LocationWrapper(location)
  {
    std::pair<CompositeLocation::sub_location_const_iterator, CompositeLocation::sub_location_const_iterator> subLocations = location->getSubLocations();
    for (; subLocations.first != subLocations.second; ++subLocations.first)
    {
      const AutoPopulatedLocation* childLocation = *subLocations.first;
      m_childLocations.push_back(LocationWrapper::createWrapper(childLocation)); 
    }
    struct GreaterNbUnits
    {
      bool operator()(const LocationWrapper* first, const LocationWrapper* second) const
      {
        return first->getNbUnits() > second->getNbUnits();
      }
    };
    std::sort(m_childLocations.begin(), m_childLocations.end(), GreaterNbUnits());
  }
  ~LocationDecompositionWrapper()
  {
    for (std::vector<LocationWrapper*>::const_iterator it = m_childLocations.begin(); it != m_childLocations.end(); ++it)
    {
      delete *it;
    }
  }
  virtual size_t getNbUnits() const
  {
    size_t nb = 0;
    for (std::vector<LocationWrapper*>::const_iterator it = m_childLocations.begin(); it != m_childLocations.end(); ++it)
    {
      nb += (*it)->getNbUnits();
    }
    return nb;
  }
protected:
  virtual void displayIn(QTreeWidgetItemKey* item) const;

  std::vector<LocationWrapper*> m_childLocations;
};
