#ifndef _TILE_BASE_NET_URI_H
#define _TILE_BASE_NET_URI_H

#pragma once

#include "tile/base/logging.h"
#include "tile/base/optional.h"
#include "tile/base/slice.h"

#include <array>

namespace tile {
template<typename T, typename>
struct TryParseTraits;

class Uri {
public:
    Uri() = default;

    explicit Uri(Slice from);

    Slice scheme() const noexcept { return GetComponent(kScheme); };

    Slice userinfo() const noexcept { return GetComponent(kUserInfo); };

    Slice host() const noexcept { return GetComponent(kHost); };

    Slice port() const noexcept { return GetComponent(kPort); };

    Slice path() const noexcept { return GetComponent(kPath); };

    Slice query() const noexcept { return GetComponent(kQuery); };

    Slice fragment() const noexcept { return GetComponent(kFragment); }

    std::string ToString() const { return uri_; }

private:
    enum Component {
        kScheme         = 0,
        kUserInfo       = 1,
        kHost           = 2,
        kPort           = 3,
        kPath           = 4,
        kQuery          = 5,
        kFragment       = 6,
        kComponentCount = 7,
    };

    using ComponentView = std::pair<std::uint16_t, std::uint16_t>;
    using Components    = std::array<ComponentView, kComponentCount>;

    Slice GetComponent(Component component) const noexcept;

private:
    std::string uri_;
    Components comps_;
    std::uint16_t port_;
};

template<>
struct TryParseTraits<Uri, void> {
    tile::optional<Uri> TryParse(Slice s);
};

}// namespace tile

#endif// _TILE_BASE_NET_URI_H
