/***************************************************************************
*                                                                          *
*  Copyright (C) Golaem S.A.  All Rights Reserved.                         *
*                                                                          *
***************************************************************************/

#pragma once

#include "glmCoreAPI.h"

#include "glmString.h"
#include <sstream>
#include <iomanip>
#include "glmArray.h"

namespace glm
{
    extern int alphaNumericCopiesBufferIndex;

    glm::GlmString GLM_CORE_API operator+(const glm::GlmString& str, float value);
    glm::GlmString GLM_CORE_API operator+(const glm::GlmString& str, double value);
    glm::GlmString GLM_CORE_API operator+(const glm::GlmString& str, int value);
    glm::GlmString GLM_CORE_API operator+(const glm::GlmString& str, unsigned int value);

    /** 
    * \brief Fonction permettant de transformer en chaine de caractères toute opérande ayant défini un operateur << d'insertion dans un ostream
    *
    * \ingroup utils
    * \author Golaem <dev@golaem.com>
    */
    template <class T>
    inline glm::GlmString toString(const T& value)
    {
        std::stringstream stream;
        stream << std::dec << std::setprecision(32) << value;
        return stream.str().c_str();
    }

    template <class T>
    inline bool fromString(const glm::GlmString& string, T& value)
    {
        std::stringstream stream;
        stream << string;
        return !(stream >> value).fail();
    }

	bool GLM_CORE_API startsWith(const glm::GlmString& src, const glm::GlmString& start, size_t atPos = 0);

    /** 
    * \brief Fonction testant si une chaine de caractères se termine par une chaine donnée
    *
    * \param src La chaine à tester
    * \param end	La chaine voulue en fin de src
    * \return vrai si src se termine par end
    *
    * \author Golaem <dev@golaem.com>
    */
    bool GLM_CORE_API endsWith(const glm::GlmString& src, const glm::GlmString& end);

    //------------------------------------------------------------
    //! Remplace un caractère par un autre dans la chaîne
    /*! \param str la chaîne de caractère non modifiée
	\param ci le caractère recherché
	\param cf le caractère remplacant
	\return la nouvelle chaîne de caractères
	*/
    //---------------------------------------------------------
    glm::GlmString GLM_CORE_API replaceChar(const glm::GlmString& str, const char ci, const char cf);

    /**
    * \brief Upper case a string
    * \param str The string to uppercase
    */
    glm::GlmString GLM_CORE_API replaceString(const glm::GlmString& str, const glm::GlmString& from, const glm::GlmString& to);

    /** 
    * \brief Upper case a string
    * \param str The string to uppercase
    */
    glm::GlmString GLM_CORE_API toUpper(const glm::GlmString& str);

    /** 
    * \brief Lower case a string
    * \param str The string to lowercase
    */
    glm::GlmString GLM_CORE_API toLower(const glm::GlmString& str);

    /** 
    * \brief Alphanumerize a string (replace non-alphanumeric characters by "_")
    * \param name The string reference
    */
    void GLM_CORE_API alphaNumerizeName(glm::GlmString& name);

    /** 
    * \brief Alphanumerize a string (replace non-alphanumeric characters by "_")
    * \param source The string reference
    * \param destination The destination string . Its buffer must be big enough
    */
    GLM_CORE_API bool alphaNumerizeNameWithCopy(const char* source, char* destination);

    /** 
    * \brief Alphanumerize a string (replace non-alphanumeric characters by "_") NOT THREADSAFE!
    * \param source The string reference
    * \param destination The converted string. if NULL, then source and result are the same -> use source.
    */
    GLM_CORE_API const char* alphaNumerizeNameStr(const char* source);

    /**
    * Split a string given a string delimitor
    * \param input a string to split
    * \param delim a string delimitor
    * \param result a vector containing input string parts (without delimitor, with empty parts between delimitors)
    */
    void GLM_CORE_API split(const glm::GlmString& input, const glm::GlmString& delim, glm::Array<glm::GlmString>& result);

    /**
    * Find the longuest common substring for 2 string
    * \param result the longuest common substring of inputA and inputB
    * \param str1 first string
    * \param str2 second string
    * \return the length of the longuest common substring
    */
    int GLM_CORE_API longuestCommonSubstring(glm::GlmString& result, const glm::GlmString& str1, const glm::GlmString& str2);

    /**
    * Return a dirmapped file path (if mapFrom is not found in sourcePath, it returns sourcePath)
    */
    glm::GlmString GLM_CORE_API dirmap(const glm::GlmString& sourcePath, const glm::GlmString& mapFrom, const glm::GlmString& mapTo);

    /**
     *  Replace environment variables defined with %envVar% with their value
     */
    glm::GlmString GLM_CORE_API replaceEnvVars(const glm::GlmString& sourcePath, const glm::GlmString& startStr = "%", const glm::GlmString& endStr = "%");

    //------------------------------------------------------------
    //! Return a vector of string from a tokenized string
    //------------------------------------------------------------
    extern glm::Array<glm::GlmString> GLM_CORE_API stringToStringArray(const glm::GlmString& inputString, const glm::GlmString& delim);

    //------------------------------------------------------------
    //! Return a tokenized string from a vector of string
    //------------------------------------------------------------
    glm::GlmString GLM_CORE_API stringArrayToString(const glm::Array<glm::GlmString>& input, const glm::GlmString& delim);
    glm::GlmString GLM_CORE_API doubleArrayToString(const glm::PODArray<double>& input, const glm::GlmString& delim);
    glm::GlmString GLM_CORE_API intArrayToString(const glm::PODArray<int>& input, const glm::GlmString& delim);
    glm::GlmString GLM_CORE_API int64ArrayToString(const glm::PODArray<int64_t>& input, const glm::GlmString& delim);

    //------------------------------------------------------------
    //! Convert print-pages style string to int vector ("1-3, 5-6, 9" => <1,2,3,5,6,9>)
    //! Does not support *, it should be treated separately
    //------------------------------------------------------------
    void GLM_CORE_API convertPrinterString(const glm::GlmString& inputString, glm::PODArray<unsigned int>& outVector, const glm::GlmString& extraValidString = "");

} // namespace glm
