/*=========================================================================

  Program:   Visualization Toolkit
  Module:    vtkWindBladeReader.h

  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
  All rights reserved.
  See Copyright.txt or http://www.kitware.com/Copyright.htm 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.

=========================================================================*/
/**
 * @class   vtkWindBladeReader
 * @brief   class for reading WindBlade data files
 *
 * vtkWindBladeReader is a source object that reads WindBlade files
 * which are block binary files with tags before and after each block
 * giving the number of bytes within the block.  The number of data
 * variables dumped varies.  There are 3 output ports with the first
 * being a structured grid with irregular spacing in the Z dimension.
 * The second is an unstructured grid only read on on process 0 and
 * used to represent the blade.  The third is also a structured grid
 * with irregular spacing on the Z dimension.  Only the first and
 * second output ports have time dependent data.
 */

#ifndef vtkWindBladeReader_h
#define vtkWindBladeReader_h

#include "vtkIOGeometryModule.h" // For export macro
#include "vtkStructuredGridAlgorithm.h"

class vtkDataArraySelection;
class vtkCallbackCommand;
class vtkStringArray;
class vtkFloatArray;
class vtkIntArray;
class vtkPoints;
class vtkStructuredGrid;
class vtkUnstructuredGrid;
class vtkMultiBlockDataSetAglorithm;
class vtkStructuredGridAlgorithm;
class WindBladeReaderInternal;

class VTKIOGEOMETRY_EXPORT vtkWindBladeReader : public vtkStructuredGridAlgorithm
{
public:
  static vtkWindBladeReader* New();
  vtkTypeMacro(vtkWindBladeReader, vtkStructuredGridAlgorithm);
  void PrintSelf(ostream& os, vtkIndent indent) override;

  vtkSetStringMacro(Filename);
  vtkGetStringMacro(Filename);

  vtkSetVector6Macro(WholeExtent, int);
  vtkGetVector6Macro(WholeExtent, int);

  vtkSetVector6Macro(SubExtent, int);
  vtkGetVector6Macro(SubExtent, int);

  /**
   * Get the reader's output
   */
  vtkStructuredGrid* GetFieldOutput();   // Output port 0
  vtkUnstructuredGrid* GetBladeOutput(); // Output port 1
  vtkStructuredGrid* GetGroundOutput();  // Output port 2

  //@{
  /**
   * The following methods allow selective reading of solutions fields.
   * By default, ALL data fields on the nodes are read, but this can
   * be modified.
   */
  int GetNumberOfPointArrays();
  const char* GetPointArrayName(int index);
  //@}

  int GetPointArrayStatus(const char* name);
  void SetPointArrayStatus(const char* name, int status);

  void DisableAllPointArrays();
  void EnableAllPointArrays();

protected:
  static float DRY_AIR_CONSTANT;
  static int NUM_PART_SIDES;       // Blade parts rhombus
  static const int NUM_BASE_SIDES; // Base pyramid
  static const int LINE_SIZE;
  static int DIMENSION;
  static int BYTES_PER_DATA;
  static int SCALAR;
  static int VECTOR;
  static int FLOAT;
  static int INTEGER;

  vtkWindBladeReader();
  ~vtkWindBladeReader() override;

  char* Filename; // Base file name

  // Extent information
  vtkIdType NumberOfTuples; // Number of tuples in subextent

  // Field
  int WholeExtent[6]; // Extents of entire grid
  int SubExtent[6];   // Processor grid extent
  int UpdateExtent[6];
  int Dimension[3];    // Size of entire grid
  int SubDimension[3]; // Size of processor grid

  // Ground
  int GExtent[6];    // Extents of ground grid
  int GSubExtent[6]; // Processor grid extent
  int GDimension[3]; // Size of ground grid

  float Step[3];               // Spacing delta
  int UseTopographyFile;       // Topography or flat
  vtkStdString TopographyFile; // Name of topography data file
  vtkPoints* Points;           // Structured grid geometry
  vtkPoints* GPoints;          // Structured grid geometry for ground
  vtkPoints* BPoints;          // Unstructured grid geometry
  float Compression;           // Stretching at Z surface [0,1]
  float Fit;                   // Cubic or quadratic [0,1]

  // Rectilinear coordinate spacing
  vtkFloatArray* XSpacing;
  vtkFloatArray* YSpacing;
  vtkFloatArray* ZSpacing;
  float* ZTopographicValues;
  float ZMinValue;

  // Variable information
  int NumberOfFileVariables;    // Number of variables in data file
  int NumberOfDerivedVariables; // Number of variables derived from file
  int NumberOfVariables;        // Number of variables to display

  vtkStringArray* DivideVariables; // Divide data by density at read
  vtkStdString* VariableName;      // Names of each variable
  int* VariableStruct;             // SCALAR or VECTOR
  int* VariableCompSize;           // Number of components
  int* VariableBasicType;          // FLOAT or INTEGER
  int* VariableByteCount;          // Number of bytes in basic type
  long int* VariableOffset;        // Offset into data file
  size_t BlockSize;                // Size of every data block
  size_t GBlockSize;               // Size of every data block

  vtkFloatArray** Data;       // Actual data arrays
  vtkStdString RootDirectory; // Directory where the .wind file is.
  vtkStdString DataDirectory; // Location of actual data
  vtkStdString DataBaseName;  // Base name of files

  // Time step information
  int NumberOfTimeSteps; // Number of time steps
  int TimeStepFirst;     // First time step
  int TimeStepLast;      // Last time step
  int TimeStepDelta;     // Delta on time steps
  double* TimeSteps;     // Actual times available for request

  // Turbine information
  int NumberOfBladeTowers; // Number of turbines
  int NumberOfBladePoints; // Points for drawing parts of blades
  int NumberOfBladeCells;  // Turbines * Blades * Parts

  vtkFloatArray* XPosition;    // Location of tower
  vtkFloatArray* YPosition;    // Location of tower
  vtkFloatArray* HubHeight;    // Height of tower
  vtkFloatArray* AngularVeloc; // Angular Velocity
  vtkFloatArray* BladeLength;  // Blade length
  vtkIntArray* BladeCount;     // Number of blades per tower

  int UseTurbineFile;            // Turbine data available
  vtkStdString TurbineDirectory; // Turbine unstructured data
  vtkStdString TurbineTowerName; // Name of tower file
  vtkStdString TurbineBladeName; // Base name of time series blade data
  int NumberOfLinesToSkip;       // New format has lines that need to be skipped in
                                 // blade files

  // Selected field of interest
  vtkDataArraySelection* PointDataArraySelection;

  // Observer to modify this object when array selections are modified
  vtkCallbackCommand* SelectionObserver;

  // Read the header file describing the dataset
  virtual bool ReadGlobalData();
  void ReadDataVariables(istream& inStr);
  virtual bool FindVariableOffsets();

  // Turbine methods
  virtual void SetupBladeData();
  virtual void LoadBladeData(int timeStep);

  // Calculate the coordinates
  void FillCoordinates();
  void FillGroundCoordinates();
  void CreateCoordinates();
  virtual void CreateZTopography(float* zdata);
  float GDeform(float sigma, float sigmaMax, int flag);
  void Spline(float* x, float* y, int n, float yp1, float ypn, float* y2);
  void Splint(float* xa, float* ya, float* y2a, int n, float x, float* y, int);

  // Load a variable from data file
  virtual void LoadVariableData(int var);

  // Variables which must be divided by density after being read from file
  void DivideByDensity(const char* name);

  // Calculate derived variables
  virtual void CalculatePressure(int pres, int prespre, int tempg, int density);
  virtual void CalculateVorticity(int vort, int uvw, int density);

  // convenience functions shared between serial and parallel version
  void InitFieldData(
    vtkInformationVector* outVector, std::ostringstream& fileName, vtkStructuredGrid* field);
  void SetUpFieldVars(vtkStructuredGrid* field);
  void InitBladeData(vtkInformationVector* outVector);
  void SetUpGroundData(vtkInformationVector* outVector);
  void InitPressureData(int pressure, int prespre, float*& pressureData, float*& prespreData);
  void SetUpPressureData(
    float* pressureData, float* prespreData, const float* tempgData, const float* densityData);
  void SetUpVorticityData(float* uData, float* vData, const float* densityData, float* vortData);
  void InitVariableData(
    int var, int& numberOfComponents, float*& varData, int& planeSize, int& rowSize);
  bool SetUpGlobalData(const std::string& fileName, std::stringstream& inStr);
  void ProcessZCoords(float* topoData, float* zValues);
  void ReadBladeHeader(const std::string& fileName, std::stringstream& inStr, int& numColumns);
  void ReadBladeData(std::stringstream& inStr);

  int RequestInformation(vtkInformation*, vtkInformationVector**, vtkInformationVector*) override;
  int RequestData(vtkInformation* request, vtkInformationVector** inputVector,
    vtkInformationVector* outputVector) override;

  static void SelectionCallback(
    vtkObject* caller, unsigned long eid, void* clientdata, void* calldata);

  static void EventCallback(vtkObject* caller, unsigned long eid, void* clientdata, void* calldata);

  int FillOutputPortInformation(int, vtkInformation*) override;

  /**
   * We intercept the requests to check for which port
   * information is being requested for and if there is
   * a REQUEST_DATA_NOT_GENERATED request then we mark
   * which ports won't have data generated for that request.
   */
  vtkTypeBool ProcessRequest(
    vtkInformation* request, vtkInformationVector** inInfo, vtkInformationVector* outInfo) override;

private:
  WindBladeReaderInternal* Internal;

  vtkWindBladeReader(const vtkWindBladeReader&) = delete;
  void operator=(const vtkWindBladeReader&) = delete;
};
#endif
