/*
 * (C) Copyright 1996- ECMWF.
 *
 * This software is licensed under the terms of the Apache Licence Version 2.0
 * which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
 * In applying this licence, ECMWF does not waive the privileges and immunities
 * granted to it by virtue of its status as an intergovernmental organisation nor
 * does it submit to any jurisdiction.
 */

#include "UriStore.h"

#include <iomanip>

#include "eckit/exception/Exceptions.h"
#include "eckit/serialisation/Stream.h"

namespace fdb5 {


//----------------------------------------------------------------------------------------------------------------------


UriStore::UriStore(const eckit::PathName &directory) :
    next_(0),
    readOnly_(false),
    directory_(directory) {
}

UriStore::~UriStore() {
}


UriStore::UriStore(const eckit::PathName &directory, eckit::Stream &s):
    next_(0),
    readOnly_(true),
    directory_(directory) {
    size_t n;

    s >> n;
    for (size_t i = 0; i < n ; i++) {
        UriStore::UriID id;
        std::string p;

        s >> id;
        s >> p;
        eckit::URI uri(p);

        if ((uri.scheme() == "unix") || (uri.scheme() == "file")) {
            eckit::PathName path = uri.path();
            std::string q = path.asString();

            if (!q.empty() && q[0] != '/')
                path = directory_ / path;
            uri = eckit::URI("file", path);
        }

        paths_[id] = uri;
        ids_[uri] = id;

        next_ = std::max(id + 1, next_);
    }

}


void UriStore::encode(eckit::Stream &s) const {
    s << paths_.size();
    for ( URIStore::const_iterator i = paths_.begin(); i != paths_.end(); ++i ) {
        s << i->first;
        const eckit::URI &uri = i->second;
        if (uri.scheme() == "file") {
            const eckit::PathName &path = uri.path();
            s << ( (path.dirName() == directory_) ?  path.baseName() : path );
        } else {
            s << uri.asRawString();
        }
    }
}


UriStore::UriID UriStore::insert( const eckit::URI &path ) {
    ASSERT(!readOnly_);

    IdStore::iterator itr = ids_.find(path);
    if ( itr != ids_.end() )
        return itr->second;

    UriStore::UriID current = next_;
    next_++;
    ids_[path] = current;
    paths_[current] = path;

    return current;
}

eckit::URI UriStore::get(const UriStore::UriID id) const {
    URIStore::const_iterator itr = paths_.find(id);
    ASSERT( itr != paths_.end() );
    return itr->second;
}

std::vector<eckit::URI> UriStore::paths() const {
    std::vector<eckit::URI> p;

    p.reserve(paths_.size());

    for (const auto& kv : paths_) {
        p.emplace_back(kv.second);
    }

    return p;
}

void UriStore::print( std::ostream &out ) const {
    for ( URIStore::const_iterator itr = paths_.begin(); itr != paths_.end(); ++itr ) {
        out << itr->first << " " << itr->second << std::endl;
    }
}

void UriStore::dump(std::ostream &out, const char* indent) const {
    out << indent << "Files:" << std::endl;
    for ( URIStore::const_iterator itr = paths_.begin(); itr != paths_.end(); ++itr ) {
        out << indent << indent << std::setw(3) << itr->first << " => " << itr->second << std::endl;
    }
}

//----------------------------------------------------------------------------------------------------------------------


} // namespace fdb5
