/*
 * Copyright (C) 2015 by Multi-Tech Systems
 *
 * This file is part of libmts.
 *
 * libmts 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 of the License, or
 * (at your option) any later version.
 *
 * libmts 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 libmts.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

/*! \file   MTS_Text.h
 \brief  A set of string formatting utilities
 \date   15JUN11
 \author Sean Godinez

 A set of string formatting utilities
 */

#ifndef MTS_TEXT_H_
#define MTS_TEXT_H_

#include <mts/MTS_NonConstructable.h>
#include <mts/MTS_Stdint.h>
#include <mts/MTS_Buffer.h>
#include <sstream>
#include <string>
#include <vector>
#include <time.h>

namespace MTS {

    class Text: private NonConstructable {

        public:

            enum DATEFORMAT {
                MMsDDsYY,           //MM/DD/YYYY
                MMsDDsYY_HHcMMcSS,  //MM/DD/YYYY HH:MM:SS:mmm
                RFC_1123            //Wdy, DD Mon YYYY HH:MM:SS GMT (Thu, 01 Jan 1970 00:00:01 GMT)
            };

            enum TIMEFORMAT {
                HHcMMcSScmmm,       //HH:MM:SS:mmm
                HHcMMcSS            //HH:MM:SS
            };

            static const uint8_t RDSTATE_SUCCESS_MASK = 0x02;   //Only OEF bit

            static std::string time(const uint64_t& iTimeMicros, const TIMEFORMAT& eTime = HHcMMcSScmmm);
            static std::string date(const tm& stTime, const DATEFORMAT& eDate = MMsDDsYY);
            static bool datetimeIsBefore(const std::string& time1, const std::string& time2);

            static std::vector<std::string> split(const std::string& str, char delimiter, int limit = 0);
            static std::vector<std::string> split(const std::string& str, const std::string& delimiter, int limit = 0);
            static std::string join(std::vector<std::string> list, char delimiter);
            static std::string replace(const std::string& str, const std::string& from, const std::string& to);
            static uint32_t count(const std::string& str, const std::string& element);
            static uint32_t count(const std::string& str, const uint8_t& element);
            static bool endsWith(const std::string& str, const std::string& key);

            static std::string getLine(const std::string& source, const size_t& start, size_t& cursor);

            static std::string trim(const std::string& str);
            static std::string trim(const std::string& str, const uint8_t& element);
            static std::string strip(const std::string& str, const std::vector<uint8_t>& elements);
            static std::string strip(const std::string& str, const uint8_t& element);

            static std::string toLowerCase(const std::string& str);
            static std::string toUpperCase(const std::string& str);
            static std::string toCapitalized(const std::string& str);
            static std::string toCamelCase(const std::string& str);
            static std::string toCommandLineEscaped(const std::string& str);

            static std::wstring widen(const std::string& str);
            static std::string narrow(const std::wstring& str);

            static std::string format(bool value);
            static std::string format(double value, std::streamsize percision = 6);

            static std::string format(int8_t value);
            static std::string format(int16_t value);
            static std::string format(int32_t value);
            static std::string format(int64_t value);

            static std::string format(uint8_t value);
            static std::string format(uint16_t value);
            static std::string format(uint32_t value);
            static std::string format(uint64_t value);

            static std::string formatHex(int8_t value, bool pad = false);
            static std::string formatHex(int16_t value, bool pad = false);
            static std::string formatHex(int32_t value, bool pad = false);
            static std::string formatHex(int64_t value, bool pad = false);

            static std::string formatHex(uint8_t value, bool pad = false);
            static std::string formatHex(uint16_t value, bool pad = false);
            static std::string formatHex(uint32_t value, bool pad = false);
            static std::string formatHex(uint64_t value, bool pad = false);

            static std::string formatHex(const Buffer& value);

            static bool parse(bool& value, const std::string& str);
            static bool parse(double& value, const std::string& str);

            static bool parse(int8_t& value, const std::string& str);
            static bool parse(int16_t& value, const std::string& str);
            static bool parse(int32_t& value, const std::string& str);
            static bool parse(int64_t& value, const std::string& str);

            static bool parse(uint8_t& value, const std::string& str);
            static bool parse(uint16_t& value, const std::string& str);
            static bool parse(uint32_t& value, const std::string& str);
            static bool parse(uint64_t& value, const std::string& str);

            static bool parseHex(uint8_t& value, const std::string& str);
            static bool parseHex(uint16_t& value, const std::string& str);
            static bool parseHex(uint32_t& value, const std::string& str);
            static bool parseHex(uint64_t& value, const std::string& str);

            template<typename S, typename T>
            static bool lexicalCast(S source, T& target) {
                std::stringstream interpreter;
                if(!(interpreter << source) ||
                   !(interpreter >> target) ||
                   !(interpreter >> std::ws).eof()) {
                   return false;
                }
                return true;
            }

            static std::string getFileExtension(const std::string& filename);
    };
}

#endif