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

The Medical Imaging Interaction Toolkit (MITK)

Copyright (c) German Cancer Research Center (DKFZ)
All rights reserved.

Use of this source code is governed by a 3-clause BSD license that can be
found in the LICENSE file.

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

#ifndef mitkModelFitInfo_h
#define mitkModelFitInfo_h

#include <mitkDataStorage.h>

#include <mitkModelFitConstants.h>
#include <mitkModelFitParameter.h>
#include <mitkModelFitStaticParameterMap.h>
#include <mitkScalarListLookupTable.h>
#include <mitkModelParameterizerBase.h>
#include <mitkModelTraitsInterface.h>

#include <MitkModelFitExports.h>

namespace mitk
{

  namespace modelFit
  {
    /**
     * \class ModelFitInfo
     * \brief Data class that stores all information about a model fit relevant to visualization.
     *
     * Fit information is stored as properties in the result nodes.
     */
    class MITKMODELFIT_EXPORT ModelFitInfo : public itk::LightObject
    {
    public:
      typedef std::string UIDType;
      typedef std::vector<Parameter::Pointer> ParamListType;
      typedef ParamListType::const_iterator ConstIterType;

      mitkClassMacroItkParent(ModelFitInfo, itk::LightObject);
      itkSimpleNewMacro(ModelFitInfo);

      ModelFitInfo() :
        x(mitk::ModelFitConstants::MODEL_X_VALUE_DEFAULT()),
        xAxisName(mitk::ModelFitConstants::XAXIS_NAME_VALUE_DEFAULT()),
        yAxisName(mitk::ModelFitConstants::YAXIS_NAME_VALUE_DEFAULT())
      {
      }

      /**
       * \brief Adds the given parameter to this fit's parameter list if it doesn't exist already.
       * \param p The parameter that should be added to this fit's parameter list.
       */
      void AddParameter(Parameter::Pointer p);

      /**
       * \brief Searches for the parameter with the given name and type and returns it.
       * \param name The name of the desired parameter.
       * \param type The type of the desired parameter.
       * \return The parameter with the given name on success or NULL otherwise.
       */
      Parameter::ConstPointer GetParameter(const std::string& name, const Parameter::Type& type)
      const;

      /**
       * \brief Removes the parameter with the given name and type from the list.
       * \param name The name of the parameter to delete.
       * \param type The type of the parameter to delete.
       */
      void DeleteParameter(const std::string& name, const Parameter::Type& type);

      /** \brief Returns a const reference to the parameter list. */
      const ParamListType& GetParameters() const;

      /** ModelFitConstants::MODEL_NAME_PROPERTY_NAME */
      std::string modelName;
      /** ModelFitConstants::MODEL_TYPE_PROPERTY_NAME */
      std::string modelType;
      /** ModelFitConstants::MODEL_FUNCTION_PROPERTY_NAME */
      std::string function;
      /** ModelFitConstants::MODEL_FUNCTION_CLASS_PROPERTY_NAME */
      std::string functionClassID;
      /** ModelFitConstants::MODEL_X_PROPERTY_NAME */
      std::string x;

      /** ModelFitConstants::XAXIS_NAME_PROPERTY_NAME */
      std::string xAxisName;
      /** ModelFitConstants::XAXIS_UNIT_PROPERTY_NAME */
      std::string xAxisUnit;

      /** ModelFitConstants::YAXIS_NAME_PROPERTY_NAME */
      std::string yAxisName;
      /** ModelFitConstants::YAXIS_UNIT_PROPERTY_NAME */
      std::string yAxisUnit;

      /** ModelFitConstants::FIT_UID_PROPERTY_NAME */
      UIDType uid;
      /** ModelFitConstants::FIT_NAME_PROPERTY_NAME */
      std::string fitName;
      /** ModelFitConstants::FIT_TYPE_PROPERTY_NAME */
      std::string fitType;
      /** ModelFitConstants::FIT_STATIC_PARAMETERS_PROPERTY_NAME */
      StaticParameterMap staticParamMap;
      /** ModelFitConstants::FIT_INPUT_ROIUID_PROPERTY_NAME */
      UIDType roiUID;
      /** ModelFitConstants::FIT_INPUT_DATA_PROPERTY_NAME */
      ScalarListLookupTable inputData;
      mitk::Image::ConstPointer inputImage;

    private:
      typedef ParamListType::iterator IterType;
      typedef std::lock_guard<std::mutex> LockType;

      ParamListType parameterList;
      std::mutex mutex;
    };

    /**
     * \brief Reads a mandatory string property from a data node.
     * \param node The node whose property value should be returned.
     * \param prop The name of the property that should be read.
     * \return The value of the found property.
     * \throw ModelFitException If the property doesn't exist or returns an empty string.
     */
    MITKMODELFIT_EXPORT const std::string GetMandatoryProperty(const mitk::DataNode* node,
        const std::string& prop);

    /**
     * \brief Reads a mandatory string property from base data.
     * \param data The data whose property value should be returned.
     * \param prop The name of the property that should be read.
     * \return The value of the found property.
     * \throw ModelFitException If the property doesn't exist or returns an empty string.
     */
    MITKMODELFIT_EXPORT const std::string GetMandatoryProperty(const mitk::BaseData* data,
      const std::string& prop);

    /**
     * \brief Creates a new ModelFitInfo instance from the nodes in the passed storage.
     *
     * The fit will be identified by the passed UID.
     * \param uid The UID of the fit that identifies the nodes in the storage.
     * \param storage Pointer to the data storage containing the relevant nodes.
     * \return The newly created ModelFitInfo on success or NULL otherwise.
     */
    MITKMODELFIT_EXPORT ModelFitInfo::Pointer CreateFitInfoFromNode(const ModelFitInfo::UIDType& uid,
        const mitk::DataStorage* storage);

    /**
     * \brief Creates a new ModelFitInfo instance from a model parameterizer.
     * \param usedParameterizer Pointer to the parameterizer used for the fit.
     * \param inputImage Pointer to the input image. If it has no UID yet, one will be added.
     * \param fitType String identifying the type of fit (e.g. ROI based or pixel based).
     * \param fitName Optional human readable name of the fit.
     * \param roiUID UID of the ROI, if one was used.
     * \return The newly created ModelFitInfo on success or NULL otherwise.
     */
    MITKMODELFIT_EXPORT ModelFitInfo::Pointer CreateFitInfoFromModelParameterizer(
      const ModelParameterizerBase* usedParameterizer, mitk::BaseData* inputImage,
      const std::string& fitType, const std::string& fitName = "", const ModelFitInfo::UIDType& roiUID = "");

    /** \overload */
    MITKMODELFIT_EXPORT ModelFitInfo::Pointer CreateFitInfoFromModelParameterizer(
      const ModelParameterizerBase* usedParameterizer, mitk::BaseData* inputImage,
      const std::string& fitType, const ScalarListLookupTable& inputData, const std::string& fitName = "",
      const ModelFitInfo::UIDType& roiUID = "");

    /**
     * \brief Returns all nodes that belong to the fit indicated by the passed UID.
     * \param fitUID The UID of the fit.
     * \param storage Pointer to the data storage containing relevant nodes.
     * \return The set of found nodes or null if storage is not valid.
     */
    MITKMODELFIT_EXPORT DataStorage::SetOfObjects::ConstPointer GetNodesOfFit(
      const ModelFitInfo::UIDType& fitUID,
      const mitk::DataStorage* storage);

    typedef std::set<ModelFitInfo::UIDType> NodeUIDSetType;

    /**
     * \brief Returns the UIDs of all fits that are derived from the passed node.
     * \param node The parent node to search for derived fits.
     * \param storage Pointer to the data storage containing relevant nodes.
     * \return The set of found fit UIDs.
     */
    MITKMODELFIT_EXPORT NodeUIDSetType GetFitUIDsOfNode(const mitk::DataNode* node,
        const mitk::DataStorage* storage);

  }
}

#endif
