/////////////////////////////////////////////////////////////////////////////////
//
//  Copyright (C) 2017     Statoil ASA
//
//  ResInsight 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.
//
//  ResInsight 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 at <http://www.gnu.org/licenses/gpl.html>
//  for more details.
//
/////////////////////////////////////////////////////////////////////////////////

#include "RiuPvtPlotPanel.h"

#include "RiuDockedQwtPlot.h"
#include "RiuGuiTheme.h"
#include "RiuPvtPlotUpdater.h"

#include "RiaEclipseUnitTools.h"

#include "RigFlowDiagSolverInterface.h"

#include "cvfAssert.h"
#include "cvfMath.h"

#include "qwt_legend.h"
#include "qwt_picker_machine.h"
#include "qwt_plot.h"
#include "qwt_plot_curve.h"
#include "qwt_plot_grid.h"
#include "qwt_plot_layout.h"
#include "qwt_plot_marker.h"
#include "qwt_plot_picker.h"
#include "qwt_symbol.h"
#include "qwt_text.h"

#include <QComboBox>
#include <QHBoxLayout>
#include <QLabel>
#include <QVBoxLayout>
#include <QWidget>

//==================================================================================================
//
//
//
//==================================================================================================
class PvtQwtPlot : public RiuDockedQwtPlot
{
public:
    PvtQwtPlot( QWidget* parent )
        : RiuDockedQwtPlot( parent )
    {
    }
    QSize sizeHint() const override { return QSize( 100, 100 ); }
    QSize minimumSizeHint() const override { return QSize( 0, 0 ); }
};

//==================================================================================================
//
//
//
//==================================================================================================
class RiuPvtQwtPicker : public QwtPicker
{
public:
    RiuPvtQwtPicker( QwtPlot* plot, RiuPvtTrackerTextProvider* trackerTextProvider )
        : QwtPicker( QwtPicker::NoRubberBand, QwtPicker::AlwaysOn, plot->canvas() )
        , m_trackerTextProvider( trackerTextProvider )
    {
        setStateMachine( new QwtPickerTrackerMachine );
    }

    QwtText trackerText( const QPoint& ) const override
    {
        QwtText text( m_trackerTextProvider->trackerText() );
        text.setRenderFlags( Qt::AlignLeft );
        return text;
    }

private:
    const RiuPvtTrackerTextProvider* m_trackerTextProvider;
};

//==================================================================================================
///
/// \class RiuPvtPlotWidget
///
///
///
//==================================================================================================

//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RiuPvtPlotWidget::RiuPvtPlotWidget( RiuPvtPlotPanel* parent )
    : QWidget( parent )
    , m_trackerPlotMarker( nullptr )
{
    m_qwtPlot = new PvtQwtPlot( this );
    m_qwtPlot->setProperty( "qss-class", "PvtPlot" );
    setPlotDefaults( m_qwtPlot );
    applyFontSizes( false );

    QHBoxLayout* layout = new QHBoxLayout();
    layout->addWidget( m_qwtPlot );
    layout->setSpacing( 0 );
    layout->setContentsMargins( 0, 0, 0, 0 );

    setLayout( layout );

    m_qwtPicker = new RiuPvtQwtPicker( m_qwtPlot, this );
    RiuGuiTheme::styleQwtItem( m_qwtPicker );
    connect( m_qwtPicker, SIGNAL( activated( bool ) ), this, SLOT( slotPickerActivated( bool ) ) );
    connect( m_qwtPicker, SIGNAL( moved( const QPoint& ) ), this, SLOT( slotPickerPointChanged( const QPoint& ) ) );
}

//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RiuPvtPlotWidget::setPlotDefaults( QwtPlot* plot )
{
    plot->setAutoFillBackground( true );

    QFrame* canvasFrame = dynamic_cast<QFrame*>( plot->canvas() );
    if ( canvasFrame )
    {
        canvasFrame->setFrameShape( QFrame::NoFrame );
    }

    // Grid
    {
        QwtPlotGrid* grid = new QwtPlotGrid;
        grid->attach( plot );
        RiuGuiTheme::styleQwtItem( grid );
    }

    // Axis number font
    {
        QFont axisFont = plot->axisFont( QwtAxis::XBottom );
        axisFont.setPointSize( 8 );
        plot->setAxisFont( QwtAxis::XBottom, axisFont );
        plot->setAxisFont( QwtAxis::YLeft, axisFont );
    }

    // Axis title font
    {
        QwtText axisTitle     = plot->axisTitle( QwtAxis::XBottom );
        QFont   axisTitleFont = axisTitle.font();
        axisTitleFont.setPointSize( 8 );
        axisTitleFont.setBold( false );
        axisTitle.setFont( axisTitleFont );
        axisTitle.setRenderFlags( Qt::AlignRight );
        plot->setAxisTitle( QwtAxis::XBottom, axisTitle );
        plot->setAxisTitle( QwtAxis::YLeft, axisTitle );
    }

    // Title font
    {
        QwtText plotTitle = plot->title();
        QFont   titleFont = plotTitle.font();
        titleFont.setPointSize( 12 );
        plotTitle.setFont( titleFont );
        plot->setTitle( plotTitle );
    }

    plot->setAxisMaxMinor( QwtAxis::XBottom, 2 );
    plot->setAxisMaxMinor( QwtAxis::YLeft, 3 );

    plot->plotLayout()->setAlignCanvasToScales( true );
}

//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RiuPvtPlotWidget::plotCurves( RiaDefines::EclipseUnitSystem                            unitSystem,
                                   const std::vector<RigFlowDiagSolverInterface::PvtCurve>& curveArr,
                                   double                                                   pressure,
                                   double                                                   pointMarkerYValue,
                                   const QString&                                           pointMarkerLabel,
                                   const QString&                                           plotTitle,
                                   const QString&                                           yAxisTitle )
{
    m_qwtPlot->detachItems( QwtPlotItem::Rtti_PlotCurve );
    m_qwtPlot->detachItems( QwtPlotItem::Rtti_PlotMarker );
    m_qwtCurveArr.clear();
    m_pvtCurveArr.clear();
    m_trackerPlotMarker = nullptr;

    // Construct an auxiliary curve that connects the first point in all the input curves as a visual aid
    // This should only be shown when the phase being plotted is oil
    // Will not be added to our array of qwt curves since we do not expect the user to interact with it
    {
        std::vector<double> xVals;
        std::vector<double> yVals;
        for ( size_t i = 0; i < curveArr.size(); i++ )
        {
            const RigFlowDiagSolverInterface::PvtCurve& curve = curveArr[i];
            if ( curve.phase == RigFlowDiagSolverInterface::PvtCurve::OIL && curve.pressureVals.size() > 0 && curve.yVals.size() > 0 )
            {
                xVals.push_back( curve.pressureVals[0] );
                yVals.push_back( curve.yVals[0] );
            }
        }

        if ( xVals.size() > 1 )
        {
            QwtPlotCurve* qwtCurve = new QwtPlotCurve( "Auxiliary" );
            qwtCurve->setSamples( xVals.data(), yVals.data(), static_cast<int>( xVals.size() ) );

            qwtCurve->setStyle( QwtPlotCurve::Lines );
            qwtCurve->setRenderHint( QwtPlotItem::RenderAntialiased, true );

            qwtCurve->attach( m_qwtPlot );
            RiuGuiTheme::styleQwtItem( qwtCurve );
        }
    }

    // Add the primary curves
    for ( size_t i = 0; i < curveArr.size(); i++ )
    {
        const RigFlowDiagSolverInterface::PvtCurve& curve       = curveArr[i];
        QwtPlotCurve*                               qwtCurve    = new QwtPlotCurve();
        QwtSymbol*                                  curveSymbol = new QwtSymbol( QwtSymbol::Ellipse );

        CVF_ASSERT( curve.pressureVals.size() == curve.yVals.size() );
        qwtCurve->setSamples( curve.pressureVals.data(), curve.yVals.data(), static_cast<int>( curve.pressureVals.size() ) );

        qwtCurve->setStyle( QwtPlotCurve::Lines );

        if ( curve.phase == RigFlowDiagSolverInterface::PvtCurve::GAS )
        {
            qwtCurve->setTitle( "Gas" );
        }
        else if ( curve.phase == RigFlowDiagSolverInterface::PvtCurve::OIL )
        {
            qwtCurve->setTitle( "Oil" );
        }
        else
        {
            qwtCurve->setTitle( "Undefined" );
        }

        qwtCurve->setRenderHint( QwtPlotItem::RenderAntialiased, true );

        curveSymbol->setSize( 6, 6 );
        curveSymbol->setBrush( Qt::NoBrush );
        qwtCurve->setSymbol( curveSymbol );

        qwtCurve->attach( m_qwtPlot );
        RiuGuiTheme::styleQwtItem( qwtCurve );

        m_qwtCurveArr.push_back( qwtCurve );
    }

    m_pvtCurveArr = curveArr;
    CVF_ASSERT( m_pvtCurveArr.size() == m_qwtCurveArr.size() );

    // Add vertical marker line to indicate cell pressure
    if ( pressure != HUGE_VAL )
    {
        QwtPlotMarker* lineMarker = new QwtPlotMarker;

        QPen pen;
        pen.setStyle( Qt::DashLine );
        lineMarker->setLinePen( pen );

        lineMarker->setXValue( pressure );
        lineMarker->setLineStyle( QwtPlotMarker::VLine );
        lineMarker->setLabel( QString( "PRESSURE" ) );
        lineMarker->setLabelAlignment( Qt::AlignTop | Qt::AlignRight );
        lineMarker->setLabelOrientation( Qt::Vertical );
        lineMarker->attach( m_qwtPlot );
        RiuGuiTheme::styleQwtItem( lineMarker );
    }

    // Then point marker
    if ( pressure != HUGE_VAL && pointMarkerYValue != HUGE_VAL )
    {
        QwtPlotMarker* pointMarker = new QwtPlotMarker;
        pointMarker->setValue( pressure, pointMarkerYValue );

        QwtSymbol* symbol = new QwtSymbol( QwtSymbol::Ellipse );
        symbol->setSize( 13, 13 );
        QPen pen;
        pen.setWidth( 2 );
        symbol->setPen( pen );
        symbol->setBrush( Qt::NoBrush );
        pointMarker->setSymbol( symbol );

        if ( !pointMarkerLabel.isEmpty() )
        {
            QwtText text( pointMarkerLabel );
            text.setRenderFlags( Qt::AlignLeft );
            text.setColor( RiuGuiTheme::getColorByVariableName( "textColor" ) );
            pointMarker->setLabel( text );
            pointMarker->setLabelAlignment( Qt::AlignTop | Qt::AlignRight );
        }

        pointMarker->attach( m_qwtPlot );
        RiuGuiTheme::styleQwtItem( pointMarker );
    }

    m_qwtPlot->setTitle( plotTitle );

    m_qwtPlot->setAxisTitle( QwtAxis::XBottom, QString( "Pressure [%1]" ).arg( RiaEclipseUnitTools::unitStringPressure( unitSystem ) ) );
    m_qwtPlot->setAxisTitle( QwtAxis::YLeft, yAxisTitle );

    updateTrackerPlotMarkerAndLabelFromPicker();

    m_qwtPlot->replot();
}

//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RiuPvtPlotWidget::applyFontSizes( bool replot )
{
    m_qwtPlot->applyFontSizes( replot );
}

//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RiuPvtPlotWidget::updateTrackerPlotMarkerAndLabelFromPicker()
{
    bool    hasValidSamplePoint = false;
    QPointF samplePoint;
    QString mixRatioText = "";
    double  mixRat       = HUGE_VAL;

    if ( m_qwtPicker && m_qwtPicker->isActive() )
    {
        const QPoint trackerPos = m_qwtPicker->trackerPosition();

        int                 pointSampleIdx  = -1;
        const QwtPlotCurve* closestQwtCurve = closestCurveSample( trackerPos, &pointSampleIdx );
        if ( closestQwtCurve && pointSampleIdx >= 0 )
        {
            samplePoint         = closestQwtCurve->sample( pointSampleIdx );
            hasValidSamplePoint = true;

            size_t curveIdx = indexOfQwtCurve( closestQwtCurve );
            if ( curveIdx < m_pvtCurveArr.size() )
            {
                const RigFlowDiagSolverInterface::PvtCurve& pvtCurve = m_pvtCurveArr[curveIdx];
                if ( static_cast<size_t>( pointSampleIdx ) < pvtCurve.mixRatVals.size() )
                {
                    mixRat = pvtCurve.mixRatVals[pointSampleIdx];

                    // The text is Rs or Rv depending on phase
                    mixRatioText = ( pvtCurve.phase == RigFlowDiagSolverInterface::PvtCurve::GAS ) ? "Rv" : "Rs";
                }
            }
        }
    }

    m_trackerLabel = "";

    bool needsReplot = false;

    if ( hasValidSamplePoint )
    {
        if ( !m_trackerPlotMarker )
        {
            m_trackerPlotMarker = new QwtPlotMarker;
            m_trackerPlotMarker->setTitle( QString( "TrackedPoint" ) );

            QwtSymbol* symbol = new QwtSymbol( QwtSymbol::Ellipse );
            symbol->setSize( 13, 13 );
            symbol->setBrush( Qt::NoBrush );
            m_trackerPlotMarker->setSymbol( symbol );
            m_trackerPlotMarker->attach( m_qwtPlot );
            RiuGuiTheme::styleQwtItem( m_trackerPlotMarker );

            needsReplot = true;
        }

        if ( m_trackerPlotMarker->value() != samplePoint )
        {
            m_trackerPlotMarker->setValue( samplePoint );
            needsReplot = true;
        }

        m_trackerLabel = QString( "%1 (%2)" ).arg( samplePoint.y() ).arg( samplePoint.x() );
        if ( mixRat != HUGE_VAL )
        {
            m_trackerLabel += QString( "\n%1 = %2" ).arg( mixRatioText ).arg( mixRat );
        }
    }
    else
    {
        if ( m_trackerPlotMarker )
        {
            m_trackerPlotMarker->detach();
            delete m_trackerPlotMarker;
            m_trackerPlotMarker = nullptr;

            needsReplot = true;
        }
    }

    if ( needsReplot )
    {
        m_qwtPlot->replot();
    }
}

//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
const QwtPlotCurve* RiuPvtPlotWidget::closestCurveSample( const QPoint& cursorPosition, int* closestSampleIndex ) const
{
    // Construct a set containing the relevant qwt curves to consider
    // These are the curves that have a corresponding Pvt source curve
    std::set<const QwtPlotCurve*> relevantQwtCurvesSet( m_qwtCurveArr.begin(), m_qwtCurveArr.end() );

    if ( closestSampleIndex ) *closestSampleIndex = -1;

    const QwtPlotCurve* closestCurve            = nullptr;
    double              distMin                 = HUGE_VAL;
    int                 closestPointSampleIndex = -1;

    const QwtPlotItemList& itemList = m_qwtPlot->itemList();
    for ( QwtPlotItemIterator it = itemList.begin(); it != itemList.end(); it++ )
    {
        if ( ( *it )->rtti() == QwtPlotItem::Rtti_PlotCurve )
        {
            const QwtPlotCurve* curve = static_cast<const QwtPlotCurve*>( *it );
            if ( relevantQwtCurvesSet.find( curve ) != relevantQwtCurvesSet.end() )
            {
                double dist                 = HUGE_VAL;
                int    candidateSampleIndex = curve->closestPoint( cursorPosition, &dist );
                if ( dist < distMin )
                {
                    closestCurve            = curve;
                    closestPointSampleIndex = candidateSampleIndex;
                    distMin                 = dist;
                }
            }
        }
    }

    if ( closestCurve && closestPointSampleIndex >= 0 && distMin < 50 )
    {
        if ( closestSampleIndex ) *closestSampleIndex = closestPointSampleIndex;
        return closestCurve;
    }
    else
    {
        return nullptr;
    }
}

//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
size_t RiuPvtPlotWidget::indexOfQwtCurve( const QwtPlotCurve* qwtCurve ) const
{
    for ( size_t i = 0; i < m_qwtCurveArr.size(); i++ )
    {
        if ( m_qwtCurveArr[i] == qwtCurve )
        {
            return i;
        }
    }

    return cvf::UNDEFINED_SIZE_T;
}

//--------------------------------------------------------------------------------------------------
/// Implements the RiuPvtTrackerTextProvider interface
//--------------------------------------------------------------------------------------------------
QString RiuPvtPlotWidget::trackerText() const
{
    return m_trackerLabel;
}

//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RiuPvtPlotWidget::slotPickerPointChanged( const QPoint& pt )
{
    updateTrackerPlotMarkerAndLabelFromPicker();
}

//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RiuPvtPlotWidget::slotPickerActivated( bool on )
{
    updateTrackerPlotMarkerAndLabelFromPicker();
}

//==================================================================================================
///
/// \class RiuPvtPlotPanel
///
///
///
//==================================================================================================

//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RiuPvtPlotPanel::RiuPvtPlotPanel( QWidget* parent )
    : QWidget( parent )
    , m_unitSystem( RiaDefines::EclipseUnitSystem::UNITS_UNKNOWN )
    , m_plotUpdater( new RiuPvtPlotUpdater( this ) )
{
    m_phaseComboBox = new QComboBox( this );
    m_phaseComboBox->setEditable( false );
    m_phaseComboBox->addItem( "Oil", QVariant( RigFlowDiagSolverInterface::PvtCurve::OIL ) );
    m_phaseComboBox->addItem( "Gas", QVariant( RigFlowDiagSolverInterface::PvtCurve::GAS ) );

    m_titleLabel = new QLabel( "", this );
    m_titleLabel->setAlignment( Qt::AlignHCenter );
    QFont font = m_titleLabel->font();
    font.setPointSize( 10 );
    font.setBold( true );
    m_titleLabel->setFont( font );

    QHBoxLayout* topLayout = new QHBoxLayout();
    topLayout->addWidget( new QLabel( "Phase:" ) );
    topLayout->addWidget( m_phaseComboBox );
    topLayout->addWidget( m_titleLabel, 1 );
    topLayout->setContentsMargins( 5, 5, 0, 0 );

    m_fvfPlot       = new RiuPvtPlotWidget( this );
    m_viscosityPlot = new RiuPvtPlotWidget( this );

    QHBoxLayout* plotLayout = new QHBoxLayout();
    plotLayout->addWidget( m_fvfPlot );
    plotLayout->addWidget( m_viscosityPlot );
    plotLayout->setSpacing( 0 );
    plotLayout->setContentsMargins( 0, 0, 0, 0 );

    QVBoxLayout* mainLayout = new QVBoxLayout();
    mainLayout->addLayout( topLayout );
    mainLayout->addLayout( plotLayout );
    mainLayout->setContentsMargins( 0, 0, 0, 0 );

    setLayout( mainLayout );

    connect( m_phaseComboBox, SIGNAL( currentIndexChanged( int ) ), SLOT( slotPhaseComboCurrentIndexChanged( int ) ) );

    plotUiSelectedCurves();
}

//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RiuPvtPlotPanel::~RiuPvtPlotPanel()
{
}

//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RiuPvtPlotPanel::setPlotData( RiaDefines::EclipseUnitSystem                            unitSystem,
                                   const std::vector<RigFlowDiagSolverInterface::PvtCurve>& fvfCurveArr,
                                   const std::vector<RigFlowDiagSolverInterface::PvtCurve>& viscosityCurveArr,
                                   const FvfDynProps&                                       fvfDynProps,
                                   const ViscosityDynProps&                                 viscosityDynProps,
                                   const CellValues&                                        cellValues,
                                   const QString&                                           cellReferenceText )
{
    // cvf::Trace::show("RiuPvtPlotPanel::setPlotData()");

    m_unitSystem            = unitSystem;
    m_allFvfCurvesArr       = fvfCurveArr;
    m_allViscosityCurvesArr = viscosityCurveArr;
    m_fvfDynProps           = fvfDynProps;
    m_viscosityDynProps     = viscosityDynProps;
    m_cellValues            = cellValues;
    m_cellReferenceText     = cellReferenceText;

    plotUiSelectedCurves();
}

//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RiuPvtPlotPanel::clearPlot()
{
    // cvf::Trace::show("RiuPvtPlotPanel::clearPlot()");

    if ( m_allFvfCurvesArr.empty() && m_allViscosityCurvesArr.empty() && m_cellReferenceText.isEmpty() )
    {
        return;
    }

    m_unitSystem = RiaDefines::EclipseUnitSystem::UNITS_UNKNOWN;
    m_allFvfCurvesArr.clear();
    m_allViscosityCurvesArr.clear();
    m_fvfDynProps       = FvfDynProps();
    m_viscosityDynProps = ViscosityDynProps();
    m_cellValues        = CellValues();
    m_cellReferenceText.clear();

    plotUiSelectedCurves();
}

//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RiuPvtPlotUpdater* RiuPvtPlotPanel::plotUpdater()
{
    return m_plotUpdater.get();
}

//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RiuPvtPlotPanel::applyFontSizes( bool replot )
{
    if ( m_fvfPlot ) m_fvfPlot->applyFontSizes( replot );
    if ( m_viscosityPlot ) m_viscosityPlot->applyFontSizes( replot );
}

//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RiuPvtPlotPanel::plotUiSelectedCurves()
{
    // Determine which curves (phase) to actually plot based on selection in GUI
    const int                                         currComboIdx = m_phaseComboBox->currentIndex();
    const RigFlowDiagSolverInterface::PvtCurve::Phase phaseToPlot =
        static_cast<RigFlowDiagSolverInterface::PvtCurve::Phase>( m_phaseComboBox->itemData( currComboIdx ).toInt() );

    QString phaseString = "";
    if ( phaseToPlot == RigFlowDiagSolverInterface::PvtCurve::GAS )
    {
        phaseString = "Gas ";
    }
    else if ( phaseToPlot == RigFlowDiagSolverInterface::PvtCurve::OIL )
    {
        phaseString = "Oil ";
    }

    // FVF plot
    {
        RigFlowDiagSolverInterface::PvtCurve::Ident curveIdentToPlot    = RigFlowDiagSolverInterface::PvtCurve::Unknown;
        double                                      pointMarkerFvfValue = HUGE_VAL;
        QString                                     pointMarkerLabel    = "";

        if ( phaseToPlot == RigFlowDiagSolverInterface::PvtCurve::GAS )
        {
            curveIdentToPlot    = RigFlowDiagSolverInterface::PvtCurve::Bg;
            pointMarkerFvfValue = m_fvfDynProps.bg;
            pointMarkerLabel    = QString( "%1 (%2)" ).arg( pointMarkerFvfValue ).arg( m_cellValues.pressure );
            if ( m_cellValues.rv != HUGE_VAL )
            {
                pointMarkerLabel += QString( "\nRv = %1" ).arg( m_cellValues.rv );
            }
        }
        else if ( phaseToPlot == RigFlowDiagSolverInterface::PvtCurve::OIL )
        {
            curveIdentToPlot    = RigFlowDiagSolverInterface::PvtCurve::Bo;
            pointMarkerFvfValue = m_fvfDynProps.bo;
            pointMarkerLabel    = QString( "%1 (%2)" ).arg( pointMarkerFvfValue ).arg( m_cellValues.pressure );
            if ( m_cellValues.rs != HUGE_VAL )
            {
                pointMarkerLabel += QString( "\nRs = %1" ).arg( m_cellValues.rs );
            }
        }

        std::vector<RigFlowDiagSolverInterface::PvtCurve> selectedFvfCurves;
        for ( RigFlowDiagSolverInterface::PvtCurve curve : m_allFvfCurvesArr )
        {
            if ( curve.ident == curveIdentToPlot )
            {
                selectedFvfCurves.push_back( curve );
            }
        }

        const QString plotTitle = QString( "%1 Formation Volume Factor" ).arg( phaseString );
        const QString yAxisTitle =
            QString( "%1 Formation Volume Factor [%2]" ).arg( phaseString ).arg( unitLabelFromCurveIdent( m_unitSystem, curveIdentToPlot ) );
        m_fvfPlot->plotCurves( m_unitSystem, selectedFvfCurves, m_cellValues.pressure, pointMarkerFvfValue, pointMarkerLabel, plotTitle, yAxisTitle );
    }

    // Viscosity plot
    {
        RigFlowDiagSolverInterface::PvtCurve::Ident curveIdentToPlot          = RigFlowDiagSolverInterface::PvtCurve::Unknown;
        double                                      pointMarkerViscosityValue = HUGE_VAL;
        QString                                     pointMarkerLabel          = "";

        if ( phaseToPlot == RigFlowDiagSolverInterface::PvtCurve::GAS )
        {
            curveIdentToPlot          = RigFlowDiagSolverInterface::PvtCurve::Visc_g;
            pointMarkerViscosityValue = m_viscosityDynProps.mu_g;
            pointMarkerLabel          = QString( "%1 (%2)" ).arg( pointMarkerViscosityValue ).arg( m_cellValues.pressure );
            if ( m_cellValues.rv != HUGE_VAL )
            {
                pointMarkerLabel += QString( "\nRv = %1" ).arg( m_cellValues.rv );
            }
        }
        else if ( phaseToPlot == RigFlowDiagSolverInterface::PvtCurve::OIL )
        {
            curveIdentToPlot          = RigFlowDiagSolverInterface::PvtCurve::Visc_o;
            pointMarkerViscosityValue = m_viscosityDynProps.mu_o;
            pointMarkerLabel          = QString( "%1 (%2)" ).arg( pointMarkerViscosityValue ).arg( m_cellValues.pressure );
            if ( m_cellValues.rs != HUGE_VAL )
            {
                pointMarkerLabel += QString( "\nRs = %1" ).arg( m_cellValues.rs );
            }
        }

        std::vector<RigFlowDiagSolverInterface::PvtCurve> selectedViscosityCurves;
        for ( RigFlowDiagSolverInterface::PvtCurve curve : m_allViscosityCurvesArr )
        {
            if ( curve.ident == curveIdentToPlot )
            {
                selectedViscosityCurves.push_back( curve );
            }
        }

        const QString plotTitle = QString( "%1 Viscosity" ).arg( phaseString );
        const QString yAxisTitle =
            QString( "%1 Viscosity [%2]" ).arg( phaseString ).arg( unitLabelFromCurveIdent( m_unitSystem, curveIdentToPlot ) );
        m_viscosityPlot->plotCurves( m_unitSystem,
                                     selectedViscosityCurves,
                                     m_cellValues.pressure,
                                     pointMarkerViscosityValue,
                                     pointMarkerLabel,
                                     plotTitle,
                                     yAxisTitle );
    }

    // Update the label on top in our panel
    QString titleStr = "PVT";
    if ( !m_cellReferenceText.isEmpty() )
    {
        titleStr += ", " + m_cellReferenceText;
    }

    m_titleLabel->setText( titleStr );
}

//--------------------------------------------------------------------------------------------------
/// Static helper to get unit labels
//--------------------------------------------------------------------------------------------------
QString RiuPvtPlotPanel::unitLabelFromCurveIdent( RiaDefines::EclipseUnitSystem               unitSystem,
                                                  RigFlowDiagSolverInterface::PvtCurve::Ident curveIdent )
{
    if ( curveIdent == RigFlowDiagSolverInterface::PvtCurve::Bo )
    {
        switch ( unitSystem )
        {
            case RiaDefines::EclipseUnitSystem::UNITS_METRIC:
                return "rm3/sm3";
            case RiaDefines::EclipseUnitSystem::UNITS_FIELD:
                return "rb/stb";
            case RiaDefines::EclipseUnitSystem::UNITS_LAB:
                return "rcc/scc";
            default:
                return "";
        }
    }
    else if ( curveIdent == RigFlowDiagSolverInterface::PvtCurve::Bg )
    {
        switch ( unitSystem )
        {
            case RiaDefines::EclipseUnitSystem::UNITS_METRIC:
                return "rm3/sm3";
            case RiaDefines::EclipseUnitSystem::UNITS_FIELD:
                return "rb/Mscf";
            case RiaDefines::EclipseUnitSystem::UNITS_LAB:
                return "rcc/scc";
            default:
                return "";
        }
    }
    else if ( curveIdent == RigFlowDiagSolverInterface::PvtCurve::Visc_o || curveIdent == RigFlowDiagSolverInterface::PvtCurve::Visc_g )
    {
        switch ( unitSystem )
        {
            case RiaDefines::EclipseUnitSystem::UNITS_METRIC:
                return "cP";
            case RiaDefines::EclipseUnitSystem::UNITS_FIELD:
                return "cP";
            case RiaDefines::EclipseUnitSystem::UNITS_LAB:
                return "cP";
            default:
                return "";
        }
    }

    return "";
}

//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RiuPvtPlotPanel::slotPhaseComboCurrentIndexChanged( int )
{
    plotUiSelectedCurves();
}
