//
// This file is part of MorphoGraphX - http://www.MorphoGraphX.org
// Copyright (C) 2012-2015 Richard S. Smith and collaborators.
//
// If you use MorphoGraphX in your work, please cite:
//   http://dx.doi.org/10.7554/eLife.05864
//
// MorphoGraphX is free software, and is licensed under under the terms of the 
// GNU General (GPL) Public License version 2.0, http://www.gnu.org/licenses.
// 
#ifndef PROCESS_HPP
#define PROCESS_HPP

/**
 * \file Process.hpp
 *
 * File containing the definition of a Process.
 */

#include <Config.hpp>
#include <GL.hpp>

#include <QIcon>
#include <QSharedPointer>
#include <QStringList>
#include <QTextStream>

#include <MGXCamera.hpp>
#include <ProcessParms.hpp>
#include <Forall.hpp>
#include <Vector.hpp>
#include <Attributes.hpp>
#include <Information.hpp>
#include <Clip.hpp>
#include <CuttingSurface.hpp>
#include <Mesh.hpp>
#include <Stack.hpp>
#include <Store.hpp>
#include <Quaternion.hpp>
#include <VisFlags.hpp>

#include <algorithm>
#include <iostream>
#include <typeinfo>
#include <tr1/memory>

class QWidget;
class MorphoGraphX;

/**
 * \def PROCESS_VERSION
 *
 * Number identifying the running version of the process API. This makes sure the loaded 
 * processes will run with the current API. Otherwise, an error informing correctly the user
 * will be shown in the standard error.
 *
 * This is set to the SVN revision number that triggered a change in the process interface 
 */
#define PROCESS_VERSION 1380

/**
 * \mainpage MorphoGraphX Plug-in documentation
 *
 * Plug-ins in MorphoGraphX are called processes. Most features in MorphoGraphX are implemented
 * internally as processes.
 *
 * All processes are inherited from the Process class.
 *
 * Plug-ins are compiled into shared object (.so) files and are loaded when MorphoGraphX starts.
 * They can be installed in a system area for all users, or in the user's home directory. Run
 * the command:
 *
 * \verbatim $ MorphoGraphX --all-process \endverbatim
 *
 * to print the plug-in directories.
 *
 * The best way to start is from a sample plug-in available from the MorphoGraphX
 * website: www.MorphoGraphX.org. 
 *
 * If you write a useful plug-in, please let us know so that we can incorporate it
 * into MorphoGraphX.
 *
 * \defgroup StackProcess Stack Processes
 *
 * List of Stack processes
 *
 * \defgroup MeshProcess Mesh Processes
 *
 * List of Mesh processes
 *
 * \defgroup MiscellaneousProcess Miscellaneous Processes
 *
 * List of Miscellaneous processes
 *
 * \defgroup ProcessUtils Process utilities
 *
 * Classes and functions needed to create your own processes or call other processes.
 */

/**
 * \namespace mgx
 *
 * This namespace contains all the API of MorphoGraphX
 */
namespace mgx 
{
  /**
	 * Here is a template of a minimal process:
   *
   * \section Basics
   *
   * \code
   * class DoNothing : public Process
   * {
   * public:
   *   // Processes can only be created with the copy constructor
   *   DoNothing(const StackProcess& proc) : Process(proc)
   *   {
   *     setName("Nothing");
   *     setDescription("Do nothing");
   *   }
   *   // Define what the class do ... here it's nothing
   *   bool run() { return true; }
   * };
   * \endcode
   *
   * Then, in the implementation file, you need to add:
   * \code
   * REGISTER_PROCESS(DoNothing);
   * \endcode
   * Which will take care of registering the process to the system when the
   * library is loaded.
   *
   * \section Recommendations
   *
   * Beside the minimal process, it is recommended to structure the process in two functions:
   * the first one taking generic arguments (i.e. a string list and a float list), the other
   * one taking specific arguments. This way, your process will
   * be easier to use from another C++ process.
   *
   * Also, to help providing meaningful (and uniform) error messages, and to help you
   * testing the current state of the process, the checkState() method is provided.
   *
   * The structure then typically becomes:
   *
   * \code
   * class DoSomething : public Process
   * {
   * public:
   *   // Add parameters in the constructor as follows:
   *   //   addParm(name, description, default, pick-list);
   *   //
   *   // Name, description, and default are all QStrings, pick-list is a QStringList.
   *   //
   *   DoSomething(const StackProcess& proc) : Process(proc)
   *   {
   *     setName("Nothing");
   *     setDescription("Do nothing");
   *     // This time, we have four parameters
   *     addParm("Store", "The store to process", "Work", storeChoice);
   *     addParm("Amount", "The amount to process", "2.0");
   *     addParm("Verbose", "Report additional information?", "Yes", booleanChoice);
   *     addParm("User Parm", "A dropdown defined by the user", "Case1", QStringList << "Case1" << "Case2");
   *   }
   *
   *   // Run the process
   *   bool run()
   *   {
   *     Store *store = currentStack()->work();
   *     bool isneeded = stringToBool(parms[1]);
   *     QString aname = parms[2];
   *     float param = parms[3].toFloat();
   *     bool result =
   *        run(stringToStore(parm("Store")), parm("Amount").toDouble(), stringToBool(parm("Verbose")), parm("User Parm"));
   *     // Update store if successful
   *     if(result)
   *       store->changed();
   *     return result;
   *   }
   *
   *   // run() with specialized arguments is recommended to be used by other C++ processes
   *   bool run(Store *store, double amount, bool percent, const QString &userParm)
   *   {
   *     // Do what is needed, return false if failed
   *     return true;
   *   }
   * };
   * \endcode
   */

  #ifndef DOXYGEN
  enum SystemCommand { UPDATE_VIEWER, LOAD_VIEW, SAVE_VIEW, SET_CURRENT_STACK,
                       TAKE_SNAPSHOT, UPDATE_STATE, SET_STATUS, SET_FRAME_VIS, SET_CAMERA_VIS };

  class PrivateProcess;
  class SetupProcess;
  #endif
  
  /**
   * \class UserCancelException Process.hpp <Process.hpp>
   *
   * Exception launched when a user clicks the Cancel button.
   * When writing your own processes, you should use the userCancel() method.
   * \ingroup ProcessUtils
   */
  class mgx_EXPORT UserCancelException : public std::exception {
  public:
    UserCancelException() : std::exception() {}
  
    const char* what() const throw() {
      return "Process canceled by user.";
    }
  };
  
  /**
   * \class Process Process.hpp <Process.hpp>
   *
   * This is the main process class, the one all process inherit from.
   * \ingroup ProcessUtils
   */
  class mgx_EXPORT Process : public QObject, public virtual ProcessParms
  {
    Q_OBJECT
    friend class SetupProcess;
  public:
    static unsigned int processVersion;
  
    typedef std::vector<Stack*>::iterator stack_iterator;
    typedef std::vector<Stack*>::const_iterator const_stack_iterator;
  
    typedef std::vector<Mesh*>::iterator mesh_iterator;
    typedef std::vector<Mesh*>::const_iterator const_mesh_iterator;

  private:
    /**
     * Constructor used only to initialize the first instance in SetupProcess.
     */
    Process();
  public:
    /**
     * Copy constructor.
     *
     * Use when inheriting from Process.
     * Normally makeProcess is used to create new processes.
     */
    Process(const Process& p);
  public:
    /**
     * Virtual destructor
     */
    virtual ~Process() {}
  
    /**
     * Method to be called anytime a file is acted on (i.e. saved/loaded).
     *
     * If needed, it will set the current folder to the one containing the file and start a session
     *
     * If it is a project file (i.e. ending in mgxv), then project_file should be set to true to force the change in
     * folder.
     */
    void actingFile(const QString& filename, bool project_file = false);
  
    /**
     * Get the file currently defining the path of the system
     */
    QString actingFile() const;
  
    /**
     * Return the python call describing the current process
     */
    QString pythonCall(const QStringList &parms) const;
  
    /**
     * Number of stacks available to the process
     */
    int stackCount() const;
    /**
     * Returns the ith stack, or 0 if there is no such stack.
     */
    Stack* stack(int i);
    /**
     * Returns the current stack (i.e. the stack currently selected by the user).
     */
    Stack* currentStack();
    /**
     * Returns the other stack (i.e. the stack not currently selected by the user).
     */
    Stack* otherStack();
    /**
     * Return the id (i.e. number) of the current stack.
     */
    int currentStackId() const;
    /**
     * Return the id (i.e. number) of the other stack.
     */
    int otherStackId() const;
    /**
     * Change which stack is current.
     */
    void setCurrentStackId(int i);
    bool setCurrentStack(int id, const QString &store);
  
    //bool resetProject();
  
    /**
     * Save screen shot to a file
     */
    bool takeSnapshot(QString filename, float overSampling = 1.0f, int width = 0, int height = 0, int quality = 95,
                      bool expand_frustum = false);
    /**
     * Display a message in the status bar  
     */
    bool setStatus(const QString &msg, bool alsoPrint = true);

    /**
     * Run a system command
     */
    bool systemCommand(int command, const QStringList &parms);

    /**
     * Get the camera
     */
    MGXCamera *camera();

    //
    /// Iterate over all the stacks
    std::pair<stack_iterator, stack_iterator> stacks();
    /// Iterate over all the stacks
    std::pair<const_stack_iterator, const_stack_iterator> stacks() const;
  
    /**
     * Add a new stack to the process
     */
    Stack* addStack();
  
    /**
     * Delete the stack of given id
     *
     * \note The current implementation assumes there are at least two stacks always available
     */
    bool deleteStack(int i);
  
    /**
     * Returns the number of mesh available to the process
     */
    int meshCount() const;
    /**
     * Returns the ith mesh
     */
    Mesh* mesh(int i);
    /**
     * Returns the current mesh (i.e. the mesh currently selected by the user)
     */
    Mesh* currentMesh();
    /**
     * Returns the other mesh (i.e. the mesh not currently selected by the user)
     */
    Mesh* otherMesh();
    /**
     * Returns the id (i.e. number) of the current mesh
     */
    int currentMeshId() const;
    /**
     * Returns the id (i.e. number) of the other mesh
     */
    int otherMeshId() const;
    /**
     * Change which mesh is current
     */
    void setCurrentMeshId(int i);
  
    /// Iterate over all the meshs
    std::pair<mesh_iterator, mesh_iterator> meshes();
    /// Iterate over all the meshs
    std::pair<const_mesh_iterator, const_mesh_iterator> meshes() const;
  
    /**
     * Add a mesh to the process for the given stack
     */
    Mesh* addMesh(const Stack* stack);
  
    /**
     * Remove a mesh from the process
     */
    bool deleteMesh(int i);
  
    /**
     * Get the current selected label
     */
    int selectedLabel() const;
  
    /**
     * Change the current selected label
     */
    void setSelectedLabel(int label);
  
    /**
     * Return the current setting for the global brightness level
     */
    float globalBrightness();
  
    /**
     * Return the current setting for the global contrast level
     */
    float globalContrast();

    /**
     * Return the current setting for the global shininess
     */
    float globalShininess(); 

    /**
     * Return the current setting for the global specular component
     */
    float globalSpecular();

    /**
     * Change the current setting for the global brightness level
     *
     * The brightness is clamped to the range [-1,1]
     */
    void setGlobalBrightness(float value);
  
    /**
     * Change the current setting for the global contrast level
     *
     * The contrast is clamped to the range [0,2]
     */
    void setGlobalContrast(float value);

     /**
     * Change the current setting for the global shininess
     *
     * The shininess is clamped to the range [0,1000]
     */
    void setGlobalShininess(float value); 

     /**
     * Change the current setting for the global specular component
     *
     * The specular component is clamped to the range [0,1]
     */
    void setGlobalSpecular(float value); 

    /**
     * Returns if the user has mesh selection active
     */
    bool meshSelection() const;
    /**
     * Returns is the user has line border selection active
     */
    bool lineBorderSelection() const;
  
    /**
     * Update the Gui of MorphoGraphX
     */
    bool updateState();
    /**
     * Tell the viewer to redraw
     */
    bool updateViewer();
    /**
     * Load viewfile
     */
    bool loadView(const QString &fileName);
     /**
     * Save viewfile
     */
    bool saveView(const QString &fileName); 
     /**
     * Set the visualization for a frame
     */
    bool setFrameVis(const QString &name, ulong flags, const Point3d &pos, const Quaternion &orient); 
     /**
     * Set the visualization for camera
     */
    bool setCameraVis(const Point3d &pos, const Quaternion &orient, const Point3d &center, double zoom); 

    /**
     * Set an error message that will be displayed if the process returns false.
     */
    bool setErrorMessage(const QString& str);
  
    /**
     * Get the current error message
     */
    QString errorMessage() const;
  
    /**
     * Set a warning message that will be displayed if the process returns true.
     */
    void setWarningMessage(const QString& str);
    /**
     * Get the current warning message
     */
    QString warningMessage() const;
  
    /**
     * Throw an exception informing the system that the user canceled the current process.
     */
    void userCancel() const { throw UserCancelException(); }
  
    /**
     * Get the name of the file that was used to load the current process 
     * (i.e. the mgxv file), if any.
     */
    const QString& file() const;
  
    /**
     * Return the object defining the first clipping region
     */
    Clip *clip1();
    /**
     * Return the object defining the second clipping region
     */
    Clip *clip2();
    /**
     * Return the object defining the third clipping region
     */
    Clip *clip3();
  
    /**
     * Return the object defining the first clipping region
     */
    const Clip *clip1() const;
    /**
     * Return the object defining the second clipping region
     */
    const Clip *clip2() const;
    /**
     * Return the object defining the third clipping region
     */
    const Clip *clip3() const;
  
    /**
     * Return the cutting surface.
     */
    CuttingSurface *cuttingSurface();

    /**
     * Return the cutting surface.
     */
    const CuttingSurface *cuttingSurface() const;
  
    //@{
    //\name Methods needed to launch other processes
  
    /**
     * Creates a process object by name
     */
    Process *makeProcess(const QString &processName);

    /**
     * Gets process
     */
    template <typename ProcessT>
    bool getProcess(const QString &processName, ProcessT* &p)
    {
      p = dynamic_cast<ProcessT*>(makeProcess(processName));
      if(p)
        return true;
      else
        return false;
    }

    /**
     * Set the parms from the GUI
     * */
    bool setCurrentParms();

    /**
     * Enumeration for process flow control
     */
    enum ProcessAction { PROCESS_RUN, PROCESS_STEP, PROCESS_REWIND } ;

    /**
     * Launch a process with generic arguments.
     *
     * Note that exceptions are filtered and converted into an error message and
     * the process returning false.
     */
    bool runProcess(Process &proc, QStringList &parms) throw();
  
    /**
     * Launch a process by name
     *
     * Note that exceptions are filtered and converted into an error message and the
     * process returning false.
     */
    bool runProcess(const QString &processName, QStringList &parms) throw();

    //@}
  
    // @{ Functions to be defined by the user

    /**
     * Initialize the process. Called from the main (GUI) thread before the process
     * is run. If there is an active GUI, then parent will be set.
     *
     * The process can use the method to update the argument list with a dialog. If the arguments
     * are updates, the process should return true
     *
     * \param parent Pointer to the parent widget if there is an active GUI.
     * @returns false if the process is not to run afterwards
     */
    virtual bool initialize(QWidget * /*parent*/) { return true; }

    /**
     * @brief Runs the process.
     *
     * @returns false if process failed, true otherwise (FIXME: what kind of fail do we care about?)
     */
    virtual bool run() { return true; }

    /**
     * This is an optional method that is called from the main thread before the process
     * is run. If there is an active GUI, then parent will be set.
     *
     * \param parent Pointer to the parent widget if there is an active GUI.
     */
    virtual bool finalize(QWidget * /*parent*/) { return true; }

    // @}
  
    static std::vector<Colorf> &LabelColors;

    //@{
    //
    //\name Methods to get and check elements
  
    /**
     * Enumeration for the bitfield that identifies stack properties
     */
    enum StackCheckType {
      STACK_ANY = 0,              ///< Any stack
      STACK_NON_EMPTY = 0x01,     ///< Non-empty stack
      STACK_VISIBLE = 0x02,       ///< Visible stack
      STACK_EMPTY = 0x04,         ///< Empty stack
  
      STACK_SCALED = 0x08,              ///< Scaled stack
      STACK_TRANSFORMED = 0x10,         ///< Transformed stack
      STACK_NON_SCALED = 0x20,          ///< Non-Scaled stack
      STACK_NON_TRANSFORMED = 0x40,     ///< Non-Transformed stack
    };
  
    /**
     * Enumeration for the bitfield that identifies store properties
     */
    enum StoreCheckType {
      STORE_ANY = 0,                ///< Any store
      STORE_NON_EMPTY = 0x0001,     ///< Non-Empty store
      STORE_VISIBLE = 0x0002,       ///< Visible store
      STORE_EMPTY = 0x0004,         ///< Empty store
  
      STORE_LABEL = 0x0008,         ///< Label store
      STORE_NON_LABEL = 0x0010,     ///< Non-Label store
  
      STORE_SCALED = 0x0020,              ///< Scaled store
      STORE_TRANSFORMED = 0x0040,         ///< Transformed store
      STORE_NON_SCALED = 0x0080,          ///< Non-Scaled store
      STORE_NON_TRANSFORMED = 0x0100,     ///< Non-Transformed store
  
      STORE_WORK = 0x1000,     ///< Work store
      STORE_MAIN = 0x2000      ///< Main store
    };
  
    /**
     * Enumeration for the bitfield that identifies mesh properties
     */
    enum MeshCheckType {
      MESH_ANY = 0,                  ///< Any mesh
      MESH_NON_EMPTY = 0x000001,     ///< Non-empty mesh
      MESH_VISIBLE = 0x000002,       ///< Either mesh or surface are visible
  
      MESH_HEAT = 0x000004,       ///< Show the heat map
      MESH_LABEL = 0x000008,      ///< Show the label
      MESH_NORMAL = 0x000010,     ///< Show the normal
  
      MESH_SIGNAL = 0x000020,      ///< Show the signal
      MESH_TEXTURE = 0x000040,     ///< Show the texture
      MESH_IMAGE = 0x000080,       ///< Show the image
  
      MESH_SHOW_MESH = 0x000100,     ///< Show the mesh
      MESH_SHOW_SURF = 0x000200,     ///< Show the surface
  
      MESH_ALL = 0x000400,         ///< Show the all mesh
      MESH_BORDER = 0x000800,      ///< Show border only
      MESH_CELLMAP = 0x001000,     ///< Show the cell map
  
      MESH_CELLS = 0x002000,           ///< This mesh is a cell mesh
      MESH_IMG_TEX = 0x004000,         ///< This mesh has a texture
      MESH_SCALED = 0x008000,          ///< This mesh is scaled
      MESH_TRANSFORMED = 0x010000,     ///< This mesh is transformed
  
      MESH_EMPTY = 0x020000,               ///< Empty mesh
      MESH_NON_CELLS = 0x040000,           ///< This mesh is not a cell mesh
      MESH_NON_IMG_TEX = 0x080000,         ///< This mesh doesn't have an image texture
      MESH_NON_SCALED = 0x100000,          ///< This mesh is non-scaled
      MESH_NON_TRANSFORMED = 0x200000,     ///< This mesh is non-transformed

      MESH_USE_PARENTS = 0x400000,         ///< Show the parent label
    };
  
    /**
     * Enumeration of the type of checks that can be performed
     */
    enum CheckType {
      CHECK_STACK = 0,     ///< Check stack properties
      CHECK_STORE = 1,     ///< Check store properties
      CHECK_MESH = 2       ///< Check mesh properties
    };
  
    enum CheckWhich {
      CHECK_CURRENT = -1     ///< Constant marking the element to check is the current one
    };
  
    /**
     * \class CheckState
     *
     * Class that construct a state check on the current process.
     */
    class mgx_EXPORT CheckState {
  public:
      CheckState(const CheckState& copy);
      CheckState(Process* process);
  
      /**
       * Add a check for a store
       */
      CheckState& store(int checks = STORE_ANY, int which = CHECK_CURRENT);
      /**
       * Add a check for a stack
       */
      CheckState& stack(int checks = STACK_ANY, int which = CHECK_CURRENT);
      /**
       * Add a check for a mesh
       */
      CheckState& mesh(int checks = MESH_ANY, int which = CHECK_CURRENT);
  
      /**
       * A CheckState object converts to true if the checks hold on the current process
       */
      operator bool();
  
  protected:
      void setError();
  
      struct ProcessReqs {
        int type;
        int checks;
        int which;
      };
  
      QList<ProcessReqs> reqs;
      Process* process;
    };
  
    friend class Process::CheckState;
  
    /**
     * Call this function and convert the result to a boolean. If the checks hold, it will return true. If not, it
     * will return false and set the error message to a standard, fully descriptive description of what conditions
     * should be met to use this process.
     *
     * Syntax:
     *
     * checkState().TYPE(CONSTRAINTS).TYPE(CONSTRAINTS)...;
     *
     * Example:
     *
     * if(!checkState().store(STORE_MAIN | STORE_NON_EMPTY)
     *                 .store(STORE_WORK | STORE_LABEL))
     *   return false;
     *
     * FIXME: what does the state apply to?
     * FIXME: why is it necessary to check it?
     * FIXME: how is the state changed?
     */
    CheckState checkState();
    //@}
  
    PrivateProcess* p;
  
  protected:
    //@{
    ///\name Internal methods
  
    /**
     * Check stack properties
     */
    bool stackCheck(int checks, int which);
    /**
     * Check store properties
     */
    bool storeCheck(int checks, int which);
    /**
     * Check mesh properties
     */
    bool meshCheck(int checks, int which);
  
    /**
     * Generate a standardised string describing how the stack should be to not generate an error
     */
    QString stackError(int checks, int which);
    /**
     * Generate a standardised string describing how the store should be to not generate an error
     */
    QString storeError(int checks, int which);
    /**
     * Generate a standardised string describing how the mesh should be to not generate an error
     */
    QString meshError(int checks, int which);
    //@}
  signals:
    void systemCommandGui(mgx::Process *, int, QStringList);
    void systemCommandProcess(mgx::Process *, int, QStringList);
  };
  
  #ifndef DOXYGEN
  
  //struct ProcessFactory 
  struct mgx_EXPORT ProcessFactory 
  {
    ProcessFactory() {}
    virtual ~ProcessFactory() {}
  
    virtual Process* operator()(const Process& process) = 0;
    virtual void reload() = 0;
  };
  
  //#  ifdef WIN32
  //struct mgx_EXPORT ProcessFactory;
  //#  endif
  
  template<typename ProcessName> struct ClassProcessFactory : public ProcessFactory 
  {
    ClassProcessFactory() : ProcessFactory(), pPtr(0) {}
  
    virtual Process* operator()(const Process& process) 
    {
      // Recycle the process object to allows variable persistence
      if(!pPtr)
        pPtr = new ProcessName(process);
      return pPtr;
    }
    void reload() 
    {
      // Recycle the process object to allows variable persistence
      if(pPtr) {
        delete pPtr;
        pPtr = 0;
      }
    }
    virtual ~ClassProcessFactory() 
    {
      if(pPtr)
        delete pPtr;
    }

    ProcessName *pPtr;
  };
  
  // Smart pointer to factory
  typedef std::tr1::shared_ptr<ProcessFactory> ProcessFactoryPtr;
  
  struct mgx_EXPORT Registration {
    typedef QList<ProcessFactoryPtr> factoryList;
  
    Registration(ProcessFactoryPtr f, const char* class_name, unsigned int compiledVersion);
    ~Registration();
    static factoryList& processFactories();
  
    ProcessFactoryPtr factory;
    const char* classname;
  };
  
  /**
   * @brief processFactories
   *
   * Wrapper around Registration::processFactories
   *
   * @return process data
   */
  inline QList<ProcessFactoryPtr>& processFactories() 
  {
    return Registration::processFactories();
  }
  #endif
  
  /**
   * \def REGISTER_PROCESS(ClassName)
   *
   * Register \c ClassName as a process. It must inherit Process and have a constructor 
   * accepting a single Process.
   * \ingroup ProcessUtils
   */
  #define REGISTER_PROCESS(ClassName) \
            mgx::Registration ClassName ## registration( \
            mgx::ProcessFactoryPtr(new mgx::ClassProcessFactory<ClassName>()), \
                                     typeid(ClassName).name(), PROCESS_VERSION)
  /**
   * \struct ProcessDefinition Process.hpp <Process.hpp>
   *
   * Definition of a process
   *  \ingroup ProcessUtils
   */
  struct mgx_EXPORT ProcessDefinition 
  {
    QString name;            ///< Name of the process
    QString description;     ///< Description of the process
    QStringList parmNames;   ///< List of named parameters of the process
    QStringList parmDescs;   ///< List of descriptions of named parameters
    QStringList parms;       ///< List of parameters/parameter defaults
    QIcon icon;              ///< Icon of the process
    ParmChoiceList parmChoice;   ///< List of choices for parameters

    /**
     * \typedef process_t
     *
     * Type of the generated process.
     */
    typedef Process process_t;
    /**
     * Process factory
     */
    ProcessFactoryPtr factory;
  };
  
  #ifndef DOXYGEN
    typedef QMap<QString, ProcessDefinition> processesMap_t;
    
    mgx_EXPORT extern processesMap_t processes;
  #endif
  
  ///\addtogroup ProcessUtils
  ///@{
  /**
   * Retrieves the process definition from the name of the process
   */
  mgx_EXPORT ProcessDefinition* getProcessDefinition(const QString& processName);
  
  /// Get the parameters for a given process
  mgx_EXPORT bool getLastParms(const Process& proc, QStringList& parms);
  /// Get the default parameters for a given process (i.e. the ones defined by the process)
  mgx_EXPORT bool getDefaultParms(const Process& proc, QStringList& parms);
  /// Save the default parameters in memory
  mgx_EXPORT bool saveDefaultParms(const Process& proc, const QStringList &parms);
  /// Check if the parameters have enough defaults
  mgx_EXPORT bool checkProcessParms(const Process& proc, const QStringList &parms, size_t* nbParms = 0);
  /// Get the parameters for a given process
  mgx_EXPORT bool getLastParms(const QString& processName, QStringList& parms);
  /// Get the default parameters for a given process (i.e. the ones defined by the process)
  mgx_EXPORT bool getDefaultParms(const QString& processName, QStringList& parms);
  /// Save the default parameters in memory
  mgx_EXPORT bool saveDefaultParms(const QString& processName, const QStringList &parms);
  /// Check if the parameters have enough defaults
  mgx_EXPORT bool checkProcessParms(const QString& processName, const QStringList &parms,
                                    size_t* nbParms = 0);
  /// Get the definition of a process
  mgx_EXPORT ProcessDefinition* getProcessDefinition(const QString& processThread, const QString& processName);
  /// Returns the list of names of the processes
  mgx_EXPORT QStringList listProcesses();
  /// Split process name into Tab/Folder/Name
  mgx_EXPORT bool getProcessText(const QString &text, QString &tab, QString &folder, QString &name);

  /**
   * Check if the \c processName exist in the list of processes.
   */
  mgx_EXPORT bool validProcessName(const QString& processName);
  
  /// Helper function converting a string into a boolean.
  mgx_EXPORT bool stringToBool(const QString& string);
  /// Returns true if \c string correspond to the work store, false otherwise
  mgx_EXPORT bool stringToWorkStore(const QString& string);
  /// Returns true if \c string correspond to the main store, false otherwise
  mgx_EXPORT bool stringToMainStore(const QString& string);
  
  /// Helper function converting a boolean into a string
  inline QString boolToString(bool b) { return (b ? "Yes" : "No"); }
  
  ///@}
}
#endif
