// KEKS -- C99 KEKS encoder implementation
// Copyright (C) 2024-2025 Sergey Matveev <stargrave@stargrave.org>
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as
// published by the Free Software Foundation, version 3 of the License.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this program.  If not, see <http://www.gnu.org/licenses/>.

#include <assert.h>
#include <stdint.h>
#include <time.h>

#include "enctai.h"
#include "leapsecs.h"
#include "tobe.h"

bool
KEKSTimespecToTAI64(unsigned char *buf, const struct timespec *ts)
{
    assert(ts != NULL);
    int64_t v = (int64_t)(ts->tv_sec);
    uint64_t val = (uint64_t)v + 0x4000000000000000;
    if (val <= (uint64_t)v) {
        return false;
    }
    assert(buf != NULL);
    keksToBE(buf, 8, val);
    if (ts->tv_nsec != 0) {
        if (ts->tv_nsec >= 1000000000) {
            return false;
        }
        keksToBE(buf + 8, 4, (uint64_t)(ts->tv_nsec));
    }
    return true;
}

bool
KEKSTimespecToTAI(struct timespec *ts)
{
    assert(ts != NULL);
    if (ts->tv_sec < 0) {
        return false;
    }
    uint64_t v = 10 + (uint64_t)(ts->tv_sec);
    for (size_t i = 0; i < KEKSLeapsecsN; i++) {
        if (v >= KEKSLeapsecs[i]) {
            v++;
        }
    }
    if ((v < (uint64_t)(ts->tv_sec)) ||
        (((uint64_t)1 << ((sizeof(time_t) * 8) - 1)) < v)) {
        return false;
    }
    ts->tv_sec = (time_t)v;
    return true;
}
