#!/bin/bash

# note: you can use this script independently to generate a CEP:
# source /path/to/this/script/generate-cep.sh
# generateCompleteCEP path/to/bin/camitk-extensiongenerator

generateCompleteCEP() {
camitkDir="$(dirname $1)/.."

echo "Generating complete CEP in $(pwd)..."

# create directory structure
mkdir -p actions/test1 # Standard
mkdir -p actions/test2 # Standard
mkdir -p actions/test3 # HotPlug
mkdir -p libraries/testlib

echo "Extracting CMake files..."

cat << EOF > CMakeLists.txt
#--------------------------------------------
#         CamiTK Extension Project
#--------------------------------------------
cmake_minimum_required(VERSION 3.20)

# Find CamiTK SDK
set(CAMITK_DIR "${camitkDir}")
set(CMAKE_MODULE_PATH \${CMAKE_MODULE_PATH} \${CMAKE_CURRENT_SOURCE_DIR} \${EXTENSION_GENERATOR_CMAKE_MODULE_PATH})

project(completetestcep1)

# CamiTK requires C++11
# All target after this declaration will be compile with c++11 policy
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)

find_package(CamiTK REQUIRED)
include(\${CAMITK_USE_FILE})

# define the CEP
camitk_extension_project(NAME "Complete test CEP 1" 
                        CONTACT "timc-camitk@univ-grenoble-alpes.fr"
                        DESCRIPTION "This CEP is trying to achieve a complete test of all possible cepcoreschema element"
                        ENABLED
                        # Uncomment the next line to activate the CamiTK testing framework 
                        # and enable component and action automatic tests
                        #ENABLE_TESTING
                        # Uncomment the next line to be able to generate a test coverage html report
                        #ENABLE_TEST_COVERAGE
)
EOF

cat << EOF > FindCamiTK.cmake
#
# DO NOT EDIT THIS FILE OR YOU WILL DAMAGE ALL YOUR CONFIGURATION
#
# Try to find a CamiTK installation or build tree (CAMITK_DIR)
# If CamiTK is not found, CAMITK_FOUND is set to false.
#
# This module can be used to find CamiTK.
#
# To use this file, you just need to have the path to it in your
# CMAKE_MODULE_PATH and add this line to your CMakeLists.txt
#
# find_package(CamiTK \${CAMITK_VERSION} REQUIRED)
#
# where CAMITK_VERSION is the minimal needed version (e.g. "3.2")
#
# Once done, just add this line to your CMakeLists.txt:
# include("\${CAMITK_USE_FILE}")
# et voilà!
#
# Once this module has run, the following variables will be properly defined
#  CAMITK_FOUND            - system has CamiTK
#  CAMITK_DIR              - root installation for CamiTK (at least the SDK)
#  CAMITK_USE_FILE         - CMake file to use CamiTK (CamiTKConfig.cmake)
#  CAMITK_VERSION_MAJOR    - CamiTK major version number.
#  CAMITK_VERSION_MINOR    - CamiTK minor version number
#

#=============================================================================
# \$CAMITK_LICENCE_BEGIN$
# 
# CamiTK - Computer Assisted Medical Intervention ToolKit
# (c) 2001-2025 Univ. Grenoble Alpes, CNRS, Grenoble INP - UGA, TIMC, 38000 Grenoble, France
# 
# Visit http://camitk.imag.fr for more information
# 
# This file is part of CamiTK.
# 
# CamiTK is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License version 3
# only, as published by the Free Software Foundation.
# 
# CamiTK 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 version 3 for more details.
# 
# You should have received a copy of the GNU Lesser General Public License
# version 3 along with CamiTK.  If not, see <http://www.gnu.org/licenses/>.
# \$CAMITK_LICENCE_END$
#=============================================================================
# (To distribute this file outside of CMake, substitute the full
#  License text for the above reference.)

#-- CamiTK currently requires Cmake 3.13 
cmake_policy(VERSION 3.13)

message(STATUS "Looking for CamiTK \${CamiTK_FIND_VERSION}")

# Assume not found.
set(CAMITK_FOUND FALSE)

# name of the camitk configuration file (created during SDK build)
set(CAMITK_USE_FILE "CamiTKConfig.cmake")
set(CAMITK_DIR_DESCRIPTION "directory containing a build tree or install tree of CamiTK.\n   It must have the camitk-config binary in its 'bin' subdirectory.")

# ------------------------------------
# Stage #1: try to find camitk-config
# ------------------------------------

# User Config directory variable (if the user installed CamiTK her/himself the
# CamiTKDir.txt file can be found there
# see https://doc.qt.io/qt-5/qsettings.html#platform-specific-notes
if(WIN32)
    # %APPDATA%
    set(FIND_CAMITK_USER_BASE_DIR \$ENV{APPDATA})
else() # (UNIX OR APPLE)
    # \$HOME/.config/
    set(FIND_CAMITK_USER_BASE_DIR "\$ENV{HOME}/.config")
endif()

# Check if the user installed CamiTK her/himself
if (EXISTS "\${FIND_CAMITK_USER_BASE_DIR}/CamiTK/CamiTKDir.txt")
    file(STRINGS "\${FIND_CAMITK_USER_BASE_DIR}/CamiTK/CamiTKDir.txt" FIND_CAMITK_USER_DIR_LAST_INSTALL)
endif()

# Try to find camitk-config binary in usual/recommanded path/variable/user directories
find_program(CAMITK_CONFIG_EXECUTABLE
        NAMES camitk-config-debug camitk-config
        PATH_SUFFIXES "bin"
        PATHS
                #-- 0. from CAMITK_DIR environment or cache variable
                "\${CAMITK_DIR}"
                "\$ENV{CAMITK_DIR}"
                "\${EXTENSION_GENERATOR_CAMITK_DIR}"

                #-- 1. Build path
                # Read from the CMakeSetup registry entries.  It is likely that
                # CamiTK will have been recently built.
                [HKEY_CURRENT_USER\\\\Software\\\\Kitware\\\\CMakeSetup\\\\Settings\\\\StartPath;WhereBuild1]
                [HKEY_CURRENT_USER\\\\Software\\\\Kitware\\\\CMakeSetup\\\\Settings\\\\StartPath;WhereBuild2]
                [HKEY_CURRENT_USER\\\\Software\\\\Kitware\\\\CMakeSetup\\\\Settings\\\\StartPath;WhereBuild3]
                [HKEY_CURRENT_USER\\\\Software\\\\Kitware\\\\CMakeSetup\\\\Settings\\\\StartPath;WhereBuild4]
                [HKEY_CURRENT_USER\\\\Software\\\\Kitware\\\\CMakeSetup\\\\Settings\\\\StartPath;WhereBuild5]
                [HKEY_CURRENT_USER\\\\Software\\\\Kitware\\\\CMakeSetup\\\\Settings\\\\StartPath;WhereBuild6]
                [HKEY_CURRENT_USER\\\\Software\\\\Kitware\\\\CMakeSetup\\\\Settings\\\\StartPath;WhereBuild7]
                [HKEY_CURRENT_USER\\\\Software\\\\Kitware\\\\CMakeSetup\\\\Settings\\\\StartPath;WhereBuild8]
                [HKEY_CURRENT_USER\\\\Software\\\\Kitware\\\\CMakeSetup\\\\Settings\\\\StartPath;WhereBuild9]
                [HKEY_CURRENT_USER\\\\Software\\\\Kitware\\\\CMakeSetup\\\\Settings\\\\StartPath;WhereBuild10]

                # For camitk communityedition compilation
                "\${CMAKE_BINARY_DIR}"

                #-- 2. installed path
                # Unix/MacOS
                "/usr"
                "/usr/local"
                "/opt/CamiTK"
                "\$ENV{HOME}/Dev/CamiTK"
                "\$ENV{HOME}/Dev/camitk"
                
                # Windows
                "C:/Programs "
                "C:/Programs/CamiTK"
                "C:/Program Files/CamiTK"
                "C:/Programs/camitk"
                "C:/Program Files/camitk"
                "C:/Dev"
                "C:/Dev/CamiTK"
                "C:/Dev/camitk"

                # From last installation
                "\${FIND_CAMITK_USER_DIR_LAST_INSTALL}"
)

# hide this from the user
mark_as_advanced(CAMITK_CONFIG_EXECUTABLE)

# ---------------------------------
# Stage 2: Identify CamiTK version
# ---------------------------------
if (NOT CAMITK_CONFIG_EXECUTABLE)
    # camitk-config is not in an obvious place, ask the user to update its PATH env. variable, or define CAMITK_DIR
    set(CAMITK_NOT_FOUND_MESSAGE "CamiTK not found.\n   To solve this problem, you can (in order of preference):\n   a) make sure CamiTK SDK is installed and camitk-config is in a directory included\n      in the environment command path (\$PATH or %PATH%).\n   b) or specify the CMake cache variable (e.g. modify the value directly in the cmake GUI\n      or run cmake from the command line with -DCAMITK_DIR:PATH=...)\n   c) or specify a CAMITK_DIR environment variable (system variable)")
    # use file was not found, camitk-imp was no help
    set(CAMITK_DIR "CAMITK_DIR-NOTFOUND" CACHE PATH "The \${CAMITK_DIR_DESCRIPTION}" FORCE)
else()
    # get the path to the installation dir from the camitk-config
    execute_process(COMMAND "\${CAMITK_CONFIG_EXECUTABLE}" "--camitk-dir"
                RESULT_VARIABLE CAMITK_CONFIG_DIR_RETURN_CODE
                OUTPUT_VARIABLE CAMITK_CONFIG_DIR_OUTPUT
                ERROR_VARIABLE  CAMITK_CONFIG_DIR_OUTPUT_ERROR
                OUTPUT_STRIP_TRAILING_WHITESPACE
                ERROR_STRIP_TRAILING_WHITESPACE
    )    

    if (CAMITK_CONFIG_DIR_RETURN_CODE)
        set(CAMITK_NOT_FOUND_MESSAGE "CamiTK configuration utility reports errors. Check the output of \${CAMITK_DIR}/bin/camitk-config --camitk-dir\n   Returns:\n   \${CAMITK_CONFIG_DIR_RETURN_CODE}\n   Error message:\n\${CAMITK_CONFIG_DIR_OUTPUT_ERROR}\n   Output:\${CAMITK_CONFIG_DIR_OUTPUT}")
    else()
        # use camitk-config output directly
        set(CAMITK_DIR \${CAMITK_CONFIG_DIR_OUTPUT})
        
        # get the version number automatically from camitk-config
        execute_process(COMMAND "\${CAMITK_CONFIG_EXECUTABLE}" "--short-version"
                    RESULT_VARIABLE CAMITK_CONFIG_VERSION_RETURN_CODE
                    OUTPUT_VARIABLE CAMITK_CONFIG_VERSION_OUTPUT
                    ERROR_VARIABLE  CAMITK_CONFIG_VERSION_OUTPUT_ERROR
                    OUTPUT_STRIP_TRAILING_WHITESPACE
                    ERROR_STRIP_TRAILING_WHITESPACE
        )

        if (CAMITK_CONFIG_VERSION_RETURN_CODE)
            set(CAMITK_NOT_FOUND_MESSAGE "CamiTK configuration utility reports errors. Check the output of \${CAMITK_DIR}/bin/camitk-config --short-version\n   Returns:\n   \${CAMITK_CONFIG_VERSION_RETURN_CODE}\n   Error message:\n\${CAMITK_CONFIG_VERSION_OUTPUT_ERROR}\n   Output:\${CAMITK_CONFIG_VERSION_OUTPUT}")
        else()
            # use camitk-config output directly
            set(CAMITK_SHORT_VERSION_STRING \${CAMITK_CONFIG_VERSION_OUTPUT})
            # extract major and minor version
            string(REGEX REPLACE "^camitk-([0-9]+).*" "\\\\1" CAMITK_VERSION_MAJOR "\${CAMITK_SHORT_VERSION_STRING}")
            string(REGEX REPLACE "^camitk-[0-9]+\\\\.([0-9]+)" "\\\\1" CAMITK_VERSION_MINOR "\${CAMITK_SHORT_VERSION_STRING}")
            set(CAMITK_VERSION_FOUND "\${CAMITK_VERSION_MAJOR}.\${CAMITK_VERSION_MINOR}")
        endif()
    endif()   
endif()


# -----------------------------------------------------------------------------------
# Stage 3: check that the version matches (if the user asked for a specific version)
# -----------------------------------------------------------------------------------
if (CAMITK_VERSION_FOUND)
    if(CamiTK_FIND_VERSION)
        if ("\${CAMITK_VERSION_FOUND}" STRLESS "\${CamiTK_FIND_VERSION}")
            set(CAMITK_NOT_FOUND_MESSAGE "CamiTK \${CAMITK_VERSION_FOUND} found, mismatch required version \${CamiTK_FIND_VERSION}\n   To solve this problem, you can (in order of preference):\n   a) make sure CamiTK SDK \${CamiTK_FIND_VERSION} is installed and camitk-config is in a directory included\n      in the environment command path (\$PATH or %PATH%) before the install dir of version \${CAMITK_VERSION_FOUND}\n   b) or specify the CMake cache variable (e.g. modify the value directly in the cmake GUI\n      or run cmake from the command line with -DCAMITK_DIR:PATH=...)\n   c) or specify a CAMITK_DIR environment variable (system variable)\n   d) or remove the version requirement in the CMakeLists.txt (e.g. use a simple\n      \"find_package(CamiTK REQUIRED)\" without specifying the version)")
        else()
            set(CAMITK_VERSION_MESSAGE " (found suitable version \"\${CAMITK_VERSION_FOUND}\", required is \"\${CamiTK_FIND_VERSION}\")")
            set(CAMITK_FOUND TRUE)            
        endif()
    else()
        set(CAMITK_FOUND TRUE)
    endif()
endif()

# -------------------------
# Stage 4: Notify the user
# -------------------------
if(CAMITK_FOUND)
    # advertise the success
    message(STATUS "Found CamiTK (version \${CAMITK_VERSION_FOUND}) in \${CAMITK_DIR}\${CAMITK_VERSION_MESSAGE}")
    # update module path and use file
    set(CAMITK_USE_FILE "CamiTKConfig")
    # setup the module path to find the use file
    set(CMAKE_MODULE_PATH \${CMAKE_MODULE_PATH} \${CAMITK_DIR}/share/\${CAMITK_SHORT_VERSION_STRING}/cmake)
else()
    # CamiTK not found, explain to the user how to specify its location.
    if(CamiTK_FIND_REQUIRED)
        message(FATAL_ERROR \${CAMITK_NOT_FOUND_MESSAGE})
    else()
        if(NOT CamiTK_FIND_QUIETLY)
            message(STATUS \${CAMITK_NOT_FOUND_MESSAGE})
        endif()
    endif()
endif()
EOF

CMakeListsSubDir="# find subdirectories
get_subdirectories(DIR_LIST)

# Add subdirectories in CMake project
foreach(DIR_NAME \${DIR_LIST})
add_subdirectory(\${DIR_NAME})
endforeach()"

echo "$CMakeListsSubDir" > actions/CMakeLists.txt
echo "$CMakeListsSubDir" > libraries/CMakeLists.txt

cat << EOF > libraries/testlib/CMakeLists.txt
project(testlib)

# Call CamiTK CMake Macro to define Testlib library
gather_headers_and_sources(TESTLIB)

camitk_library(SHARED
            SOURCES \${TESTLIB_HEADERS} \${TESTLIB_SOURCES} 
            NEEDS_ITK
            DEFINES COMPILE_TESTLIB_EXPORT
            NEEDS_CEP_LIBRARIES qtpropertybrowser
            DESCRIPTION "A simple test lib. This lib will not compile unless some minimal C++ code is present in the generated source. Copy TestLib.h and TestLib.cpp to the library directory before configuration time."
)
EOF

echo "Extracting .camitk files..."

cat <<EOF > actions/test1/test1.camitk
{
    "camitk": {
        "extensions": {
            "contact": {
            "author": "camitk-team",
            "email": "timc-camitk@univ-grenoble-alpes.fr"
            },
            "name": "Test Action Extension 1",
            "description": "Test the first action extension.",
            "generationType": "Standard",
            "license": "/*****************************************************************************\n*\n * CamiTK - Computer Assisted Medical Intervention ToolKit\n * (c) 2001-2024 camitk-team <timc-camitk@univ-grenoble-alpes.fr>\n *\n * Visit http://camitk.imag.fr for more information\n *\n * This file is part of CamiTK.\n *\n * completetest1 is under the following licence:\n * This is the complete licence, it covers everything, everywhere,\n * for everyone at everytime.\n *\n * This is just an example of a user-defined licence...\n *\n****************************************************************************/",
            "extensionDependencies": "NEEDS_ITK\nNEEDS_CEP_LIBRARIES testlib",
            "actions": [
                {
                "name": "Test Action 1",
                "description": "Test a first action, for image component, with a lot of parameters",
                "componentClass": "ImageComponent",
                "classification": {              
                    "family": "Complete Test Actions #1",
                    "tags": [ 
                    "Test", 
                    "Action #1",
                    "ImageComponent"
                    ]
                },
                "gui": "Default Action GUI",
                "implementationIncludes": "#include <QDate>\n#include<QVector3D>\n#include<QTime>",
                "parameters": [
                                {
                                    "name": "p1",
                                    "type": "int",
                                    "description": "This is p1",
                                    "unit": "unit 1",
                                    "defaultValue": 42
                                },
                                {
                                    "name": "p2",
                                    "type": "bool",
                                    "description": "This is p2",
                                    "unit": "unit 2",
                                    "defaultValue": true
                                },
                                {
                                    "name": "p3",
                                    "type": "double",
                                    "description": "This is p3",
                                    "unit": "unit 3",
                                    "defaultValue": 42.42
                                },
                                {
                                    "name": "p4",
                                    "type": "QString",
                                    "description": "This is p4",
                                    "unit": "unit 4",
                                    "defaultValue": "\"Default value\""
                                },
                                {
                                    "name": "p5",
                                    "type": "QDate",
                                    "description": "This is p5",
                                    "unit": "unit 5",
                                    "defaultValue": "QDate(1952,3,11)"
                                },
                                {
                                    "name": "p6",
                                    "type": "QColor",
                                    "description": "This is p6",
                                    "unit": "unit 6",
                                    "defaultValue": "QColor(\"gold\")"
                                },
                                {
                                    "name": "p7",
                                    "type": "QPoint",
                                    "description": "This is p7",
                                    "unit": "unit 7",
                                    "defaultValue": "QPoint(42,84)"
                                },
                                {
                                    "name": "p8",
                                    "type": "QPointF",
                                    "description": "This is p8",
                                    "unit": "unit 8",
                                    "defaultValue": "QPointF(42.42,84.84)"
                                },
                                {
                                    "name": "p9",
                                    "type": "QVector3D",
                                    "description": "This is p9",
                                    "unit": "unit 9",
                                    "defaultValue": "QVariant().value<QVector3D>()"
                                },
                                {
                                    "name": "p11",
                                    "type": "QTime",
                                    "description": "This is p11",
                                    "unit": "unit 11",
                                    "defaultValue": "QTime(23,58)"
                                }
                    ]
                
                },
                {
                    "name": "Test Action 2",
                    "description": "Test a second action, with no tag, no component, and with just one non editable parameters but that depends on TestLib. It also have public and private members.",
                    "componentClass": "",
                    "classification": {              
                    "family": "Complete Test Actions #1"
                    },
                    "implementationIncludes": "#include <TestLib.h>",
                    "classMembers": "public:\nvoid publicTest();\nprivate:\nbool called;",
                    "gui": "Custom GUI",
                    "parameters": [
                        {
                            "name": "No Tag Action",
                            "type": "bool",
                            "description": "A <b>small</b> description with <i>hyper text<i>",
                            "unit": "€",
                            "defaultValue": false,
                            "readOnly": true
                        }
                    ]
                },
                {
                    "name": "Test Action 3",
                    "description": "Test a third action, with 'Mesh Component', and with lots of parameters and default editable.",
                    "componentClass": "MeshComponent",
                    "classification": {              
                    "family": "Complete Test Actions #1",
                    "tags": [ "Mesh Component" ]
                    },
                    "implementationIncludes": "#include <QDate>\n#include<QVector3D>\n#include<QTime>",
                    "parameters": [
                        {
                            "name": "p1",
                            "type": "int",
                            "description": "This is p1",
                            "unit": "unit 1",
                            "defaultValue": 42
                        },
                        {
                            "name": "p2",
                            "type": "bool",
                            "description": "This is p2",
                            "unit": "unit 2",
                            "defaultValue": true
                        },
                        {
                            "name": "p3",
                            "type": "double",
                            "description": "This is p3",
                            "unit": "unit 3",
                            "defaultValue": 42.42
                        },
                        {
                            "name": "p4",
                            "type": "QString",
                            "description": "This is p4",
                            "unit": "unit 4",
                            "defaultValue": "\"Default value\""
                        },
                        {
                            "name": "p5",
                            "type": "QDate",
                            "description": "This is p5",
                            "unit": "unit 5",
                            "defaultValue": "QDate(1952,3,11)"
                        },
                        {
                            "name": "p6",
                            "type": "QColor",
                            "description": "This is p6",
                            "unit": "unit 6",
                            "defaultValue": "QColor(\"gold\")"
                        },
                        {
                            "name": "p7",
                            "type": "QPoint",
                            "description": "This is p7",
                            "unit": "unit 7",
                            "defaultValue": "QPoint(42,84)"
                        },
                        {
                            "name": "p8",
                            "type": "QPointF",
                            "description": "This is p8",
                            "unit": "unit 8",
                            "defaultValue": "QPointF(42.42,84.84)"
                        },
                        {
                            "name": "p9",
                            "type": "QVector3D",
                            "description": "This is p9",
                            "unit": "unit 9",
                            "defaultValue": "QVariant().value<QVector3D>()"
                        },
                        {
                            "name": "p11",
                            "type": "QTime",
                            "description": "This is p11",
                            "unit": "unit 11",
                            "defaultValue": "QTime(23,58)",
                            "readOnly": true
                        }
                    ]
                }
            ]
        },
        "timestamp": "2024-04-28T16:26:59",
        "version": "camitk-6.0"
    }
}
EOF

cat <<EOF > actions/test2/test2.camitk
{
    "camitk": {
        "extensions": {
            "contact": {
            "author": "camitk-team",
            "email": "timc-camitk@univ-grenoble-alpes.fr"
            },
            "name": "Test Action Extension 2",
            "description": "Test the second action extension.",
            "generationType": "Standard",
            "license": "/*****************************************************************************\n*\n * CamiTK - Computer Assisted Medical Intervention ToolKit\n * (c) 2001-2024 camitk-team <timc-camitk@univ-grenoble-alpes.fr>\n *\n * Visit http://camitk.imag.fr for more information\n *\n * This file is part of CamiTK.\n *\n * completetest1 is under the following licence:\n * This is the complete licence, it covers everything, everywhere,\n * for everyone at everytime.\n *\n * This is just an example of a user-defined licence...\n *\n****************************************************************************/",
            "extensionDependencies": "NEEDS_ITK\nNEEDS_CEP_LIBRARIES testlib",
            "actions": [
                {
                "name": "Test Action 4",
                "description": "Test an other action, in another extension",
                "componentClass": "ImageComponent",
                "gui": "No GUI",
                "classification": {              
                    "family": "Complete Test Actions #2",
                    "tags": [ 
                    "Test", 
                    "Action #4",
                    "ImageComponent"
                    ]
                },
                "implementationIncludes": "",
                "parameters": [
                    {
                        "name": "message",
                        "type": "QString",
                        "description": "This is a message parameter",
                        "unit": "",
                        "defaultValue": "\"hello!\""
                    }
                ]
                
                }
            ]
        },
        "timestamp": "2024-04-28T16:26:59",
        "version": "camitk-6.0"
    }
}
EOF

cat <<EOF > actions/test3/test3.camitk
{
    "camitk": {
        "extensions": {
            "actions": [
                {
                    "classMembers": "void setIncrement(int increment);\nint increment;\n",
                    "classification": {
                        "family": "Extension Generator Test",
                        "tags": [
                            "Image",
                            "ITK"
                        ]
                    },
                    "componentClass": "",
                    "description": "Example of simple ITK action on image component.",
                    "implementationIncludes": "#include <QDate>\n#include <QRegularExpression>",
                    "itkFilters": true,
                    "name": "Parameter Test",
                    "parameters": [
                        {
                            "defaultValue": -1,
                            "description": "alpha: int, no limit, default -1, in group 'Numeric Properties')",
                            "group": "Numeric Properties",
                            "maximum": 2147483647,
                            "minimum": -2147483648,
                            "name": "alpha",
                            "readOnly": false,
                            "singleStep": 1,
                            "type": "int",
                            "unit": ""
                        },
                        {
                            "defaultValue": true,
                            "description": "beta: bool, true, read only",
                            "group": "",
                            "name": "beta",
                            "readOnly": true,
                            "type": "bool",
                            "unit": ""
                        },
                        {
                            "defaultValue": "\"loweronlyregexp\"",
                            "description": "A QString constrained to lowercase characters only with RegExp (no separators, numbers...)",
                            "group": "",
                            "name": "constrained string",
                            "readOnly": false,
                            "regExp": "[a-z]*",
                            "type": "QString",
                            "unit": ""
                        },
                        {
                            "decimals": 6,
                            "defaultValue": 3.141592,
                            "description": "delta, double, 3.14, 5 decimals, value constained in -PI/+PI by step of PI/20",
                            "group": "Numeric Properties",
                            "maximum": 3.141592,
                            "minimum": -3.141592,
                            "name": "delta",
                            "readOnly": false,
                            "singleStep": 0.314159,
                            "type": "double",
                            "unit": "Radians"
                        },
                        {
                            "defaultValue": false,
                            "description": "theta, bool, false",
                            "group": "",
                            "name": "theta",
                            "readOnly": false,
                            "type": "bool",
                            "unit": ""
                        },
                        {
                            "defaultValue": 0,
                            "description": "Specific enum, 3 possible values : ACE, KING and QUEEN",
                            "enumValues": [
                                "ACE",
                                "KING",
                                "QUEEN"
                            ],
                            "group": "",
                            "name": "Specific Enum",
                            "readOnly": false,
                            "type": "enum",
                            "unit": ""
                        },
                        {
                            "defaultValue": "\"ABC\"",
                            "description": "MyString a QString \"ABC\" limited to 3 upper case letter by RegExp [A-Z]{3}",
                            "group": "",
                            "maximum": 0,
                            "minimum": 0,
                            "name": "MyString",
                            "readOnly": false,
                            "regExp": "[A-Z]{3}",
                            "singleStep": 1,
                            "type": "QString",
                            "unit": ""
                        },
                        {
                            "decimals": 2,
                            "defaultValue": 10,
                            "description": "Grade, int, 10, [0..20], by step of 5",
                            "group": "",
                            "maximum": 20,
                            "minimum": 0,
                            "name": "Grade",
                            "readOnly": false,
                            "singleStep": 5,
                            "type": "int",
                            "unit": ""
                        },
                        {
                            "decimals": 2,
                            "defaultValue": 0,
                            "description": "gamma, double, 0.0, no limit",
                            "group": "Numeric Properties",
                            "maximum": 2147483647,
                            "minimum": -2147483648,
                            "name": "Gamma",
                            "readOnly": false,
                            "singleStep": 1,
                            "type": "double",
                            "unit": ""
                        }
                    ],
                    "userIncludesInImplementation": "#include <iostream>\n#include <QString>"
                }
            ],
            "contact": {
                "author": "Emmanuel Promayon",
                "email": "Emmanuel.Promayon@univ-grenoble-alpes.fr"
            },
            "description": "This extension has 4 example of actions.",
            "extensionDependencies": "NEEDS_ITK\n",
            "license": "LGPL",
            "name": "Action extension example"
        },
        "timestamp": "2024-05-17T16:27:05",
        "version": "camitk-6.0"
    }
}
EOF

echo "Extracting Test library C++ source code files..."

cat <<EOF > libraries/testlib/TestLib.h
#ifndef TESTLIB_H
#define TESTLIB_H

#if defined(_WIN32)
#    if defined(COMPILE_TESTLIB_EXPORT)
#               define TESTLIB_EXPORT __declspec(dllexport)
#    else
#               define TESTLIB_EXPORT __declspec(dllimport)
#    endif
#else
#define TESTLIB_EXPORT
#endif

// A simple test library
class TESTLIB_EXPORT TestLib {

public:
    static void test();
};

#endif // TESTLIB_H
EOF

cat <<EOF > libraries/testlib/TestLib.cpp
#include "TestLib.h"

#include <iostream>

// --------------- test -------------------
void TestLib::test() {
    std::cout << "Test output" << std::endl;
}
EOF

echo "Generating initial extension source code..."

$1 --file actions/test1/test1.camitk --directory actions/test1
$1 --file actions/test2/test2.camitk --directory actions/test2
$1 --file actions/test3/test3.camitk --directory actions/test3

echo "Adding additional source code to user class TestAction2..."
cat <<EOF >> actions/test1/actions/TestAction2.cpp 


// -------------------- publicTest --------------------
void TestAction2::publicTest() {
    // use the (private) member declared in classMembers (.camitk)
    called = false;
    // call the CEP internal library
    TestLib::test(); 

    called = true;
}

EOF

echo "[OK] Complete CEP generated"
}