/*
  Copyright 2015 SINTEF ICT, Applied Mathematics.

  This file is part of the Open Porous Media project (OPM).

  OPM 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 3 of the License, or
  (at your option) any later version.

  OPM 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 OPM.  If not, see <http://www.gnu.org/licenses/>.
*/

#ifndef OPM_AUTODIFF_VFPPROPERTIES_HPP_
#define OPM_AUTODIFF_VFPPROPERTIES_HPP_

#include <opm/simulators/wells/VFPInjProperties.hpp>
#include <opm/simulators/wells/VFPProdProperties.hpp>
#include <opm/simulators/wells/WellState.hpp>
#include <opm/simulators/wells/VFPHelpers.hpp>

#include <cstddef>

namespace Opm {

class VFPInjTable;
class VFPProdTable;

/**
 * A thin wrapper class that holds one VFPProdProperties and one
 * VFPInjProperties object.
 */
template<typename Scalar, typename IndexTraits>
class VFPProperties {
public:
    /**
     * Constructor
     * Takes *no* ownership of data.
     * @param inj_tables A map of different VFPINJ tables.
     * @param prod_tables A map of different VFPPROD tables.
     * @param well_state Current well state
     */

    VFPProperties(const std::vector<std::reference_wrapper<const VFPInjTable>>& inj_tables,
                  const std::vector<std::reference_wrapper<const VFPProdTable>>& prod_tables,
                  const WellState<Scalar, IndexTraits>& well_state)
        : well_state_(well_state)
    {
        for (const auto& vfpinj : inj_tables)
            this->m_inj.addTable( vfpinj );

        for (const auto& vfpprod : prod_tables)
            this->m_prod.addTable( vfpprod );
    };

    /**
     * Returns the VFP properties for injection wells
     */
    const VFPInjProperties<Scalar>* getInj() const
    {
        return &m_inj;
    }

    /**
     * Returns the VFP properties for production wells
     */
    const VFPProdProperties<Scalar>* getProd() const
    {
        return &m_prod;
    }

    Scalar getExplicitWFR(const int table_id, const std::size_t well_index) const
    {
        const auto& pu = well_state_.phaseUsageInfo();
        const bool has_water = pu.phaseIsActive(IndexTraits::waterPhaseIdx);
        const bool has_oil = pu.phaseIsActive(IndexTraits::oilPhaseIdx);
        const bool has_gas = pu.phaseIsActive(IndexTraits::gasPhaseIdx);
        const auto& rates = well_state_.well(well_index).prev_surface_rates;
        const auto& aqua = has_water ? rates[pu.canonicalToActivePhaseIdx(IndexTraits::waterPhaseIdx)] : 0.0;
        const auto& liquid = has_oil ? rates[pu.canonicalToActivePhaseIdx(IndexTraits::oilPhaseIdx)] : 0.0;
        const auto& vapour = has_gas ? rates[pu.canonicalToActivePhaseIdx(IndexTraits::gasPhaseIdx)] : 0.0;
        const VFPProdTable& table = this->m_prod.getTable(table_id);
        return detail::getWFR(table, aqua, liquid, vapour);
    }

    Scalar getExplicitGFR(const int table_id, const std::size_t well_index) const
    {
        const auto& pu = well_state_.phaseUsageInfo();
        const auto& rates = well_state_.well(well_index).prev_surface_rates;
        const bool has_water = pu.phaseIsActive(IndexTraits::waterPhaseIdx);
        const bool has_oil = pu.phaseIsActive(IndexTraits::oilPhaseIdx);
        const bool has_gas = pu.phaseIsActive(IndexTraits::gasPhaseIdx);
        const auto& aqua = has_water ? rates[pu.canonicalToActivePhaseIdx(IndexTraits::waterPhaseIdx)] : 0.0;
        const auto& liquid = has_oil ? rates[pu.canonicalToActivePhaseIdx(IndexTraits::oilPhaseIdx)] : 0.0;
        const auto& vapour = has_gas ? rates[pu.canonicalToActivePhaseIdx(IndexTraits::gasPhaseIdx)] : 0.0;
        const VFPProdTable& table = this->m_prod.getTable(table_id);
        return detail::getGFR(table, aqua, liquid, vapour);
    }

private:
    VFPInjProperties<Scalar> m_inj;
    VFPProdProperties<Scalar> m_prod;
    const WellState<Scalar, IndexTraits>& well_state_;
};

} // namespace Opm

#endif /* OPM_AUTODIFF_VFPPROPERTIES_HPP_ */
