/***************************************************************************
                          qgsmeshcalculator.h
                          -------------------
    begin                : December 18th, 2018
    copyright            : (C) 2018 by Peter Petrik
    email                : zilolv at gmail dot com
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   This program 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 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 ***************************************************************************/

#ifndef QGSMESHCALCULATOR_H
#define QGSMESHCALCULATOR_H

#include "qgis_core.h"
#include "qgis_sip.h"
#include "qgsgeometry.h"
#include "qgsmeshdataset.h"
#include "qgsprovidermetadata.h"
#include "qgsrectangle.h"

#include <QString>
#include <QStringList>
#include <QVector>

class QgsMeshLayer;
class QgsFeedback;

/**
 * \ingroup core
 * \class QgsMeshCalculator
 * \brief Performs mesh layer calculations.
 *
 * Mesh calculator can do various mathematical operations
 * between dataset groups from a single mesh layer.
 * Resulting dataset group is added to the mesh layer.
 * Result can be filtered by extent or a vector layer mask
 * spatially and by selection of times.
 *
 * Resulting dataset is always scalar
 *
 * \since QGIS 3.6
*/
class CORE_EXPORT QgsMeshCalculator
{
  public:
    //! Result of the calculation
    enum Result
    {
      Success = 0,       //!< Calculation successful
      Canceled,          //!< Calculation canceled
      CreateOutputError, //!< Error creating output data file
      InputLayerError,   //!< Error reading input layer
      ParserError,       //!< Error parsing formula
      InvalidDatasets,   //!< Datasets with different time outputs or not part of the mesh
      EvaluateError,     //!< Error during evaluation
      MemoryError,       //!< Error allocating memory for result
    };

    /**
     * Creates calculator with bounding box (rectangular) mask
     * \param formulaString formula/expression to evaluate. Consists of dataset group names, operators and numbers
     * \param outputFile file to store the resulting dataset group data
     * \param outputExtent spatial filter defined by rectangle
     * \param startTime time filter defining the starting dataset
     * \param endTime time filter defining the ending dataset
     * \param layer mesh layer with dataset groups references in formulaString
     *
     * \deprecated QGIS 3.12
     */
    Q_DECL_DEPRECATED QgsMeshCalculator( const QString &formulaString, const QString &outputFile, const QgsRectangle &outputExtent, double startTime, double endTime, QgsMeshLayer *layer )
      SIP_DEPRECATED;

    /**
     * Creates calculator with geometry mask
     * \param formulaString formula/expression to evaluate. Consists of dataset group names, operators and numbers
     * \param outputFile file to store the resulting dataset group data
     * \param outputMask spatial filter defined by geometry
     * \param startTime time filter defining the starting dataset
     * \param endTime time filter defining the ending dataset
     * \param layer mesh layer with dataset groups references in formulaString
     *
     * \deprecated QGIS 3.12
     */
    Q_DECL_DEPRECATED QgsMeshCalculator( const QString &formulaString, const QString &outputFile, const QgsGeometry &outputMask, double startTime, double endTime, QgsMeshLayer *layer ) SIP_DEPRECATED;

    /**
     * Creates calculator with bounding box (rectangular) mask
     * \param formulaString formula/expression to evaluate. Consists of dataset group names, operators and numbers
     * \param outputDriver output driver name
     * \param outputGroupName output group name
     * \param outputFile file to store the resulting dataset group data
     * \param outputExtent spatial filter defined by rectangle
     * \param startTime time filter defining the starting dataset
     * \param endTime time filter defining the ending dataset
     * \param layer mesh layer with dataset groups references in formulaString
     *
     * \since QGIS 3.12
     */
    QgsMeshCalculator(
      const QString &formulaString, const QString &outputDriver, const QString &outputGroupName, const QString &outputFile, const QgsRectangle &outputExtent, double startTime, double endTime, QgsMeshLayer *layer
    );

    /**
     * Creates calculator with geometry mask
     * \param formulaString formula/expression to evaluate. Consists of dataset group names, operators and numbers
     * \param outputDriver output driver name
     * \param outputGroupName output group name
     * \param outputFile file to store the resulting dataset group data
     * \param outputMask spatial filter defined by geometry
     * \param startTime time filter defining the starting dataset
     * \param endTime time filter defining the ending dataset
     * \param layer mesh layer with dataset groups references in formulaString
     *
     * \since QGIS 3.12
     */
    QgsMeshCalculator(
      const QString &formulaString, const QString &outputDriver, const QString &outputGroupName, const QString &outputFile, const QgsGeometry &outputMask, double startTime, double endTime, QgsMeshLayer *layer
    );

    /**
     * Creates calculator with bounding box (rectangular) mask, store the result in \a destination (must be on memory or virtual),
     * see QgsMeshCalculator::Destination
     * \param formulaString formula/expression to evaluate. Consists of dataset group names, operators and numbers
     * \param outputGroupName output group name
     * \param outputExtent spatial filter defined by rectangle
     * \param destination destination of the calculation (memory or virtual)
     * \param startTime time filter defining the starting dataset
     * \param endTime time filter defining the ending dataset
     * \param layer mesh layer with dataset groups references in formulaString
     *
     * \since QGIS 3.16
     */
    QgsMeshCalculator(
      const QString &formulaString, const QString &outputGroupName, const QgsRectangle &outputExtent, const QgsMeshDatasetGroup::Type &destination, QgsMeshLayer *layer, double startTime, double endTime
    );

    /**
     * Creates calculator with with geometry mask, store the result in \a destination (must be on memory or virtual),
     *  see QgsMeshCalculator::Destination
     * \param formulaString formula/expression to evaluate. Consists of dataset group names, operators and numbers
     * \param outputGroupName output group name
     * \param outputMask spatial filter defined by geometry
     * \param destination destination of the calculation (memory or virtual)
     * \param startTime time filter defining the starting dataset
     * \param endTime time filter defining the ending dataset
     * \param layer mesh layer with dataset groups references in formulaString
     *
     * \since QGIS 3.16
     */
    QgsMeshCalculator(
      const QString &formulaString, const QString &outputGroupName, const QgsGeometry &outputMask, const QgsMeshDatasetGroup::Type &destination, QgsMeshLayer *layer, double startTime, double endTime
    );

    /**
     * Starts the calculation, creates new dataset group and adds it to the mesh layer
     * \param feedback The optional feedback argument for progress reporting and cancellation support
     * \returns QgsMeshCalculator::Success in case of success
     */
    Result processCalculation( QgsFeedback *feedback = nullptr );

    /**
     * Returns whether formula is valid for particular mesh layer
     * \param formulaString formula/expression to evaluate. Consists of dataset group names, operators and numbers
     * \param layer mesh layer with dataset groups references in formulaString
     * \returns QgsMeshCalculator::Success in case of success
     *
     * \deprecated QGIS 3.12. Use expressionIsValid.
     */
    Q_DECL_DEPRECATED static Result expression_valid( const QString &formulaString, QgsMeshLayer *layer ) SIP_DEPRECATED;

    /**
     * Returns whether formula is valid for particular mesh layer
     * \param formulaString formula/expression to evaluate. Consists of dataset group names, operators and numbers
     * \param layer mesh layer with dataset groups references in formulaString
     * \param requiredCapability returns required capability of driver to store results of the calculation
     * \returns QgsMeshCalculator::Success in case of success
     *
     * \since QGIS 3.12
     */
    static Result expressionIsValid( const QString &formulaString, QgsMeshLayer *layer, QgsMeshDriverMetadata::MeshDriverCapability &requiredCapability );

  private:
    QgsMeshCalculator();

    QString mFormulaString;
    QString mOutputDriver;
    QString mOutputGroupName;
    QString mOutputFile;
    QgsRectangle mOutputExtent;
    QgsGeometry mOutputMask;
    bool mUseMask = false;
    QgsMeshDatasetGroup::Type mDestination = QgsMeshDatasetGroup::Persistent;
    double mStartTime = 0.0;
    double mEndTime = 0.0;
    QgsMeshLayer *mMeshLayer = nullptr;
};

#endif // QGSMESHCALCULATOR_H
