/////////////////////////////////////////////////////////////////////////////////
//
//  Copyright (C) 2018-     Equinor 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.
//
/////////////////////////////////////////////////////////////////////////////////
#pragma once

#include "RiaLineArcWellPathCalculator.h"
#include "RiaWellPlanCalculator.h"

#include "cafAppEnum.h"
#include "cafPdmChildArrayField.h"
#include "cafPdmChildField.h"
#include "cafPdmField.h"
#include "cafPdmFieldCvfColor.h"
#include "cafPdmFieldCvfVec3d.h"
#include "cafPdmObject.h"
#include "cafPdmPtrField.h"

#include "cvfColor3.h"
#include "cvfObject.h"

class RimWellPath;
class RimWellPathTarget;
class RicCreateWellTargetsPickEventHandler;

class RigWellPath;

class RimWellPathGeometryDef : public caf::PdmObject
{
    CAF_PDM_HEADER_INIT;

public:
    caf::Signal<bool> changed;

public:
    RimWellPathGeometryDef();
    ~RimWellPathGeometryDef() override;

    cvf::Vec3d anchorPointXyz() const;
    cvf::Vec3d anchorPointXyd() const;
    void       setReferencePointXyz( const cvf::Vec3d& refPointXyz );
    bool       useReferencePointFromTopLevelWell() const;
    void       enableReferencePointFromTopLevelWell( bool enable );
    void       enableLinkOfReferencePointUpdates( bool enable );
    bool       isReferencePointUpdatesLinked() const;

    double airGap() const;
    void   setAirGap( double airGap );
    double mdAtFirstTarget() const;
    void   setMdAtFirstTarget( double mdrkb );

    void setIsAttachedToParentWell( bool isAttached );
    void setFixedWellPathPoints( const std::vector<cvf::Vec3d>& points );
    void setFixedMeasuredDepths( const std::vector<double>& mds );

    std::vector<RimWellPathTarget*> createAndInsertTargets( const std::vector<cvf::Vec3d>& points );

    std::pair<RimWellPathTarget*, RimWellPathTarget*> findActiveTargetsAroundInsertionPoint( const RimWellPathTarget* targetToInsertBefore );

    cvf::ref<RigWellPath> createWellPathGeometry();
    void                  insertTarget( const RimWellPathTarget* targetToInsertBefore, RimWellPathTarget* targetToInsert );
    void                  deleteTarget( RimWellPathTarget* targetTodelete );
    void                  deleteAllTargets();
    RimWellPathTarget*    appendTarget();

    const RimWellPathTarget*        firstActiveTarget() const;
    const RimWellPathTarget*        lastActiveTarget() const;
    std::vector<RimWellPathTarget*> activeWellTargets() const;

    void enableTargetPointPicking( bool isEnabling );
    void updateWellPathVisualization( bool fullUpdate );

    void setUseAutoGeneratedTargetAtSeaLevel( bool autoGenerate );

    std::vector<RiaWellPlanCalculator::WellPlanSegment> wellPlan() const;

    // Well target appearance
    bool         showSpheres() const;
    cvf::Color3f sphereColor() const;
    double       sphereRadiusFactor() const;
    bool         showAbsoluteCoordinates() const;
    double       wellTargetScalingFactor() const;

protected:
    std::vector<RimWellPathTarget*> activeWellTargets( bool useAutoGeneratedTargetAtSeaLevel ) const;
    cvf::ref<RigWellPath> createWellPathGeometry( bool useAutoGeneratedTargetAtSeaLevel, double offsetMd, bool updateTargets ) const;

    void defineCustomContextMenu( const caf::PdmFieldHandle* fieldNeedingMenu, QMenu* menu, QWidget* fieldEditorWidget ) override;

    void defineEditorAttribute( const caf::PdmFieldHandle* field, QString uiConfigName, caf::PdmUiEditorAttribute* attribute ) override;

    void                 defineObjectEditorAttribute( QString uiConfigName, caf::PdmUiEditorAttribute* attribute ) override;
    caf::PdmFieldHandle* objectToggleField() override;

    void onTargetMoved( const caf::SignalEmitter* emitter, bool fullUpdate );

private:
    void fieldChangedByUi( const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue ) override;
    void defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering& uiOrdering ) override;
    void defineUiTreeOrdering( caf::PdmUiTreeOrdering& uiTreeOrdering, QString uiConfigName ) override;
    void initAfterRead() override;
    QList<caf::PdmOptionItemInfo> calculateValueOptions( const caf::PdmFieldHandle* fieldNeedingOptions ) override;

    RiaLineArcWellPathCalculator lineArcWellPathCalculator( bool useAutoGeneratedTargetAtSeaLevel, bool updateTargets = true ) const;

    void updateTargetAtSeaLevel();

private:
    caf::PdmField<cvf::Vec3d> m_referencePointUtmXyd;

    caf::PdmField<double> m_airGap;

    caf::PdmField<double> m_mdAtFirstTarget;

    caf::PdmChildArrayField<RimWellPathTarget*> m_wellTargets;
    caf::PdmField<bool>                         m_showAbsolutePosForWellTargets;
    caf::PdmField<bool>                         m_useTopLevelWellReferencePoint;
    caf::PdmField<bool>                         m_linkReferencePointUpdates;

    caf::PdmField<bool>                    m_useAutoGeneratedTargetAtSeaLevel;
    caf::PdmChildField<RimWellPathTarget*> m_autoTargetAtSeaLevel;
    caf::PdmField<bool>                    m_pickPointsEnabled;
    caf::PdmField<std::vector<cvf::Vec3d>> m_fixedWellPathPoints;
    caf::PdmField<std::vector<double>>     m_fixedMeasuredDepths;

    caf::PdmField<bool> m_isAttachedToParentWell;

    caf::PdmField<bool>         m_showSpheres;
    caf::PdmField<cvf::Color3f> m_sphereColor;
    caf::PdmField<double>       m_sphereRadiusFactor;
    caf::PdmField<double>       m_wellTargetHandleScalingFactor;

    std::shared_ptr<RicCreateWellTargetsPickEventHandler> m_pickTargetsEventHandler;
};
