#include "shards_config.h"

#include <util/string/vector.h>

namespace NRTYServer {

TString TShardsConfig::ToString() const {
    TVector<TString> res;
    i64 p = -5;
    i64 b = 0;
    for(TLocalShards::const_iterator i = LocalShards.begin(); i != LocalShards.end(); ++i) {
        if (*i - p != 1) {
            if (p >= 0)
                res.push_back(::ToString(b) + ((p == b) ? TString() : ("-" + ::ToString(p))));
            b = *i;
        }
        p = *i;
    }
    if (p >= 0)
        res.push_back(::ToString(b) + ((p == b) ? TString() : ("-" + ::ToString(p))));
    return ::ToString(Number) + "(" + JoinStrings(res, ",") + ")";
}

void TShardsConfig::Init(const char* shards) {
    LocalShards.clear();
    const TStringBuf shardsNumber(shards);
    const size_t beg = shardsNumber.find('(');
    if (beg != TString::npos) {
        Number = FromString<size_t>(shardsNumber.substr(0, beg));
        const size_t end = shardsNumber.find(')', beg);
        if (end == TString::npos)
            ythrow yexception() << "Invalid shards config";
        const TVector<TString> chanks = SplitString(TString(shardsNumber.data() + beg + 1, end - beg - 1), ",");
        for(TVector<TString>::const_iterator i = chanks.begin(); i != chanks.end(); ++i)
            AddChunk(Strip(*i));
    } else {
        Number = FromString<size_t>(shardsNumber);
        AddChunk("0-" + ::ToString(Number - 1));
    }

}

void TShardsConfig::Init(const TYandexConfig::Directives& directives) {
    TYandexConfig::Directives::const_iterator iShardsNumber = directives.find("ShardsNumber");
    LocalShards.clear();
    if ((iShardsNumber == directives.end()) || (iShardsNumber->second == nullptr)) {
        LocalShards.insert(0);
        Number = 1;
    } else {
        Init(iShardsNumber->second);
    }
}

void TShardsConfig::AddChunk(const TString& value) {
    const TVector<TString> parts = StringSplitter(value).SplitBySet("-: ").SkipEmpty();
    size_t b,e;
    switch (parts.size()) {
        case 1:
            b = FromString<size_t>(parts[0]);
            e = b;
            break;
        case 2:
            b = FromString<size_t>(parts[0]);
            e = FromString<size_t>(parts[1]);
            break;
        default:
            ythrow yexception() << "Invalid shard chunk config: " << value;
    }
    if (b > e)
        ythrow yexception() << "Invalid shard chunk config: " << value;
    if (e >= Number)
        ythrow yexception() << "Local shard number is bigger than ShardsNumber: " << value;
    for(size_t i = b; i <= e; ++i)
        LocalShards.insert(i);
}

}
