/* -*- mia-c++  -*-
 *
 * This file is part of MIA - a toolbox for medical image analysis
 * Copyright (c) Leipzig, Madrid 1999-2017 Gert Wollny
 *
 * MIA 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 3 of the License, or
 * (at your option) any later version.
 *
 * This program 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with MIA; if not, see <http://www.gnu.org/licenses/>.
 *
 */

#ifndef mia_core_ica_template_hh
#define mia_core_ica_template_hh

#include <mia/core/ica.hh>
#include <vector>


#ifndef EXPORT_TDataSeriesICA
#ifdef WIN32
#  define EXPORT_TDataSeriesICA __declspec(dllimport)
#else
# ifdef __GNUC__
#   define EXPORT_TDataSeriesICA __attribute__((visibility("default")))
# else
#   define EXPORT_TDataSeriesICA
# endif
#endif
#endif

NS_MIA_BEGIN

/**
   \ingroup perf

   \brief Templated representation of a ICA series analyis

   This class provides a generic implementation for the ICA analysis
   of data series.
   \tparam Data some kind of data set ofwhich series are analyzed
   The class \a Data must somehow provide:
   - a typedef \a Pointer  for a pointer like representation of itself
     or on of its base classes (preferable based on boost::shared_ptr)
   - a typedef \a dimsize_type for its the size seperated into dimensions
   - a method \a get_size() that returns \a dimsize_type
   - a method \a size() that returns the number of elements hold by itself
   - STL comaptible const and non-const iterators returned by
       functions named \a begin() and \a end()
*/

template <class Data>
class  EXPORT_TDataSeriesICA TDataSeriesICA
{
public:
       /** a set of indices used for addressing a subset of the independend componsts
        */
       typedef CIndepCompAnalysis::IndexSet IndexSet;

       /** a (shared) pointer to itself */
       typedef typename Data::Pointer PData;

       /**
          \brief ICA initialization

          The contructor for an ICA
           \param icatool tool used for the ICA analysis
          \param initializer data set containing all the time steps of input data
          \param strip_mean strip the mean from the series before processing
        */


       TDataSeriesICA(const CIndepCompAnalysisFactory&  icatool, const std::vector<Data>& initializer, bool strip_mean);

       /**  Runs the ICA
            \param ncomponents retained components
            \param strip_mean strip the mean from the input
            \param ica_normalize normalize the ICA after processing
            \param guess provide an initial guess (leave empty, if not wanted)
       */
       bool run(size_t ncomponents, bool strip_mean, bool ica_normalize,
                std::vector<std::vector<float>>  guess = std::vector<std::vector<float>>());



       /** Normalizes the ICs to the range of [-1,1] and correct the mixing matrix accordingly.
           This operation does not change the output of a mix.
        */
       void normalize();

       /// Normalizes the Mixing Matrix columns to have zero mean.
       void normalize_Mix();


       /**
           \returns the mixed signal at index \a idx
       */
       Data get_mix(size_t idx) const;

       /// \returns the mean of the input data
       const Data&  get_mean_image() const;

       /**
          Evaluate a partial mix of the ICs
          \param idx time indes
          \param skip set of components to skip when mixing
          \returns the mixed data
        */
       Data get_incomplete_mix(size_t idx, const IndexSet& skip) const;

       /**
          Evaluate a partial mix of the ICs by using the given indes set
          \param idx time indes
          \param comps set of components to use when mixing
          \returns the mixed data
        */
       Data get_partial_mix(size_t idx, const IndexSet& comps) const;

       /// \returns the mixing curves as vector of vectors
       CSlopeColumns get_mixing_curves() const;

       /**
          Obtain a specific mixing curve
          \param idx: index of requested curve, throws invalid_argument if index is out of bounds
          \returns a mixing curve

       */
       std::vector<float> get_mixing_curve(unsigned idx) const;

       /// \returns the feature data relating to component \a idx
       PData get_feature_image(size_t idx) const;

       /**
          Evaluate a mix as sum and difference of ICs
          \param plus add these ICs
          \param minus subtract these ICs
          \returns the combined signal
        */
       PData get_delta_feature(const IndexSet& plus, const IndexSet& minus)const;

       /**
          replace a mixing series by a new set
          \param index component number of the mixing curve to be replaced
          \param series new mixing data
        */
       void set_mixing_series(size_t index, const std::vector<float>& series);


       /**
          sets the number of iterations in the ICA
          \param n
        */
       void set_max_iterations(int n);

       /**
          Set the ICA approach to either FICA_APPROACH_DEFL(default) or FICA_APPROACH_SYMM.
          \param approach
        */
       void set_approach(CIndepCompAnalysis::EApproach approach);


       ~TDataSeriesICA();
private:
       PIndepCompAnalysis m_analysis;
       typedef typename Data::dimsize_type dimsize_type;
       dimsize_type m_size;
       Data m_mean;

};

NS_MIA_END

#endif
