/////////////////////////////////////////////////////////////////////////////////
//
//  Copyright (C) 2016 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 "RicSummaryPlotEditorUi.h"

#include "RiaColorTables.h"
#include "RiaCurveSetDefinition.h"
#include "RiaGuiApplication.h"
#include "RiaSummaryCurveDefinition.h"

#include "RiuSummaryCurveDefinitionKeywords.h"

#include "RimDerivedEnsembleCaseCollection.h"
#include "RimEnsembleCurveSet.h"
#include "RimEnsembleCurveSetCollection.h"
#include "RimEnsembleCurveSetColorManager.h"
#include "RimMainPlotCollection.h"
#include "RimObservedDataCollection.h"
#include "RimObservedSummaryData.h"
#include "RimOilField.h"
#include "RimProject.h"
#include "RimSummaryCalculationCollection.h"
#include "RimSummaryCase.h"
#include "RimSummaryCaseCollection.h"
#include "RimSummaryCaseMainCollection.h"
#include "RimSummaryCurve.h"
#include "RimSummaryCurveAutoName.h"
#include "RimSummaryCurveCollection.h"
#include "RimSummaryMultiPlot.h"
#include "RimSummaryPlot.h"

#include "RiuPlotMainWindow.h"
#include "RiuPlotMainWindowTools.h"
#include "RiuSummaryQwtPlot.h"
#include "RiuSummaryVectorSelectionUi.h"
#include "RiuTools.h"

#include "PlotBuilderCommands/RicSummaryPlotBuilder.h"

#include "cafPdmUiComboBoxEditor.h"
#include "cafPdmUiPushButtonEditor.h"

#include <QInputDialog>
#include <QMessageBox>

#include <algorithm>
#include <sstream>

CAF_PDM_SOURCE_INIT( RicSummaryPlotEditorUi, "RicSummaryCurveCreator" );

//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
const size_t ENSEMBLE_CURVE_COUNT_THRESHOLD = 600;

//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
const QString RicSummaryPlotEditorUi::CONFIGURATION_NAME = "CurveCreatorCfg";

//--------------------------------------------------------------------------------------------------
/// Internal functions
//--------------------------------------------------------------------------------------------------
int ensembleCurveCount( const std::set<RiaSummaryCurveDefinition>& allCurveDefs );
template <typename T>
std::vector<T> toVector( const std::set<T>& set );

//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RicSummaryPlotEditorUi::RicSummaryPlotEditorUi()
    : m_plotContainer( nullptr )
{
    CAF_PDM_InitFieldNoDefault( &m_targetPlot, "TargetPlot", "Target Plot" );

    CAF_PDM_InitField( &m_useAutoAppearanceAssignment, "UseAutoAppearanceAssignment", true, "Auto" );
    CAF_PDM_InitField( &m_appearanceApplyButton, "AppearanceApplyButton", false, "" );
    CAF_PDM_InitFieldNoDefault( &m_caseAppearanceType, "CaseAppearanceType", "Case" );
    CAF_PDM_InitFieldNoDefault( &m_variableAppearanceType, "VariableAppearanceType", "Vector" );
    CAF_PDM_InitFieldNoDefault( &m_wellAppearanceType, "WellAppearanceType", "Well" );
    CAF_PDM_InitFieldNoDefault( &m_groupAppearanceType, "GroupAppearanceType", "Group" );
    CAF_PDM_InitFieldNoDefault( &m_regionAppearanceType, "RegionAppearanceType", "Region" );

    m_previewPlot = std::make_unique<RimSummaryPlot>();

    CAF_PDM_InitFieldNoDefault( &m_useAutoPlotTitleProxy, "UseAutoPlotTitle", "Auto Plot Title" );
    m_useAutoPlotTitleProxy.registerGetMethod( this, &RicSummaryPlotEditorUi::proxyPlotAutoTitle );
    m_useAutoPlotTitleProxy.registerSetMethod( this, &RicSummaryPlotEditorUi::proxyEnablePlotAutoTitle );

    CAF_PDM_InitFieldNoDefault( &m_applyButtonField, "ApplySelection", "" );
    m_applyButtonField = false;
    m_applyButtonField.uiCapability()->setUiEditorTypeName( caf::PdmUiPushButtonEditor::uiEditorTypeName() );
    m_applyButtonField.uiCapability()->setUiLabelPosition( caf::PdmUiItemInfo::HIDDEN );

    CAF_PDM_InitFieldNoDefault( &m_closeButtonField, "Close", "" );
    m_closeButtonField = false;
    m_closeButtonField.uiCapability()->setUiEditorTypeName( caf::PdmUiPushButtonEditor::uiEditorTypeName() );
    m_closeButtonField.uiCapability()->setUiLabelPosition( caf::PdmUiItemInfo::HIDDEN );

    CAF_PDM_InitFieldNoDefault( &m_okButtonField, "OK", "" );
    m_okButtonField = false;
    m_okButtonField.uiCapability()->setUiEditorTypeName( caf::PdmUiPushButtonEditor::uiEditorTypeName() );
    m_okButtonField.uiCapability()->setUiLabelPosition( caf::PdmUiItemInfo::HIDDEN );

    m_appearanceApplyButton = false;
    m_appearanceApplyButton.uiCapability()->setUiEditorTypeName( caf::PdmUiPushButtonEditor::uiEditorTypeName() );
    m_appearanceApplyButton.uiCapability()->setUiLabelPosition( caf::PdmUiItemInfo::LEFT );

    CAF_PDM_InitFieldNoDefault( &m_curveNameConfig, "SummaryCurveNameConfig", "SummaryCurveNameConfig" );
    m_curveNameConfig = new RimSummaryCurveAutoName();
    m_curveNameConfig.uiCapability()->setUiTreeHidden( true );
    m_curveNameConfig.uiCapability()->setUiTreeChildrenHidden( true );

    m_summaryCurveSelectionEditor = std::make_unique<RiuSummaryVectorSelectionWidgetCreator>();

    m_summaryCurveSelectionEditor->summaryAddressSelection()->setFieldChangedHandler( [this]() { this->selectionEditorFieldChanged(); } );
    m_summaryCurveSelectionEditor->summaryAddressSelection()->setMultiSelectionMode( true );
}

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

//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RimSummaryPlot* RicSummaryPlotEditorUi::previewPlot() const
{
    return m_previewPlot.get();
}

//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RicSummaryPlotEditorUi::updateFromSummaryPlot( RimSummaryPlot* targetPlot, const std::vector<SummarySource*>& defaultSources )
{
    if ( targetPlot == nullptr || m_targetPlot != targetPlot )
    {
        resetAllFields();
    }

    m_targetPlot                  = targetPlot;
    m_useAutoAppearanceAssignment = true;

    if ( m_targetPlot )
    {
        RimSummaryMultiPlot* parentPlot = nullptr;
        m_targetPlot->firstAncestorOfType( parentPlot );
        m_plotContainer = parentPlot;

        populateCurveCreator( *m_targetPlot );
        syncPreviewCurvesFromUiSelection();
        setInitialCurveVisibility( targetPlot );
        m_previewPlot->loadDataAndUpdate();
    }
    else
    {
        setDefaultCurveSelection( defaultSources );
        m_previewPlot->enableAutoPlotTitle( true );
        syncPreviewCurvesFromUiSelection();
        m_plotContainer = nullptr;
    }

    caf::PdmUiItem::updateConnectedEditors();
}

//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RicSummaryPlotEditorUi::updateFromSummaryMultiPlot( RimSummaryMultiPlot*               summaryMultiPlot,
                                                         const std::vector<SummarySource*>& defaultSources )
{
    resetAllFields();

    m_useAutoAppearanceAssignment = true;

    m_plotContainer = summaryMultiPlot;

    setDefaultCurveSelection( defaultSources );

    caf::PdmUiItem::updateConnectedEditors();
}

//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QWidget* RicSummaryPlotEditorUi::addressSelectionWidget( QWidget* parent )
{
    return m_summaryCurveSelectionEditor->getOrCreateWidget( parent );
}

//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RicSummaryPlotEditorUi::isCloseButtonPressed() const
{
    return m_closeButtonField();
}

//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RicSummaryPlotEditorUi::clearCloseButton()
{
    m_closeButtonField = false;
}

//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RicSummaryPlotEditorUi::fieldChangedByUi( const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue )
{
    if ( changedField == &m_applyButtonField || changedField == &m_okButtonField )
    {
        if ( m_targetPlot == nullptr )
        {
            createNewPlot();
        }

        updateTargetPlot();

        if ( changedField == &m_okButtonField )
        {
            m_closeButtonField = true;

            RiuPlotMainWindowTools::showPlotMainWindow();
            RiuPlotMainWindowTools::selectAsCurrentItem( m_targetPlot );
            RiuPlotMainWindowTools::setExpanded( m_targetPlot );
        }

        m_applyButtonField = false;
        m_okButtonField    = false;

        caf::PdmField<bool>* field = dynamic_cast<caf::PdmField<bool>*>( m_targetPlot->uiCapability()->objectToggleField() );
        field->setValueWithFieldChanged( true );

        RiuPlotMainWindow* mainPlotWindow = RiaGuiApplication::instance()->mainPlotWindow();
        mainPlotWindow->updateMultiPlotToolBar();
    }
    else if ( changedField == &m_useAutoAppearanceAssignment && m_useAutoAppearanceAssignment )
    {
        updateAppearanceEditor();
    }
    else if ( changedField == &m_appearanceApplyButton )
    {
        applyAppearanceToAllPreviewCurves();
        m_previewPlot->loadDataAndUpdate();
        m_appearanceApplyButton = false;
    }
    else if ( changedField == &m_useAutoPlotTitleProxy )
    {
        m_previewPlot->updatePlotTitle();

        m_previewPlot->summaryCurveCollection()->updateConnectedEditors();
    }
}

//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QList<caf::PdmOptionItemInfo> RicSummaryPlotEditorUi::calculateValueOptions( const caf::PdmFieldHandle* fieldNeedingOptions )
{
    QList<caf::PdmOptionItemInfo> options;

    if ( fieldNeedingOptions == &m_targetPlot )
    {
        // Create New Plot item
        QString displayName = "( New Plot )";
        options.push_back( caf::PdmOptionItemInfo( displayName, nullptr ) );

        if ( m_plotContainer )
        {
            m_plotContainer->summaryPlotItemInfos( &options );
        }
    }

    return options;
}

//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RicSummaryPlotEditorUi::defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering& uiOrdering )
{
    // Appearance settings
    caf::PdmUiGroup* appearanceGroup =
        uiOrdering.addNewGroupWithKeyword( "Curve Appearance Assignment", RiuSummaryCurveDefinitionKeywords::appearance() );

    caf::PdmUiGroup* appearanceSubGroup = appearanceGroup->addNewGroup( "Appearance Type Assignment" );
    appearanceSubGroup->setCollapsedByDefault();

    appearanceSubGroup->add( &m_useAutoAppearanceAssignment );
    appearanceSubGroup->add( &m_caseAppearanceType );
    appearanceSubGroup->add( &m_variableAppearanceType );
    appearanceSubGroup->add( &m_wellAppearanceType );
    appearanceSubGroup->add( &m_groupAppearanceType );
    appearanceSubGroup->add( &m_regionAppearanceType );

    appearanceGroup->add( &m_appearanceApplyButton );

    // Appearance option sensitivity
    {
        m_caseAppearanceType.uiCapability()->setUiReadOnly( m_useAutoAppearanceAssignment );
        m_variableAppearanceType.uiCapability()->setUiReadOnly( m_useAutoAppearanceAssignment );
        m_wellAppearanceType.uiCapability()->setUiReadOnly( m_useAutoAppearanceAssignment );
        m_groupAppearanceType.uiCapability()->setUiReadOnly( m_useAutoAppearanceAssignment );
        m_regionAppearanceType.uiCapability()->setUiReadOnly( m_useAutoAppearanceAssignment );
    }

    // Name config
    caf::PdmUiGroup* autoNameGroup =
        uiOrdering.addNewGroupWithKeyword( "Plot and Curve Name Configuration", RiuSummaryCurveDefinitionKeywords::nameConfig() );
    autoNameGroup->setCollapsedByDefault();

    autoNameGroup->add( &m_useAutoPlotTitleProxy );

    m_curveNameConfig->uiOrdering( uiConfigName, *autoNameGroup );

    // Fields to be displayed directly in UI
    uiOrdering.add( &m_targetPlot );
    uiOrdering.add( &m_okButtonField );
    uiOrdering.add( &m_applyButtonField );
    uiOrdering.add( &m_closeButtonField );

    uiOrdering.skipRemainingFields( true );

    syncPreviewCurvesFromUiSelection();

    m_summaryCurveSelectionEditor->updateUi( uiConfigName );
}

//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RicSummaryPlotEditorUi::syncPreviewCurvesFromUiSelection()
{
    std::vector<RiaSummaryCurveDefinition> allCurveDefinitionsVector =
        m_summaryCurveSelectionEditor->summaryAddressSelection()->allCurveDefinitionsFromSelection();

    auto curveSetDefs = m_summaryCurveSelectionEditor->summaryAddressSelection()->allCurveSetDefinitionsFromSelections();
    for ( const auto& curveSet : curveSetDefs )
    {
        allCurveDefinitionsVector.emplace_back( curveSet.ensemble(), curveSet.summaryAddress() );
    }

    std::set<RiaSummaryCurveDefinition> allCurveDefinitions =
        std::set<RiaSummaryCurveDefinition>( allCurveDefinitionsVector.begin(), allCurveDefinitionsVector.end() );

    std::vector<RimSummaryCurve*> currentCurvesInPreviewPlot = m_previewPlot->summaryAndEnsembleCurves();

    {
        std::set<RiaSummaryCurveDefinition> currentCurveDefs;
        std::set<RiaSummaryCurveDefinition> newCurveDefs;
        std::set<RimSummaryCurve*>          curvesToDelete;

        for ( const auto& curve : currentCurvesInPreviewPlot )
        {
            currentCurveDefs.insert( curve->curveDefinitionY() );
        }

        {
            // Determine which curves to delete from plot
            std::set<RiaSummaryCurveDefinition> deleteCurveDefs;
            std::set_difference( currentCurveDefs.begin(),
                                 currentCurveDefs.end(),
                                 allCurveDefinitions.begin(),
                                 allCurveDefinitions.end(),
                                 std::inserter( deleteCurveDefs, deleteCurveDefs.end() ) );

            for ( const auto& curve : currentCurvesInPreviewPlot )
            {
                RiaSummaryCurveDefinition curveDef = curve->curveDefinitionY();
                if ( deleteCurveDefs.count( curveDef ) > 0 ) curvesToDelete.insert( curve );
            }
        }

        {
            // Determine which curves are new since last time
            std::set_difference( allCurveDefinitions.begin(),
                                 allCurveDefinitions.end(),
                                 currentCurveDefs.begin(),
                                 currentCurveDefs.end(),
                                 std::inserter( newCurveDefs, newCurveDefs.end() ) );
        }

        // Curve sets to delete
        std::set<RimEnsembleCurveSet*> curveSetsToDelete;
        {
            std::vector<RiaCurveSetDefinition> allCurveSetDefinitionsVector =
                m_summaryCurveSelectionEditor->summaryAddressSelection()->allCurveSetDefinitionsFromSelections();
            std::set<RiaCurveSetDefinition> allCurveSetDefinitions =
                std::set<RiaCurveSetDefinition>( allCurveSetDefinitionsVector.begin(), allCurveSetDefinitionsVector.end() );
            std::vector<RimEnsembleCurveSet*> currentCurveSetsInPreviewPlot = m_previewPlot->curveSets();
            std::set<RiaCurveSetDefinition>   currentCurveSetDefs;

            for ( const auto& curveSet : currentCurveSetsInPreviewPlot )
            {
                RimSummaryCaseCollection* ensemble = curveSet->summaryCaseCollection();
                currentCurveSetDefs.insert( RiaCurveSetDefinition( ensemble, curveSet->summaryAddress() ) );
            }

            if ( allCurveSetDefinitions.size() < currentCurveSetsInPreviewPlot.size() )
            {
                // Determine which curves to delete from plot
                std::set<RiaCurveSetDefinition> deleteCurveSetDefs;
                std::set_difference( currentCurveSetDefs.begin(),
                                     currentCurveSetDefs.end(),
                                     allCurveSetDefinitions.begin(),
                                     allCurveSetDefinitions.end(),
                                     std::inserter( deleteCurveSetDefs, deleteCurveSetDefs.end() ) );

                for ( const auto& curveSet : currentCurveSetsInPreviewPlot )
                {
                    RimSummaryCaseCollection* ensemble    = curveSet->summaryCaseCollection();
                    RiaCurveSetDefinition     curveSetDef = RiaCurveSetDefinition( ensemble, curveSet->summaryAddress() );
                    if ( deleteCurveSetDefs.count( curveSetDef ) > 0 ) curveSetsToDelete.insert( curveSet );
                }
            }
        }

        updatePreviewCurvesFromCurveDefinitions( allCurveDefinitions, newCurveDefs, curvesToDelete, curveSetsToDelete );
    }
}

//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RicSummaryPlotEditorUi::updatePreviewCurvesFromCurveDefinitions( const std::set<RiaSummaryCurveDefinition>& allCurveDefsToDisplay,
                                                                      const std::set<RiaSummaryCurveDefinition>& curveDefsToAdd,
                                                                      const std::set<RimSummaryCurve*>&          curvesToDelete,
                                                                      const std::set<RimEnsembleCurveSet*>&      curveSetsToDelete )
{
    static bool warningDisplayed = false;

    std::set<RiaSummaryCurveDefinition> summaryCurveDefsToDisplay;

    // Ignore curve sets when assigning colors to singe summary curves
    for ( const auto& def : allCurveDefsToDisplay )
    {
        if ( !def.isEnsembleCurve() ) summaryCurveDefsToDisplay.insert( def );
    }

    RimSummaryCurveAppearanceCalculator curveLookCalc( summaryCurveDefsToDisplay );
    initCurveAppearanceCalculator( curveLookCalc );

    // Delete curves
    if ( !curveSetsToDelete.empty() )
    {
        m_previewPlot->ensembleCurveSetCollection()->deleteCurveSets( toVector( curveSetsToDelete ) );
    }
    if ( !curvesToDelete.empty() )
    {
        m_previewPlot->deleteCurves( toVector( curvesToDelete ) );
    }

    size_t ensembleCurveCnt = ensembleCurveCount( allCurveDefsToDisplay );

    bool speedCheatsRequired = ensembleCurveCnt > ENSEMBLE_CURVE_COUNT_THRESHOLD;
    bool legendsVisible      = m_previewPlot->legendsVisible();

    // Disable legends when adding curves
    if ( speedCheatsRequired ) m_previewPlot->setLegendsVisible( false );

    // Add new curves
    std::map<RimSummaryCurve*, std::pair<bool, bool>> stashedErrorBarsAndLegendVisibility;
    for ( const auto& curveDef : curveDefsToAdd )
    {
        RimSummaryCase* currentCase = curveDef.summaryCase();

        if ( curveDef.isEnsembleCurve() )
        {
            // Find curveSet
            RimEnsembleCurveSet* curveSet = nullptr;
            for ( const auto& cs : m_previewPlot->ensembleCurveSetCollection()->curveSets() )
            {
                if ( cs->summaryCaseCollection() == curveDef.ensemble() && cs->summaryAddress() == curveDef.summaryAddress() )
                {
                    curveSet = cs;
                    break;
                }
            }
            if ( !curveSet )
            {
                curveSet = new RimEnsembleCurveSet();
                curveSet->disableStatisticCurves();
                curveSet->setSummaryCaseCollection( curveDef.ensemble() );

                // Do not call setSummaryAddressAndStatisticsFlag() here, as the call to m_statistics->updateAllRequiredEditors(); causes a
                // crash in updateUiOrdering. The statistics curves will be created when the curve set is added to the plot.
                curveSet->setSummaryAddress( curveDef.summaryAddress() );

                // Set single curve set color
                auto   allCurveSets = m_previewPlot->ensembleCurveSetCollection()->curveSets();
                size_t colorIndex =
                    std::count_if( allCurveSets.begin(),
                                   allCurveSets.end(),
                                   []( RimEnsembleCurveSet* curveSet )
                                   { return RimEnsembleCurveSetColorManager::hasSameColorForAllRealizationCurves( curveSet->colorMode() ); } );
                curveSet->setColor( RiaColorTables::summaryCurveDefaultPaletteColors().cycledColor3f( colorIndex ) );

                // Add curve to plot
                m_previewPlot->ensembleCurveSetCollection()->addCurveSet( curveSet );

                if ( m_previewPlot->ensembleCurveSetCollection()->curveSets().size() > 1 && ensembleCurveCnt > ENSEMBLE_CURVE_COUNT_THRESHOLD )
                {
                    // Toggle off new curve set and display warning
                    curveSet->showCurves( false );

                    if ( !warningDisplayed )
                    {
                        QMessageBox mbox;
                        mbox.setIcon( QMessageBox::Icon::Warning );
                        mbox.setInformativeText( "The new curve set is hidden. Too many visible curve sets may lead to poor performance" );
                        mbox.exec();
                        warningDisplayed = true;
                    }
                }
            }
        }
        else
        {
            RimSummaryCurve* curve = new RimSummaryCurve();
            if ( speedCheatsRequired )
            {
                stashedErrorBarsAndLegendVisibility[curve] = std::make_pair( curve->errorBarsVisible(), curve->showInLegend() );
                curve->setErrorBarsVisible( false );
                curve->setShowInLegend( false );
            }
            curve->setSummaryCaseY( currentCase );
            curve->setSummaryAddressYAndApplyInterpolation( curveDef.summaryAddress() );
            curve->applyCurveAutoNameSettings( *m_curveNameConfig() );
            if ( currentCase && currentCase->isObservedData() ) curve->setSymbolSkipDistance( 0 );

            m_previewPlot->addCurveNoUpdate( curve );
            curveLookCalc.setupCurveLook( curve );
        }
    }

    // Enable legends if there is not too many curves
    if ( speedCheatsRequired && !warningDisplayed )
    {
        m_previewPlot->setLegendsVisible( legendsVisible );

        for ( const auto& curveAndVisibilityPair : stashedErrorBarsAndLegendVisibility )
        {
            auto curve                        = curveAndVisibilityPair.first;
            auto errorBarsAndLegendVisibility = curveAndVisibilityPair.second;
            curve->setErrorBarsVisible( errorBarsAndLegendVisibility.first );
            curve->setShowInLegend( errorBarsAndLegendVisibility.second );
        }
    }
    m_previewPlot->loadDataAndUpdate();
    m_previewPlot->zoomAll();
    m_previewPlot->updateConnectedEditors();
    m_previewPlot->summaryCurveCollection()->updateConnectedEditors();
}

//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RicSummaryPlotEditorUi::defineEditorAttribute( const caf::PdmFieldHandle* field, QString uiConfigName, caf::PdmUiEditorAttribute* attribute )
{
    if ( &m_applyButtonField == field )
    {
        caf::PdmUiPushButtonEditorAttribute* attrib = dynamic_cast<caf::PdmUiPushButtonEditorAttribute*>( attribute );
        if ( attrib )
        {
            attrib->m_buttonText = "Apply";
        }
    }
    else if ( &m_closeButtonField == field )
    {
        caf::PdmUiPushButtonEditorAttribute* attrib = dynamic_cast<caf::PdmUiPushButtonEditorAttribute*>( attribute );
        if ( attrib )
        {
            attrib->m_buttonText = "Cancel";
        }
    }
    else if ( &m_okButtonField == field )
    {
        caf::PdmUiPushButtonEditorAttribute* attrib = dynamic_cast<caf::PdmUiPushButtonEditorAttribute*>( attribute );
        if ( attrib )
        {
            attrib->m_buttonText = "OK";
        }
    }
    else if ( &m_appearanceApplyButton == field )
    {
        caf::PdmUiPushButtonEditorAttribute* attrib = dynamic_cast<caf::PdmUiPushButtonEditorAttribute*>( attribute );
        if ( attrib )
        {
            attrib->m_buttonText = "Apply";
        }
    }
    else if ( &m_targetPlot == field )
    {
        caf::PdmUiComboBoxEditorAttribute* attrib = dynamic_cast<caf::PdmUiComboBoxEditorAttribute*>( attribute );
        if ( attrib )
        {
            attrib->adjustWidthToContents = true;
        }
    }
}

//--------------------------------------------------------------------------------------------------
/// Populate curve creator from the given curve collection
//--------------------------------------------------------------------------------------------------
void RicSummaryPlotEditorUi::populateCurveCreator( const RimSummaryPlot& sourceSummaryPlot )
{
    std::vector<RiaSummaryCurveDefinition> curveDefs;

    m_previewPlot->deleteAllSummaryCurves();
    m_previewPlot->ensembleCurveSetCollection()->deleteAllCurveSets();

    for ( const auto& curve : sourceSummaryPlot.summaryCurves() )
    {
        curveDefs.push_back( curve->curveDefinitionY() );

        // Copy curve object to the preview plot
        copyCurveAndAddToPlot( curve, m_previewPlot.get(), true );
    }

    RimEnsembleCurveSetCollection* previewCurveSetColl = m_previewPlot->ensembleCurveSetCollection();
    for ( const auto& curveSet : sourceSummaryPlot.ensembleCurveSetCollection()->curveSets() )
    {
        RimEnsembleCurveSet* newCurveSet = curveSet->clone();
        newCurveSet->disableStatisticCurves();
        previewCurveSetColl->addCurveSet( newCurveSet );

        RimSummaryCaseCollection* ensemble = curveSet->summaryCaseCollection();
        curveDefs.emplace_back( ensemble, curveSet->summaryAddress() );
    }

    m_previewPlot->copyAxisPropertiesFromOther( sourceSummaryPlot );
    m_previewPlot->enableAutoPlotTitle( sourceSummaryPlot.autoPlotTitle() );
    m_previewPlot->updatePlotTitle();
    m_previewPlot->updateAxes();

    if ( curveDefs.empty() )
    {
        auto sumCases = RimProject::current()->allSummaryCases();
        if ( !sumCases.empty() )
        {
            RifEclipseSummaryAddress  defaultAdr;
            RiaSummaryCurveDefinition curveDef( sumCases.front(), defaultAdr, false );
            curveDefs.push_back( curveDef );
        }
    }

    m_summaryCurveSelectionEditor->summaryAddressSelection()->setSelectedCurveDefinitions( curveDefs );

    updateAppearanceEditor();
}

//--------------------------------------------------------------------------------------------------
/// Copy curves from preview plot to target plot
//--------------------------------------------------------------------------------------------------
void RicSummaryPlotEditorUi::updateTargetPlot()
{
    if ( !m_targetPlot ) return;

    m_targetPlot->deleteAllSummaryCurves();
    m_targetPlot->ensembleCurveSetCollection()->deleteAllCurveSets();

    // Add edited curves to target plot
    for ( const auto& editedCurve : m_previewPlot->summaryCurves() )
    {
        if ( !editedCurve->isChecked() )
        {
            continue;
        }
        copyCurveAndAddToPlot( editedCurve, m_targetPlot );
    }

    for ( const auto& editedCurveSet : m_previewPlot->ensembleCurveSetCollection()->curveSets() )
    {
        if ( !editedCurveSet->isCurvesVisible() )
        {
            continue;
        }

        RimEnsembleCurveSet* newCurveSet = editedCurveSet->clone();
        m_targetPlot->ensembleCurveSetCollection()->addCurveSet( newCurveSet );
        for ( const auto& editedCurve : newCurveSet->curves() )
        {
            copyEnsembleCurveAndAddToCurveSet( editedCurve, editedCurveSet );
        }

        newCurveSet->setParentPlotNoReplot( m_targetPlot->plotWidget() );
    }

    m_targetPlot->enableAutoPlotTitle( m_useAutoPlotTitleProxy() );

    m_targetPlot->loadDataAndUpdate();

    m_targetPlot->updateConnectedEditors();
    m_targetPlot->curvesChanged.send();
}

//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RicSummaryPlotEditorUi::copyCurveAndAddToPlot( const RimSummaryCurve* curve, RimSummaryPlot* plot, bool forceVisible )
{
    RimSummaryCurve* curveCopy =
        dynamic_cast<RimSummaryCurve*>( curve->xmlCapability()->copyByXmlSerialization( caf::PdmDefaultObjectFactory::instance() ) );
    CVF_ASSERT( curveCopy );

    if ( forceVisible )
    {
        curveCopy->setCheckState( true );
    }

    plot->addCurveNoUpdate( curveCopy, false );
    curveCopy->setLeftOrRightAxisY( curve->axisY() );

    // The curve creator is not a descendant of the project, and need to be set manually
    curveCopy->setSummaryCaseY( curve->summaryCaseY() );
    curveCopy->initAfterReadRecursively();
    curveCopy->loadDataAndUpdate( false );
}

//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RicSummaryPlotEditorUi::copyEnsembleCurveAndAddToCurveSet( const RimSummaryCurve* curve, RimEnsembleCurveSet* curveSet, bool forceVisible )
{
    RimSummaryCurve* curveCopy =
        dynamic_cast<RimSummaryCurve*>( curve->xmlCapability()->copyByXmlSerialization( caf::PdmDefaultObjectFactory::instance() ) );
    CVF_ASSERT( curveCopy );

    if ( forceVisible )
    {
        curveCopy->setCheckState( true );
    }

    curveSet->addCurve( curveCopy );

    // The curve creator is not a descendant of the project, and need to be set manually
    curveCopy->setSummaryCaseY( curve->summaryCaseY() );
    curveCopy->initAfterReadRecursively();
    curveCopy->loadDataAndUpdate( false );
}

//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RicSummaryPlotEditorUi::setDefaultCurveSelection( const std::vector<SummarySource*>& defaultSources )
{
    m_summaryCurveSelectionEditor->summaryAddressSelection()->setDefaultSelection( defaultSources );
}

//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RicSummaryPlotEditorUi::resetAllFields()
{
    std::vector<RiaSummaryCurveDefinition> curveDefinitions;
    m_summaryCurveSelectionEditor->summaryAddressSelection()->setSelectedCurveDefinitions( curveDefinitions );

    m_previewPlot->deleteAllSummaryCurves();
    m_targetPlot = nullptr;
}

//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RicSummaryPlotEditorUi::initCurveAppearanceCalculator( RimSummaryCurveAppearanceCalculator& curveAppearanceCalc )
{
    if ( !m_useAutoAppearanceAssignment() )
    {
        curveAppearanceCalc.assignDimensions( m_caseAppearanceType(),
                                              m_variableAppearanceType(),
                                              m_wellAppearanceType(),
                                              m_groupAppearanceType(),
                                              m_regionAppearanceType() );
    }
    else
    {
        RimSummaryCurveAppearanceCalculator::CurveAppearanceType caseAppearance;
        RimSummaryCurveAppearanceCalculator::CurveAppearanceType variAppearance;
        RimSummaryCurveAppearanceCalculator::CurveAppearanceType wellAppearance;
        RimSummaryCurveAppearanceCalculator::CurveAppearanceType gropAppearance;
        RimSummaryCurveAppearanceCalculator::CurveAppearanceType regiAppearance;

        curveAppearanceCalc.getDimensions( &caseAppearance, &variAppearance, &wellAppearance, &gropAppearance, &regiAppearance );

        m_caseAppearanceType     = caseAppearance;
        m_variableAppearanceType = variAppearance;
        m_wellAppearanceType     = wellAppearance;
        m_groupAppearanceType    = gropAppearance;
        m_regionAppearanceType   = regiAppearance;
    }
}

//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RicSummaryPlotEditorUi::applyAppearanceToAllPreviewCurves()
{
    std::set<RiaSummaryCurveDefinition> allCurveDefs = m_previewPlot->summaryAndEnsembleCurveDefinitions();

    RimSummaryCurveAppearanceCalculator curveLookCalc( allCurveDefs );
    initCurveAppearanceCalculator( curveLookCalc );

    // Summary curves
    for ( auto& curve : m_previewPlot->summaryCurves() )
    {
        curve->resetAppearance();
        curveLookCalc.setupCurveLook( curve );
    }

    // Ensemble curve sets
    int colorIndex = 0;
    for ( auto& curveSet : m_previewPlot->ensembleCurveSetCollection()->curveSets() )
    {
        if ( RimEnsembleCurveSetColorManager::hasSameColorForAllRealizationCurves( curveSet->colorMode() ) )
        {
            curveSet->setColor( RiaColorTables::summaryCurveDefaultPaletteColors().cycledColor3f( colorIndex++ ) );
        }
    }
}

//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RicSummaryPlotEditorUi::updateAppearanceEditor()
{
    std::set<RiaSummaryCurveDefinition> allCurveDefs = m_previewPlot->summaryAndEnsembleCurveDefinitions();

    RimSummaryCurveAppearanceCalculator curveLookCalc( allCurveDefs );
    initCurveAppearanceCalculator( curveLookCalc );
}

//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RicSummaryPlotEditorUi::createNewPlot()
{
    RimSummaryPlot* newSummaryPlot = nullptr;

    if ( !m_plotContainer )
    {
        std::vector<RimSummaryPlot*> plots;
        m_plotContainer = RicSummaryPlotBuilder::createAndAppendSummaryMultiPlot( plots );
    }

    if ( m_plotContainer )
    {
        newSummaryPlot = new RimSummaryPlot();
        newSummaryPlot->setAsPlotMdiWindow();
        newSummaryPlot->enableAutoPlotTitle( true );
        m_plotContainer->addPlot( newSummaryPlot );
    }

    if ( newSummaryPlot )
    {
        newSummaryPlot->loadDataAndUpdate();

        if ( m_plotContainer )
        {
            m_plotContainer->updateConnectedEditors();
        }

        m_targetPlot = newSummaryPlot;

        RiuPlotMainWindow* mainPlotWindow = RiaGuiApplication::instance()->mainPlotWindow();
        mainPlotWindow->updateMultiPlotToolBar();
    }
}

//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RicSummaryPlotEditorUi::updateCurveNames()
{
    for ( RimSummaryCurve* curve : m_previewPlot->summaryCurves() )
    {
        curve->applyCurveAutoNameSettings( *m_curveNameConfig() );
        curve->updateCurveNameNoLegendUpdate();
    }

    if ( m_previewPlot && m_previewPlot->plotWidget() ) m_previewPlot->updateLegend();
}

//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RicSummaryPlotEditorUi::isObservedData( RimSummaryCase* sumCase ) const
{
    return dynamic_cast<RimObservedSummaryData*>( sumCase ) != nullptr;
}

//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RicSummaryPlotEditorUi::selectionEditorFieldChanged()
{
    syncPreviewCurvesFromUiSelection();
}

//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RicSummaryPlotEditorUi::proxyEnablePlotAutoTitle( const bool& enable )
{
    m_previewPlot->enableAutoPlotTitle( enable );
    m_previewPlot->setPlotTitleVisible( enable );
    m_previewPlot->updateCurveNames();
    m_previewPlot->loadDataAndUpdate();
}

//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RicSummaryPlotEditorUi::proxyPlotAutoTitle() const
{
    return m_previewPlot->autoPlotTitle();
}

//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RicSummaryPlotEditorUi::setInitialCurveVisibility( const RimSummaryPlot* targetPlot )
{
    // Set visibility for imported curves which were not checked in source plot
    std::set<std::pair<RimSummaryCase*, RifEclipseSummaryAddress>> sourceCurveDefs;
    for ( const auto& curve : targetPlot->summaryCurves() )
    {
        sourceCurveDefs.insert( std::make_pair( curve->summaryCaseY(), curve->summaryAddressY() ) );
    }

    for ( const auto& curve : m_previewPlot->summaryCurves() )
    {
        auto curveDef = std::make_pair( curve->summaryCaseY(), curve->summaryAddressY() );
        if ( sourceCurveDefs.count( curveDef ) == 0 )
        {
            curve->setCheckState( false );
        }
    }

    std::set<std::pair<RimSummaryCaseCollection*, RifEclipseSummaryAddress>> sourceCurveSetDefs;
    for ( const auto& curveSet : targetPlot->ensembleCurveSetCollection()->curveSets() )
    {
        sourceCurveSetDefs.insert( std::make_pair( curveSet->summaryCaseCollection(), curveSet->summaryAddress() ) );
    }

    for ( const auto& curveSet : m_previewPlot->ensembleCurveSetCollection()->curveSets() )
    {
        auto curveDef = std::make_pair( curveSet->summaryCaseCollection(), curveSet->summaryAddress() );
        if ( sourceCurveSetDefs.count( curveDef ) == 0 )
        {
            curveSet->showCurves( false );
        }
    }
}

//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
int ensembleCurveCount( const std::set<RiaSummaryCurveDefinition>& allCurveDefs )
{
    return std::count_if( allCurveDefs.begin(),
                          allCurveDefs.end(),
                          []( const RiaSummaryCurveDefinition& def ) { return def.isEnsembleCurve(); } );
}

//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
template <typename T>
std::vector<T> toVector( const std::set<T>& set )
{
    return std::vector<T>( set.begin(), set.end() );
}
