//  Copyright (C) 2007-2010  CEA/DEN, EDF R&D, OPEN CASCADE
//
//  Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
//  CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
//
//  This library is free software; you can redistribute it and/or
//  modify it under the terms of the GNU Lesser General Public
//  License as published by the Free Software Foundation; either
//  version 2.1 of the License.
//
//  This library 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
//  Lesser General Public License for more details.
//
//  You should have received a copy of the GNU Lesser General Public
//  License along with this library; if not, write to the Free Software
//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
//
//  See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
//

//  File   : VISU_TimeAnimation.h
//  Author : Vitaly SMETANNIKOV
//  Module : VISU
//
#ifndef VISU_TIMEANIMATION_H
#define VISU_TIMEANIMATION_H

#include "VISUConfig.hh"

#include "VISU_Result_i.hh"
#include "SALOME_GenericObjPointer.hh"

#include <vector>

#include <QObject>
#include <QList>
#include <QThread>

class SVTK_ViewWindow;
class VISU_Actor;

namespace VISU
{
  //class Result_i;
  class ColoredPrs3d_i;
  class ExecutionState;
}

struct FieldData
{
  VISU::VISUType myPrsType;
  _PTR(SObject) myField; // field label
  long myNbTimes;        // number of Timestamps
  long myNbFrames;       // number of created Frames
  std::vector<VISU::ColoredPrs3d_i*> myPrs;     // Presentations
  std::vector<VISU_Actor*> myActors;         // Actors
  std::vector<double> myTiming;              // time values
  CORBA::Float myOffset[3];
  typedef SALOME::GenericObjPtr<VISU::Result_i> TResultPtr;
  TResultPtr myResult;
};


class VISU_I_EXPORT VISU_TimeAnimation: public QThread
{
  Q_OBJECT;

 public:
  enum DumpMode { DM_None = 0, DM_Picture, DM_Video };

 protected:
  CORBA::Boolean _generateFrames();
  void _connectView();
  void _visibilityOff(int num_field, int num_frame);
  void _clearView();
  void _clearData(FieldData& theData);
  void _startAnimation();
  void _nextFrame();
  void _prevFrame();
  void _firstFrame();
  void _lastFrame();
  void _gotoFrame(CORBA::Long theFrame);

  void _emitFrameChanged(long theNewFrame, double theTime);
  void _emitStopped();

  void parallelAnimation( bool& theIsDumping, QList<int>& theIndexList );
  void successiveAnimation( bool& theIsDumping, QList<int>& theIndexList );
  void saveImages( int theFieldId, double& theOneVal, int& theNbFiles, QList<int>& theIndexList );

 public:
  //static VISU::Result_i* createPresent (SALOMEDS::SObject_var theField);
  //static VISU::Storable::TRestoringMap getMapOfValue (SALOMEDS::SObject_var theSObject);
  //static double getTimeValue (SALOMEDS::SObject_var theTimestamp);

  static VISU::Result_i* createPresent (_PTR(SObject) theField);
  static double getTimeValue (_PTR(SObject) theTimestamp);

  VISU_TimeAnimation(_PTR(Study) theStudy,
                     VISU::View3D_ptr theView3D = VISU::View3D::_nil());
  ~VISU_TimeAnimation();

  virtual VISU::VISUType GetType() { return VISU::TNONE;};

  bool addField (_PTR(SObject) theField);
  bool addField (SALOMEDS::SObject_ptr theField);
  FieldData& getFieldData (int theNum) { return myFieldsLst[theNum]; }

  CORBA::Boolean generateFrames();
  void generatePresentations(CORBA::Long theFieldNum);
  void setViewer(SVTK_ViewWindow* theView) { myView = theView; _connectView(); }
  SVTK_ViewWindow* getViewer() { return myView; }
  void clearView();
  void clearData(FieldData& theData);
  void clearFieldData() { myFieldsLst.clear();};

  void visibilityOff(int num_field, int num_frame);
  void stopAnimation();
  void startAnimation();
  void nextFrame();
  void prevFrame();
  void firstFrame();
  void lastFrame();
  void gotoFrame(CORBA::Long theFrame);

  CORBA::Long getNbFields() { return myFieldsLst.size(); }
  CORBA::Long getNbFrames();
  CORBA::Long getCurrentFrame() { return myFrame; }

  long getAbsoluteFrameNumber(std::pair<int,long> theFieldTimeStamp);
  std::pair<int,long> getRelativeFrameNumber(long theFrame);

  VISU::ColoredPrs3d_ptr getPresentation(CORBA::Long theField, CORBA::Long theFrame);

  void setPresentationType(CORBA::Long theFieldNum, VISU::VISUType theType);
  VISU::VISUType getPresentationType(CORBA::Long theFieldNum);

  void setSpeed(CORBA::Long theSpeed);
  CORBA::Long getSpeed() { return mySpeed; }

  CORBA::Boolean isProportional() { return myProportional; }

  void setAnimationRange(CORBA::Double theMin, CORBA::Double theMax)
    { myTimeMinVal = theMin; myTimeMaxVal = theMax; }

  CORBA::Double getMinRange() { return myTimeMinVal; }
  CORBA::Double getMaxRange() { return myTimeMaxVal; }
  CORBA::Boolean isRangeDefined() { return !((myTimeMaxVal == 0) && (myTimeMinVal == myTimeMaxVal)); }

  void setAnimationSequence(const char* theSequence);
  char* getAnimationSequence();
  CORBA::Boolean isSequenceDefined();

  bool getIndicesFromSequence( QString theSequence, QList<long>& theIndices );

  void dumpTo(const char* thePath) { myDumpPath = thePath; }
  std::string setDumpFormat(const char* theFormat);

  void setTimeStampFrequency(CORBA::Long theFrequency);
  CORBA::Long getTimeStampFrequency() { return myTimeStampFrequency; }

  int getDumpMode() const { return myDumpMode; }

  bool checkAVIMaker() const;

  QString getLastErrorMsg() { return myLastError; }

  CORBA::Boolean isCycling() { return myCycling; }
  CORBA::Boolean isCleaningMemoryAtEachFrame() { return myCleaningMemoryAtEachFrame; }

  CORBA::Double getMinTime() { return myTimeMin;}
  CORBA::Double getMaxTime() { return myTimeMax;}

  void setProportional(CORBA::Boolean theProp) { myProportional = theProp; }
  void setCycling(CORBA::Boolean theCycle) { myCycling = theCycle; }
  void setCleaningMemoryAtEachFrame(CORBA::Boolean theCycle) { myCleaningMemoryAtEachFrame = theCycle; }

  SALOMEDS::SObject_ptr publishInStudy();
  void restoreFromStudy(SALOMEDS::SObject_ptr theField);
  void restoreFromStudy(_PTR(SObject) theField);
  void saveAnimation();
  bool isSavedInStudy() const { return !myAnimEntry.isEmpty(); }
  _PTR(Study) getStudy() const { return myStudy; }

  void setAnimationMode(VISU::Animation::AnimationMode theMode) { myAnimationMode = theMode; }
  VISU::Animation::AnimationMode  getAnimationMode() { return myAnimationMode; }

  void ApplyProperties(CORBA::Long theFieldNum, VISU::ColoredPrs3d_ptr thePrs) throw (SALOME::SALOME_Exception);

 public slots:
  void setProportionalSlot(bool theProp) { myProportional = theProp; }
  void setCyclingSlot(bool theCycle) { myCycling = theCycle; }
  void setCleaningMemoryAtEachFrameSlot(bool theCycle) { myCleaningMemoryAtEachFrame = theCycle; }

 signals:
  void frameChanged(long theNewFrame, double theTime);
  void stopped();

 protected:
  void run();
  QString GenerateName();

 private slots:
   void onViewDeleted();

 private:
  QString myLastError;

  QList<FieldData> myFieldsLst;
  VISU::ExecutionState* myExecutionState;
  long myFrame;
  std::vector<long> myFieldsAbsFrames;
  int mySpeed;
  bool myProportional;
  bool myCycling;
  bool myCleaningMemoryAtEachFrame;
  _PTR(Study) myStudy;

  VISU::Animation::AnimationMode myAnimationMode;
  double myTimeMinVal, myTimeMaxVal; //!< Range of time stams, set by user
  double myTimeMin   , myTimeMax   ; //!< Range of time stams, available for animation
  QString mySequence;
  QString myDumpPath;
  QString myDumpFormat;
  QString myAVIMaker;
  long myFileIndex;
  SVTK_ViewWindow* myView;

  int myDumpMode;
  int myTimeStampFrequency;

  QString myAnimEntry;

  static int myNBAnimations;
};


class VISU_I_EXPORT VISU_TimeAnimation_i: public virtual POA_VISU::Animation,
                            public virtual VISU::Base_i
{
  VISU_TimeAnimation* myAnim;
public:
  VISU_TimeAnimation_i(SALOMEDS::Study_ptr theStudy,
                       VISU::View3D_ptr theView3D = VISU::View3D::_nil());
  ~VISU_TimeAnimation_i();

  virtual VISU::VISUType GetType() { return VISU::TANIMATION; }
  //virtual VISU::VISUType GetType() { return VISU::TNONE; }

  virtual bool addField(SALOMEDS::SObject_ptr theField);
  virtual void clearFields();

  virtual CORBA::Boolean generateFrames();
  virtual void generatePresentations(CORBA::Long theFieldNum);

  virtual void clearView();

  virtual void stopAnimation();
  virtual void startAnimation();
  virtual void nextFrame();
  virtual void prevFrame();
  virtual void firstFrame();
  virtual void lastFrame();
  virtual void gotoFrame(CORBA::Long theFrame);

  virtual CORBA::Long getNbFields();
  virtual CORBA::Long getNbFrames();
  virtual CORBA::Boolean isRunning();
  virtual CORBA::Long getCurrentFrame();

  virtual VISU::ColoredPrs3d_ptr getPresentation(CORBA::Long theField, CORBA::Long theFrame);

  virtual void setPresentationType(CORBA::Long theFieldNum, VISU::VISUType theType);
  virtual VISU::VISUType getPresentationType(CORBA::Long theFieldNum);

  virtual void setSpeed(CORBA::Long theSpeed);
  virtual CORBA::Long getSpeed();

  virtual CORBA::Boolean isProportional();

  virtual void setAnimationRange(CORBA::Double theMin, CORBA::Double theMax);

  virtual CORBA::Double getMinRange();
  virtual CORBA::Double getMaxRange();
  virtual CORBA::Boolean isRangeDefined();

  virtual void setAnimationSequence(const char* theSequence);
  virtual char* getAnimationSequence();
  virtual CORBA::Boolean isSequenceDefined();

  virtual void dumpTo(const char* thePath);
  virtual char* setDumpFormat(const char* theFormat);

  virtual void setTimeStampFrequency(CORBA::Long theFrequency);
  virtual CORBA::Long getTimeStampFrequency();

  virtual CORBA::Boolean isCycling();
  virtual CORBA::Boolean isCleaningMemoryAtEachFrame();

  virtual CORBA::Double getMinTime();
  virtual CORBA::Double getMaxTime();

  virtual void setProportional(CORBA::Boolean theProp);
  virtual void setCycling(CORBA::Boolean theCycle);
  virtual void setCleaningMemoryAtEachFrame(CORBA::Boolean theCycle);

  virtual SALOMEDS::SObject_ptr publishInStudy();
  virtual void restoreFromStudy(SALOMEDS::SObject_ptr theField);
  virtual CORBA::Boolean isSavedInStudy();
  virtual void saveAnimation();

  virtual void setAnimationMode(VISU::Animation::AnimationMode theMode);
  virtual VISU::Animation::AnimationMode getAnimationMode();

  virtual void ApplyProperties(CORBA::Long theFieldNum, VISU::ColoredPrs3d_ptr thePrs) throw (SALOME::SALOME_Exception);
};

#endif  //VISU_TIMEANIMATION_H
