/*
 * (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 <sys/types.h>
#include <pwd.h>

#include "fdb5/fdb5_version.h"
#include "fdb5/LibFdb5.h"

#include <iomanip>

#include "TocRecord.h"

#include "eckit/memory/Zero.h"
#include "eckit/log/TimeStamp.h"
#include "eckit/log/Log.h"
#include "eckit/runtime/Main.h"

namespace fdb5 {

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

TocRecord::Header::Header(unsigned int serialisationVersion, unsigned char tag):
    tag_(tag) {

    if (tag_ != TOC_NULL) {
        eckit::zero(*this);
        tag_                  = tag;
        serialisationVersion_ = serialisationVersion;

        fdbVersion_ = ::fdb5_version_int();

        SYSCALL( ::gettimeofday( &timestamp_, 0 ) );

        pid_       = ::getpid();
        uid_       = ::getuid();

        std::string host = eckit::Main::hostname();
        host = host.substr(0, host.find(".")); // guaranteed to be less than 64 chars -- seee RFC 1035
        hostname_ = host;
    }
}

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

TocRecord::TocRecord(unsigned int serialisationVersion, unsigned char tag):
    header_(serialisationVersion, tag) {}

void TocRecord::dump(std::ostream& out, bool simple) const {

    switch (header_.tag_) {
        case TocRecord::TOC_INIT:
            out << "TOC_INIT ";
            break;

        case TocRecord::TOC_INDEX:
            out << "TOC_INDEX";
            break;

        case TocRecord::TOC_CLEAR:
            out << "TOC_CLEAR";
            break;

        case TocRecord::TOC_SUB_TOC:
            out << "TOC_SUB_TOC";
            break;

        default:
            out << "TOC_???? ";
            break;
    }

    std::ostringstream oss;
    oss << (header_.timestamp_.tv_usec / 1000000.0);

    out << " "
        << eckit::TimeStamp(header_.timestamp_.tv_sec)
        << "."
        << std::setw(6)
        << std::left
        << std::setfill('0')
        << oss.str().substr(2)
        << std::setfill(' ')
        << ", version:"
        << header_.serialisationVersion_
        << ", fdb: "
        << header_.fdbVersion_
        << ", uid: "
        << std::setw(4);

    struct passwd * p = getpwuid(header_.uid_);

    if (p) {
        out  << p->pw_name;
    } else {
        out << header_.uid_;
    }

    out << ", pid "
        << std::setw(5)
        << header_.pid_
        << ", host: "
        << header_.hostname_;

    if(!simple) { out << std::endl; }
}

void TocRecord::print(std::ostream & out) const {
    out << "TocRecord["
        << "tag=" << header_.tag_ << ","
        << "tocVersion=" << header_.serialisationVersion_ << ","
        << "fdbVersion=" << header_.fdbVersion_ << ","
        << "timestamp=" << header_.timestamp_.tv_sec << "." << header_.timestamp_.tv_usec << ","
        << "pid=" << header_.pid_ << ","
        << "uid=" << header_.uid_ << ","
        << "hostname=" << header_.hostname_ << "]";
}

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

} // namespace fdb5
