/* file: algorithm_types.h */
/*******************************************************************************
* Copyright 2014-2019 Intel Corporation.
*
* This software and the related documents are Intel copyrighted  materials,  and
* your use of  them is  governed by the  express license  under which  they were
* provided to you (License).  Unless the License provides otherwise, you may not
* use, modify, copy, publish, distribute,  disclose or transmit this software or
* the related documents without Intel's prior written permission.
*
* This software and the related documents  are provided as  is,  with no express
* or implied  warranties,  other  than those  that are  expressly stated  in the
* License.
*******************************************************************************/

/*
//++
//  Implementation of base classes defining algorithm interface.
//--
*/

#ifndef __ALGORITHM_TYPES_H__
#define __ALGORITHM_TYPES_H__

#include "services/daal_defines.h"
#include "data_management/data/data_archive.h"
#include "data_management/data/data_serialize.h"
#include "data_management/data/data_collection.h"
#include "services/error_handling.h"

namespace daal
{
/**
 * @defgroup base_algorithms Base Classes
 * \copydoc daal::algorithms
 * @ingroup algorithms
 */
/**
 * \brief Contains classes that implement algorithms for data analysis(data mining), and data modeling(training and prediction).
 *        These algorithms include matrix decompositions, clustering algorithms, classification and regression algorithms,
 *        as well as association rules discovery.
 */
namespace algorithms
{

/**
 * \brief Contains version 1.0 of Intel(R) Data Analytics Acceleration Library (Intel(R) DAAL) interface.
 */
namespace interface1
{
/**
 * @ingroup base_algorithms
 * @{
 */
/**
 *  <a name="DAAL-STRUCT-ALGORITHMS__PARAMETER"></a>
 *  \brief %Base class to represent computation parameters.
 *         Algorithm-specific parameters are represented as derivative classes of the Parameter class.
 */
struct Parameter
{
    DAAL_NEW_DELETE();

    Parameter(){}
    virtual ~Parameter() {}

    virtual services::Status check() const { return services::Status(); }
};

/**
 *  <a name="DAAL-CLASS-ALGORITHMS__ARGUMENT"></a>
 *  \brief %Base class to represent computation input and output arguments.
 */
class DAAL_EXPORT Argument
{
public:
    DAAL_NEW_DELETE();

    /** Default constructor. Constructs empty arguments */
    Argument() : idx(0) {}

    /**
     * Constructs conputation argument that contains n elements
     * \param[in] n     Number of elements in the argument
     */
    Argument(const size_t n);

    virtual ~Argument() {};

    /**
     * Inserts element into this argument structure
     * \param[in] val   Element to insert
     * \return Updated argument structure
     */
    Argument &operator <<(const data_management::SerializationIfacePtr &val)
    {
        (*_storage) << val;
        return *this;
    }

    /**
     * Retrieves number of elements in the argument
     * \return  Number of elements in the argument
     */
    size_t size() const
    {
        return _storage->size();
    }

protected:
    /**
    * Copy constructor
    * \param[in] other Instance of the same class to copy
    */
    Argument(const Argument& other);

    /**
     * Retrieves specified element
     * \param[in] index Index of the element
     * \return Reference to the requested element
     */
    const data_management::SerializationIfacePtr &get(size_t index) const;

    /**
     * Sets the element to the specified position in the Argument
     * \param[in] index Index of the element
     * \param[in] value Pointer to the element
     * \return Reference to the requested element
     */
    void set(size_t index, const data_management::SerializationIfacePtr &value);

    /**
    * Sets the custom storage in the Argument
    * \param[in] storage custom defined storage
    */
    void setStorage(const data_management::DataCollectionPtr& storage);

    /**
    * Gets the storage in the Argument
    * \return Storage
    */
    static data_management::DataCollectionPtr& getStorage(Argument& a);

    /**
    * Gets the const storage in the Argument
    * \return Storage
    */
    static const data_management::DataCollectionPtr& getStorage(const Argument& a);


    template<typename Archive, bool onDeserialize>
    services::Status serialImpl(Archive *arch)
    {
        arch->set(idx);
        arch->setObj(_storage.get());

        return services::Status();
    }

private:
    size_t idx;
    data_management::DataCollectionPtr _storage;
};

/**
*  <a name="DAAL-CLASS-ALGORITHMS__SERIALIZABLE_ARGUMENT"></a>
*  \brief %Base class to represent argument with serialization methods
*/
class SerializableArgument : public data_management::SerializationIface, public Argument
{
public:
    DAAL_NEW_DELETE();

    /** Default constructor. Constructs empty argument */
    SerializableArgument() {}

    /**
    * Constructs argument with n elements
    * \param[in] n     Number of elements in the input argument
    */
    SerializableArgument(const size_t n) : Argument(n) {}

    virtual ~SerializableArgument() {};
};

/**
 *  <a name="DAAL-CLASS-ALGORITHMS__INPUT"></a>
 *  \brief %Base class to represent computation input arguments.
 *         Algorithm-specific input arguments are represented as derivative classes of the Input class.
 */
class Input : public Argument
{
public:
    DAAL_NEW_DELETE();

    /** Default constructor. Constructs empty input arguments */
    Input() {}

    /**
     * Constructs input arguments with n elements
     * \param[in] n     Number of elements in the input argument
     */
    Input(const size_t n) : Argument(n) {}

    virtual ~Input() {};

    /**
     * Checks the correctness of the input arguments
     * \param[in] parameter     Pointer to the parameters of the algorithm
     * \param[in] method        Computation method
     */
    virtual services::Status check(const Parameter *parameter, int method) const { return services::Status(); }

protected:
    /**
    * Copy constructor
    * \param[in] other Instance of the same class to copy
    */
    Input(const Input& other) : Argument(other){}
};

/**
 *  <a name="DAAL-CLASS-ALGORITHMS__PARTIALRESULT"></a>
 *  \brief %Base class to represent partial results of the computation.
 *         Algorithm-specific partial results are represented as derivative classes of the PartialResult class.
 */
class PartialResult : public SerializableArgument
{
public:
    DAAL_NEW_DELETE();

    /** Default constructor. Constructs empty partial results */
    PartialResult() : _initFlag(false) {};

    /**
     * Constructs partial results with n elements
     * \param[in] n     Number of elements in the partial results
     */
    PartialResult(const size_t n) : SerializableArgument(n), _initFlag(false) {}

    virtual ~PartialResult() {};

    /**
     * \copydoc daal::data_management::interface1::SerializationIface::getSerializationTag()
     */
    virtual int getSerializationTag() const { return 0; }

    /**
     * Retrieves the initialization flag
     * \return Initialization flag. True, if the partial results are already initialized; false - otherwise.
     */
    bool getInitFlag() { return _initFlag; }

    /**
     * Sets the initialization flag
     * \param[in] flag  Initialization flag. True, if the partial results are already initialized; false - otherwise.
     */
    void setInitFlag(bool flag) { _initFlag = flag; }

    /**
     * Checks the correctness of the partial results structure
     * \param[in] input         Pointer to the input arguments of the algorithm
     * \param[in] parameter     Pointer to the parameters of the algorithm
     * \param[in] method        Computation method
     */
    virtual services::Status check(const Input *input, const Parameter *parameter, int method) const
    {
        return services::Status();
    }

    /**
    * Checks the correctness of the partial results structure
    * \param[in] parameter     Pointer to the parameters of the algorithm
    * \param[in] method        Computation method
    */
    virtual services::Status check(const Parameter *parameter, int method) const { return services::Status(); }

private:
    bool _initFlag;

protected:
    /** \private */
    template<typename Archive, bool onDeserialize>
    services::Status serialImpl(Archive *arch)
    {
        Argument::serialImpl<Archive, onDeserialize>(arch);

        arch->set(_initFlag);

        return services::Status();
    }
    virtual services::Status serializeImpl(data_management::InputDataArchive *archive)
    {
        return services::Status();
    }
    virtual services::Status deserializeImpl(const data_management::OutputDataArchive *archive)
    {
        return services::Status();
    }
};

/**
 *  <a name="DAAL-CLASS-ALGORITHMS__RESULT"></a>
 *  \brief %Base class to represent final results of the computation.
 *         Algorithm-specific final results are represented as derivative classes of the Result class.
 */
class Result : public SerializableArgument
{
public:
    DAAL_NEW_DELETE();

    /** Default constructor. Constructs empty final results */
    Result() {}

    /**
     * Constructs final results with n elements
     * \param[in] n     Number of elements in the final results
     */
    Result(const size_t n) : SerializableArgument(n) {}

    virtual ~Result() {};

    /**
     * \copydoc daal::data_management::interface1::SerializationIface::getSerializationTag()
     */
    virtual int getSerializationTag() const { return 0; }

    /**
     * Checks the correctness of the final results structure
     * \param[in] input         Pointer to the input arguments of the algorithm
     * \param[in] parameter     Pointer to the parameters of the algorithm
     * \param[in] method        Computation method
     */
    virtual services::Status check(const Input *input, const Parameter *parameter,  int method) const
    {
        return services::Status();
    }

    /**
    * Checks the correctness of the partial result structure
    * \param[in] partialResult Pointer to the partial result arguments of the algorithm
    * \param[in] parameter     Pointer to the parameters of the algorithm
    * \param[in] method        Computation method
    */
    virtual services::Status check(const PartialResult *partialResult, const Parameter *parameter, int method) const
    {
        return services::Status();
    }


protected:
    /** \private */
    template<typename Archive, bool onDeserialize>
    services::Status serialImpl(Archive *arch)
    {
        Argument::serialImpl<Archive, onDeserialize>(arch);

        return services::Status();
    }
    virtual services::Status serializeImpl(data_management::InputDataArchive *archive)
    {
        return services::Status();
    }
    virtual services::Status deserializeImpl(const data_management::OutputDataArchive *archive)
    {
        return services::Status();
    }
};

/**
*  <a name="DAAL-CLASS-ALGORITHMS__OPTIONAL_ARGUMENT"></a>
*  \brief %Base class to represent argument with serialization methods
*/
class DAAL_EXPORT OptionalArgument : public SerializableArgument
{
public:
    DECLARE_SERIALIZABLE_TAG();

    /** Default constructor. Constructs empty argument */
    OptionalArgument() : SerializableArgument(0) {}

    /**
    * Constructs argument with n elements
    * \param[in] n     Number of elements in the input argument
    */
    OptionalArgument(const size_t n) : SerializableArgument(n) {}

    /**
    * Retrieves specified element
    * \param[in] index Index of the element
    * \return Reference to the requested element
    */
    const data_management::SerializationIfacePtr &get(size_t index) const { return SerializableArgument::get(index); }

    /**
    * Sets the element to the specified position in the Argument
    * \param[in] index Index of the element
    * \param[in] value Pointer to the element
    * \return Reference to the requested element
    */
    void set(size_t index, const data_management::SerializationIfacePtr &value) { return SerializableArgument::set(index, value); }

protected:
    /** \private */
    template<typename Archive, bool onDeserialize>
    services::Status serialImpl(Archive *arch)
    {
        Argument::serialImpl<Archive, onDeserialize>(arch);

        return services::Status();
    }

    services::Status serializeImpl(data_management::InputDataArchive  *arch) DAAL_C11_OVERRIDE
    {
        serialImpl<data_management::InputDataArchive, false>(arch);

        return services::Status();
    }

    services::Status deserializeImpl(const data_management::OutputDataArchive *arch) DAAL_C11_OVERRIDE
    {
        serialImpl<const data_management::OutputDataArchive, true>(arch);

        return services::Status();
    }
};
typedef services::SharedPtr<Input> InputPtr;
typedef services::SharedPtr<PartialResult> PartialResultPtr;
typedef services::SharedPtr<Result> ResultPtr;
typedef services::SharedPtr<OptionalArgument> OptionalArgumentPtr;

/** @} */
} // namespace interface1
using interface1::Parameter;
using interface1::Argument;
using interface1::Input;
using interface1::InputPtr;
using interface1::PartialResult;
using interface1::PartialResultPtr;
using interface1::Result;
using interface1::ResultPtr;
using interface1::OptionalArgument;
using interface1::OptionalArgumentPtr;

}
}
#endif
