#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# **************************************************
__author__  = "Teddy Chantrait"
__email__   = "teddy.chantrait@gmail.com"
__status__  = "Development"
__date__    = "2024-07-03 17:28:00.999352"
__version__ = "@COSTO_VERSION@"
# **************************************************
from . import utils as COUT


class clock(metaclass=COUT.SingletonMeta):
    __slots__ = (
        "_time",
        "_dt",
        "_tic_call_allowed",
        "_tac_call_allowed"
    )

    def __init__(self, *args, t0=0.,**kwds):
        self._time = float(t0)
        self._dt = 0.
        self._tic_call_allowed = True
        self._tac_call_allowed = False

    @property
    def time(self):
        """
        return the time
        """
        return self._time

    @time.setter
    def time(self, val):
        raise RuntimeError("Time can't be set, use reset or increment")

    def reset(self, t):
        """
        reset the clock to time t
        """
        self._time = float(t)
        self._tic_call_allowed = True
        self._tac_call_allowed = False
        return

    def tic(self, dt):
        """
        set the elapsed time (dt) until the call of tac method
        """
        if self._tic_call_allowed:
            self._dt = dt
            self._tac_call_allowed = True
            self._tic_call_allowed = False
            return
        else:
            raise RuntimeError("You must call tac method before this call.")

    def tac(self):
        """
        Advance the time with the dt set on tic methode
        """
        if self._tac_call_allowed:
            self._time += self._dt
            self._dt = 0.
            self._tic_call_allowed = True
            self._tac_call_allowed = False
            return
        else:
            raise RuntimeError("You must call tac method before")

    @property
    def next_time(self):
        """
        If this method is called between a tic and tac calls
        its return the next time of the clock.
        It meens the time that will be when tac will be called.
        If this method is called between a tac and tic calls
        the current time is return. We don't know yet the next time step.
        """
        if self._tac_call_allowed:
            # between tic and tac
            return self._time + self._dt
        else:
            # between tac and tic
            return self._time

    @next_time.setter
    def next_time(self, val):
        raise RuntimeError("next_time can't be set")
