#pragma once
#include <BWAPI.h>

// Original file was in BWSAL

class Resources
{
public:
  Resources(double minerals = 0.0, double gas = 0.0, double supply = 0.0)
    : m_minerals(minerals)
    , m_gas(gas)
    , m_supply(supply)
  {}
  Resources(BWAPI::Player* player)
    : m_minerals(player->minerals())
    , m_gas(player->gas())
    , m_supply(player->supplyTotal() - player->supplyUsed())
  {}
  Resources(BWAPI::UnitType type)
    : m_minerals(type.mineralPrice())
    , m_gas(type.gasPrice())
    , m_supply(type.supplyRequired())
  {}
  Resources(BWAPI::TechType type)
    : m_minerals(type.mineralPrice())
    , m_gas(type.gasPrice())
    , m_supply(0.0)
  {}
  Resources(BWAPI::UpgradeType type, int level = 1)
    : m_minerals(type.mineralPrice() + type.mineralPriceFactor()*(level-1))
    , m_gas(type.gasPrice() + type.gasPriceFactor()*(level-1))
    , m_supply(0.0)
  {}

  Resources& Resources::operator=(const Resources &r)
  {
    m_minerals = r.m_minerals;
    m_gas      = r.m_gas;
    m_supply   = r.m_supply;
    return *this;
  }
  Resources& Resources::set(double minerals, double gas, double supply)
  {
    m_minerals = minerals;
    m_gas      = gas;
    m_supply   = supply;
    return *this;
  }
  Resources& Resources::setMinerals(double minerals)
  {
    m_minerals = minerals;
    return *this;
  }
  Resources& Resources::setGas(double gas)
  {
    m_gas = gas;
    return *this;
  }
  Resources& Resources::setSupply(double supply)
  {
    m_supply = supply;
    return *this;
  }
  Resources& Resources::addMinerals(double minerals)
  {
    m_minerals += minerals;
    return *this;
  }
  Resources& Resources::addGas(double gas)
  {
    m_gas += gas;
    return *this;
  }
  Resources& Resources::addSupply(double supply)
  {
    m_supply += supply;
    return *this;
  }
  Resources& Resources::operator+=(const Resources &resources)
  {
    m_minerals += resources.m_minerals;
    m_gas      += resources.m_gas;
    m_supply   += resources.m_supply;
    return *this;
  }
  Resources& Resources::operator-=(const Resources &resources)
  {
    m_minerals -= resources.m_minerals;
    m_gas      -= resources.m_gas;
    m_supply   -= resources.m_supply;
    return *this;
  }
  Resources& Resources::operator*=(double value)
  {
    m_minerals *= value;
    m_gas      *= value;
    m_supply   *= value;
    return *this;
  }
  Resources& Resources::operator/=(double value)
  {
    m_minerals /= value;
    m_gas      /= value;
    m_supply   /= value;
    return *this;
  }
  double Resources::getMinerals() const
  {
    return m_minerals;
  }
  double Resources::getGas() const
  {
    return m_gas;
  }
  double Resources::getSupply() const
  {
    return m_supply;
  }
  bool Resources::operator==(const Resources &resources) const
  {
    return m_minerals == resources.m_minerals 
        && m_gas == resources.m_gas 
        && m_supply == resources.m_supply;
  }
  bool Resources::operator<(const Resources &resources) const
  {
    return m_minerals < resources.m_minerals 
      || (m_minerals == resources.m_minerals && m_gas < resources.m_gas) 
      || (m_minerals == resources.m_minerals && m_gas == resources.m_gas && m_supply < resources.m_supply);
  }
  bool Resources::isValid() const
  {
    return m_minerals >= 0 
        && m_gas >= 0 
        && m_supply >= 0;
  }
  Resources Resources::operator+(const Resources &resources) const
  {
    return Resources(m_minerals + resources.m_minerals,
                     m_gas + resources.m_gas,
                     m_supply + resources.m_supply);
  }
  Resources Resources::operator-(const Resources &resources) const
  {
    return Resources(m_minerals - resources.m_minerals,
                     m_gas - resources.m_gas,
                     m_supply - resources.m_supply);
  }
  Resources Resources::operator*(double value) const
  {
    return Resources(m_minerals * value, 
                     m_gas * value, 
                     m_supply * value);
  }
  Resources Resources::operator/(double value) const
  {
    return Resources(m_minerals/value, 
                     m_gas/value,
                     m_supply/value);
  }

  friend std::ostream& operator<<(std::ostream& out, const Resources& resources)
  {
    out << "[Minerals = " << resources.m_minerals << ", Gas = " << resources.m_gas << ", Supply = " << resources.m_supply / 2 << "]";
    return out;
  }

  static Resources CumulativeResources(BWAPI::Player* player)
  {
    return Resources(player->gatheredMinerals(),
                     player->gatheredGas(),
                     player->supplyTotal() - player->supplyUsed());
  }

protected:
  double m_minerals;
  double m_gas;
  double m_supply;
};