/*
 *  Copyright (c) 2008 Cyrille Berger <cberger@cberger.net>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation;
 * either version 2, or (at your option) any later version of the License.
 *
 * This library 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this library; see the file COPYING.  If not, write to
 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301, USA.
 */

#ifndef _OPENCTL_APPLICATOR_H_
#define _OPENCTL_APPLICATOR_H_

#include <list>
#include <GTLCore/ChannelsFlags.h>
#include <GTLCore/String.h>
#include <OpenCTL/Export.h>

namespace GTLCore {
  class Buffer;
  class PixelDescription;
  class String;
  class Value;
  class AbstractImage;
  class ProgressReport;
}

namespace OpenCTL {
  class Module;
  /**
   * CTL Programs are functions that are applied to a buffer a pixels, one at a time.
   * 
   * Example:
   * @code
   * OpenCTL::Module p("testCall");
   * p.setSource( " \
   * void testCall(int a, output int b) \n\
   * { \n\
   *   b = a + 1; \n\
   *   return; \n\
   * }");
   * p.compile();
   * OpenCTL::Program Program( "testCall2", &p, GTLCore::PixelDescription( GTLCore::Type::Integer8, 1));
   * GTLCore::Array arr( 4 );
   * arr.data()[0] = 10;
   * arr.data()[1] = 30;
   * arr.data()[2] = 50;
   * arr.data()[3] = 60;
   * Program.apply(arr, arr);
   * @endcode
   * @ingroup OpenCTL
   */
  class OPENCTL_EXPORT Program {
      GTL_NO_COPY(Program);
    public:
      /**
       * @param functionName          the name of the function to call on each pixel, it must be able to
       *                              take as input the pixel of pixelDescription and as output.
       *                              For instance if your pixel is an integer and float (int,float)
       *                              the function must have the following signature:
       *                              void function(int, float, output int, output float);
       * @param module                the module with the function
       * @param pixelDescription   an object holding the information aobut the pixel
       */
      Program(const GTLCore::String& functionName, const Module* module, const GTLCore::PixelDescription& pixelDescription);
      /**
       * @param functionName          the name of the function to call on each pixel, it must be able to
       *                              take as input the pixel of pixelDescription and as output.
       *                              For instance if your pixel is an integer and float (int,float)
       *                              the function must have the following signature:
       *                              void function(int, float, output int, output float);
       * @param module                the module with the function
       * @param srcPixelDescription   an object holding the information aobut the source pixel
       * @param dstPixelDescription   an object holding the information aobut the destination pixel
       */
      Program(const GTLCore::String& functionName, const Module* module, const GTLCore::PixelDescription& srcPixelDescription, const GTLCore::PixelDescription& dstPixelDescription );
      /**
       * @param functionName          the name of the function to call on each pixel, it must be able to
       *                              take as input the pixel of pixelDescription and as output.
       *                              For instance if your pixel is an integer and float (int,float)
       *                              the function must have the following signature:
       *                              void function(int, float, output int, output float);
       * @param module                the module with the function
       * @param srcPixelDescription   an object holding the information aobut the different source pixel
       * @param dstPixelDescription   an object holding the information aobut the destination pixel
       */
      Program(const GTLCore::String& functionName, const Module* module, const std::list<GTLCore::PixelDescription>& srcPixelDescriptions, const GTLCore::PixelDescription& dstPixelDescription );
      ~Program();
      /**
       * @return true if the program was correctly initialised
       */
      bool isInitialised() const;
      void apply(const GTLCore::Buffer& input, GTLCore::Buffer& output, GTLCore::ProgressReport* report = 0, const GTLCore::ChannelsFlags& flags = GTLCore::ChannelsFlags()) const;
      void apply(const std::list<GTLCore::Buffer*>& inputs, GTLCore::Buffer& output, GTLCore::ProgressReport* report = 0, const GTLCore::ChannelsFlags& flags = GTLCore::ChannelsFlags()) const;
      void apply(const GTLCore::AbstractImage& input, GTLCore::AbstractImage& output, GTLCore::ProgressReport* report = 0, const GTLCore::ChannelsFlags& flags = GTLCore::ChannelsFlags()) const;
      /**
       * Set a varying argument of the function used by the program.
       * For instance the following CTL code gives access to exposure as a <em>varying</em>
       * argument.
       * 
       */
      void setVarying( const GTLCore::String& _name, const GTLCore::Value& _value );
      /**
       * Set a varying argument of the function used by the program.
       * For instance the following CTL code gives access to exposure as a <em>varying</em>
       * argument.
       *
       */
      void setVarying( std::size_t _id, const GTLCore::Value& _value );
      /**
       * @return a varying argument of a function.
       */
      GTLCore::Value varying( const GTLCore::String& _name ) const;
      /**
       * @return a varying argument of a function.
       */
      GTLCore::Value varying( std::size_t _id ) const;
      /**
       * @return the id varying argument of a function. To be used with setVarying and varying
      */
      std::size_t varyingId( const GTLCore::String& _name ) const;
      /**
       * @return the list of varying parameters for this program
       */
      const std::list<GTLCore::String>& varyings() const;
    private:
      /**
       * Init the program
       */
      void init(const GTLCore::String& functionName, const Module* module);
    private:
      struct Private;
      Private* const d;
  };

}

#endif
