//=========================================================================
//  Copyright (c) Kitware, Inc.
//  All rights reserved.
//  See LICENSE.txt for details.
//
//  This software is distributed WITHOUT ANY WARRANTY; without even
//  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
//  PURPOSE.  See the above copyright notice for more information.
//=========================================================================
#ifndef __pqCMBModifierArc_h
#define __pqCMBModifierArc_h

#include <QAbstractItemView>
#include <QObject>
#include <fstream>
#include <map>
#include <string>
#include <vector>

#include "vtkBoundingBox.h"
#include "vtkDataObject.h"

#include "cmbAppCommonExport.h"
#include "cmbProfileFunction.h"
#include "cmbSystemConfig.h"

class qtCMBArcEditWidget;
class qtCMBArcWidgetManager;
class pqCMBArc;
class pqPipelineSource;
class vtkPiecewiseFunction;
class vtkSMSourceProxy;

class CMBAPPCOMMON_EXPORT pqCMBModifierArc : public QObject
{
  Q_OBJECT

private:
  struct profileFunctionWrapper;

public:
  enum FunctionMode
  {
    Single = 0,
    EndPoints = 1,
    PointAssignment = 2
  };
  struct pointFunctionWrapper
  {
    friend class pqCMBModifierArc;

  private:
    profileFunctionWrapper const* function;
    vtkIdType ptId;
    vtkIdType pointIndex;
    void setFunction(profileFunctionWrapper const* f);

  public:
    pointFunctionWrapper(pointFunctionWrapper const& other);
    void operator=(pointFunctionWrapper const& other);
    pointFunctionWrapper(profileFunctionWrapper const* fun = NULL);
    ~pointFunctionWrapper();
    cmbProfileFunction const* getFunction() const;
    std::string getName() const;
    vtkIdType getPointId() const;
    vtkIdType getPointIndex() const;
  };
  enum RangeLable
  {
    MIN = 0,
    MAX = 1
  };
  pqCMBModifierArc();
  pqCMBModifierArc(vtkSMSourceProxy* proxy);
  ~pqCMBModifierArc() override;

  pqCMBArc* GetCmbArc() { return CmbArc; }

  void setId(int i) { Id = i; }

  int getId() const { return Id; }

  void setVisablity(bool vis);

  void writeFunction(std::ofstream& f);
  void readFunction(std::ifstream& f, bool import_functions = false);

  void write(std::ofstream& f);
  void read(std::ifstream& f, bool import_functions = false);

  bool updateLabel(std::string str, cmbProfileFunction* fun);

  cmbProfileFunction* getStartFun()
  {
    return const_cast<cmbProfileFunction*>(startFunction->getFunction());
  }
  cmbProfileFunction* getEndFun()
  {
    return const_cast<cmbProfileFunction*>(endFunction->getFunction());
  }
  bool setStartFun(std::string const& name);
  bool setEndFun(std::string const& name);

  void getFunctions(std::vector<cmbProfileFunction*>& funs) const;

  cmbProfileFunction* createFunction();

  bool deleteFunction(std::string const& name);

  cmbProfileFunction* setFunction(std::string const& name, cmbProfileFunction::FunctionType mode);

  cmbProfileFunction* cloneFunction(std::string const& name);

  pointFunctionWrapper* getPointFunction(vtkIdType i);
  pqCMBModifierArc::pointFunctionWrapper const* addFunctionAtPoint(
    vtkIdType i, cmbProfileFunction* fun);
  void removeFunctionAtPoint(vtkIdType i);
  bool pointHasFunction(vtkIdType i) const;

  FunctionMode getFunctionMode() const;
  void setFunctionMode(FunctionMode fm);

  void getPointFunctions(std::vector<pointFunctionWrapper const*>& result) const;

  bool isRelative() const;

public slots:
  void sendChangeSignals();
  void updateArc(vtkSMSourceProxy* source, vtkBoundingBox bbox);
  void switchToNotEditable();
  void switchToEditable();
  void removeFromServer(vtkSMSourceProxy* source);
  bool setCMBArc(pqCMBArc*);
  void setRelative(bool b);

signals:
  void functionChanged(int);
  void updateDisplacementProfile(/*Displacent info*/);
  void updateWeightProfile(/*Weight info*/);
  void finishCreating();
  void requestRender();

protected:
  //Varable for the path
  pqCMBModifierArc::pointFunctionWrapper const* addFunctionAtPoint(
    vtkIdType i, profileFunctionWrapper* fun);
  pqCMBArc* CmbArc;
  std::map<vtkIdType, pointFunctionWrapper*> pointsFunctions;
  bool IsExternalArc;

  FunctionMode functionMode;

  std::map<std::string, profileFunctionWrapper*> functions;
  pointFunctionWrapper* startFunction;
  pointFunctionWrapper* endFunction;

  int Id;

  bool IsVisible;

  bool IsRelative;

  void setUpFunction();
};

#endif
