/*****************************************************************************
 * $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$
 ****************************************************************************/

#ifndef CAMITKCORE_H
#define CAMITKCORE_H



// -- Core stuff
#include "CamiTKAPI.h"
#include "HistoryItem.h"

// -- Qt stuff
#include <QStack>



namespace camitk {
/**
 * @ingroup group_sdk_libraries_core
 *
 * @brief
 * Core class specifies the basic static information for the CamiTK API.
 *
 * Extensions can only be in three different places:
 * - CAMITK_DIR (where the libcamitkcore is)
 * - user config directory
 * - current wording directory
 *
 * Taking into account multiarch is difficult as some compiler/OS define CMAKE_INSTALL_LIBDIR to different
 * values ("lib", "lib64" or even "lib/x86_64-linux-gnu" or more complicated paths). This value sometimes
 * depends on where CMAKE_INSTALL_PATH points to (see CMake GNUInstallDirs module). For instance on debian,
 * if CMAKE_INSTALL_PATH is equals to "/usr" then CMAKE_INSTALL_LIBDIR is set to "lib/ARCH", but if
 * CMAKE_INSTALL_PATH is anything else, it is just set to "lib".
 * The `Core::libDir()` method returns something different than "" when CamiTK core is compiled (see `CamiTKVersion.h.in`), but the
 * CamiTK repositories are required also when a CamiTK application is launched.
 *
 * The difficulty therefore arises as CamiTK has to load all type of extensions in all type of repositories
 * and this must include:
 * - extensions build during CamiTK core compilation (which lands in CMAKE_INSTALL_LIBDIR, and might be
 *   as complex as "lib/x86_64-linux-gnu", i.e., include a subdirectory)
 * - extensions build by CEP outside CamiTK Community Edition (which will most certainly/by default be "lib/")
 *
 * Note that "lib/" was the only possible value of CMAKE_INSTALL_LIBDIR before multiarch was taken into
 * account in CamiTK 5.0.
 *
 * To take into account both situations, that result in a multitude of possible directories, it was decided that:
 * - repositories should be looked for either in `Core::libDir()` or `lib/`
 * - the case when `Core::libDir()` is equal to `lib/` must be taken into account to avoid duplicates
 */
class CAMITK_API Core {
public:

    /// @name runtime directory information
    ///@{
    /** get all the component directories. It gets all the valid directories
     *  where components are installed, and insert them in this particular order:
     *  1. current working directory (build install tree)
     *  2. user config directory (user install tree)
     *  3. CamiTK SDK installation directory (global install tree)
     */
    static const QStringList getComponentDirectories();

    /** get all the action directories. It gets all the valid directories
     *  where actions are installed, and insert them in this particular order:
     *  1. current working directory (build install tree)
     *  2. user config directory (user install tree)
     *  3. CamiTK SDK installation directory (global install tree)
     */
    static const QStringList getActionDirectories();

    /** get all the viewers directories. It gets all the valid directories
     *  where viewers are installed, and insert them in this particular order:
     *  1. current working directory (build install tree)
     *  2. user config directory (user install tree)
     *  3. CamiTK SDK installation directory (global install tree)
     */
    static const QStringList getViewerDirectories();

    /** Get a valid camitk test data directory name. It returns the first valid
     *  test data directory that is found. Checking is done in this particular order:
     *  1. current working directory (build install tree)
     *  2. user config directory (user install tree)
     *  3. CamiTK SDK installation directory (global install tree)
     *
     *  If none of this three directories is valid, return user's home directory.
     *
     *  A test data directory is valid if it exists and contains a least one file.
     *
     *  @return a null QString, checkable with isNull(), if no test data directory found
     */
    static const QString getTestDataDir();

    /** get all installation directories, suffixed by the given word.
     *  All the returned Strings are unique valid directories, sorted in this particular order:
     *  1. current working directory (build install tree)
     *  2. user config directory (user install tree)
     *  3. CamiTK SDK installation directory (global install tree)
     *
     * It uses getExtensionDirectories() to take multiarch into account
     *
     * If no directory is available and exitOnError is true, the application exits.
     * There are situation (namely for checking testdata dir) where it not mandatory
     * to find a directory. In this case, exitOnError should be set to false so that
     * the application does not exit.
     */
    static const QStringList getInstallDirectories(QString suffix, bool exitOnError = true);

    /// Used by getInstallDirectories to determine the list of extension repositories
    /// This method check both `Core::libDir()` and `lib/` (if different) subdirectories in order to
    /// take multiarch into account.
    /// @param extensionType the type of extensions ("actions", "components" or "viewers")
    static const QStringList getExtensionDirectories(QString extensionType);

    /// return a list with all possible file extension for shared object/dynamic library/dll (.so, .dll...)
    static QStringList getExtensionFilter();

    /// get more information about installation, etc... as a formatted string
    static const QString getConfig();

    /// get more information about installation, etc... as a JSON string instead of the text/console version of getConfig
    static const QJsonObject getConfigAsJson();

    /// get all important paths as a formatted string
    static const QString getPaths();

    /// get all important paths as a JSON string instead of the text/console version of getPaths()
    static const QJsonObject getPathsAsJson();

    /// get the CAMITK_DIR (where camitk-config is installed)
    static const QString getGlobalInstallDir();

    /// get the user config directory (this is the local installation directory)
    static const QString getUserInstallDir();

    /// get the current working directory (during dev, this should be the build directory, which is an installation directory)
    static const QString getCurrentWorkingDir();

    /// get a well formed bug report with all necessary information
    static const QString getBugReport();

    /// get the python status
    static const QString getPythonStatus();
    ///@}

    /// @name runtime build information
    ///@{
    /// get the type of build we are running, Debug or Release
    /// @return true if running in Debug, elsewhere false for Release build.
    static const bool isDebugBuild();
    ///@}


    /// @name CamiTK Version and build information set at configure time
    ///@{
    /// complete version string
    static const char* version();
    /// short version string (all in lower case, without the patch number)
    static const char* shortVersion();
    /// version used for so name
    static const char* soVersion();
    /// debug postfix used on MSVC to distinguished between release and debug version
    static const char* debugPostfix();
    /// library folder set depending on the compiler and environment choice
    /// (it could be lib/ or lib64/ on Linux).
    ///
    /// libDir value is set directly to the value of CMAKE_INSTALL_LIBDIR.
    ///
    /// Although it can not be called a version variable
    /// per se, it is required for the extension manager to find the available extensions.
    static const char* libDir();
    ///@}

private:

    // get the list of path information keys stored in the proper display order
    static const QStringList getInformationPathKeys();
};

}

#endif // CAMITKCORE_H

