/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 * 
 * utils.cpp
 *
 *      Author: pgess <v.melnychenko@xreate.org>
 */

#ifndef UTILS_H
#define UTILS_H

#include "jeayeson/jeayeson.hpp"

namespace xreate {
    
template<class Tag, class Source>
struct AddTag {

    explicit
    AddTag(const Source &src)
            : __src(src) { }

    explicit
    AddTag(Source &&src)
            : __src(std::move(src)) { }

    operator const Source&() const{
        return __src;
    }

    const Source& get() const{
        return __src;
    }

    const Source*
    operator->() const {
            return &__src;
    }

private:
    Source __src;
};

struct Expand_t{};
template<class Source>
using Expanded = AddTag<Expand_t, Source>;

//DEBT move to resources compiler. https://github.com/markusfisch/cpprc
class Config {
private: 
  json_map __storage;
  static Config __self;
  Config();

public: 
   static std::string get(std::string key) {
    return __self.__storage.get_for_path<json_value>(key).get<std::string>();
  }
};

/** \brief Decorators support */
template<class DecoratorTag>
struct DecoratorsDict{
    //typedef ConcreteDecoratorForTag result;
};

template<class DecoratorTag>
struct Decorators{
    typedef typename DecoratorsDict<DecoratorTag>::result Instance;

    template<class Base>
    static Instance* getInterface(Base* obj){
        return dynamic_cast< Instance* > (obj);
    }
};

template<class Target>
struct ManagedPtr {
    static ManagedPtr<Target> Invalid() {
        return ManagedPtr<Target>();
    }

    ManagedPtr() : __storage(0) {
    }

    ManagedPtr(unsigned int id, const std::vector<Target*>* storage)
    : __id(id), __storage(storage) {
    }

    Target&
    operator*() const {
        assert(isValid() && "Invalid Ptr");
        return *__storage->at(__id);
    }

    void operator=(const ManagedPtr<Target>& other) {
        __id = other.__id;
        __storage = other.__storage;
    }

    bool
    operator==(const ManagedPtr<Target>& other) {
        return isValid() && (__id == other.__id);
    }

    Target*
    operator->() const noexcept {
        assert(isValid() && "Invalid Ptr");
        return __storage->at(__id);
    }

    inline bool isValid() const {
        return (__storage) && (0 <= __id) && (__id < __storage->size());
    }

    inline operator bool() const {
        return isValid();
    }

    ManagedPtr<Target>& operator++() {
        ++__id;
        return *this;
    }

    inline unsigned int id() const {
        return __id;
    }

private:
    unsigned int __id = 0;
    const std::vector<Target*> * __storage = 0;
};

}

std::wstring
utf8_to_wstring(const std::string& str);

std::string
wstring_to_utf8(const std::wstring& str);


#define RST  "\x1B[0m"
#define KRED  "\x1B[31m"
#define KGRN  "\x1B[32m"
#define KYEL  "\x1B[33m"
#define KBLU  "\x1B[34m"
#define KMAG  "\x1B[35m"
#define KCYN  "\x1B[36m"
#define KWHT  "\x1B[37m"

#define FRED(x) KRED << x << RST
#define FGRN(x) KGRN <<x << RST
#define FYEL(x) KYEL << x << RST
#define FBLU(x) KBLU << x << RST
#define FMAG(x) KMAG x RST
#define FCYN(x) KCYN x RST
#define FWHT(x) KWHT x RST

#define BOLD(x) "\x1B[1m" x RST
#define UNDL(x) "\x1B[4m" x RST

#endif // UTILS_H
