#!/usr/bin/env seiscomp-python

############################################################################
# Copyright (C) 2016 by gempa GmbH                                         #
#                                                                          #
# All Rights Reserved.                                                     #
#                                                                          #
# NOTICE: All information contained herein is, and remains                 #
# the property of gempa GmbH and its suppliers, if any. The intellectual   #
# and technical concepts contained herein are proprietary to gempa GmbH    #
# and its suppliers.                                                       #
# Dissemination of this information or reproduction of this material       #
# is strictly forbidden unless prior written permission is obtained        #
# from gempa GmbH.                                                         #
#                                                                          #
#  Author: Enrico Ellguth, Dirk Roessler                                   #
#  Email: enrico.ellguth@gempa.de, roessler@gempa.de                       #
############################################################################

import os
import sys
import time
import seiscomp.client
import seiscomp.core
import seiscomp.io
import seiscomp.datamodel


def timing_pickTime(obj):
    """
    Sort picks, origins by their time values
    Sort amplitudes by their reference time
    """

    po = seiscomp.datamodel.Pick.Cast(obj[0])
    oo = seiscomp.datamodel.Origin.Cast(obj[0])
    if po or oo:
        t = obj[0].time().value()
    else:
        t = obj[0].timeWindow().reference()

    return t


def timing_creationTime(obj):
    """
    Sort all objects by their creation time
    """

    ct = obj[0].creationInfo().creationTime()
    return ct


def listPicks(self, objects):
    print(
        "\n#phase, time                   , streamID       , author, to previous pick "
        "[s], delay [s]",
        file=sys.stdout,
    )

    t0 = None
    for obj, _ in objects:
        p = seiscomp.datamodel.Pick.Cast(obj)
        if not p:
            continue

        time = p.time().value()
        try:
            phase = p.phaseHint().code()
        except ValueError:
            phase = "None"
        wfID = p.waveformID()
        net = wfID.networkCode()
        sta = wfID.stationCode()
        loc = wfID.locationCode()
        cha = wfID.channelCode()
        try:
            author = p.creationInfo().author()
        except ValueError:
            author = "None"
        try:
            delay = f"{(p.creationInfo().creationTime() - time).toDouble():.3f}"
        except ValueError:
            delay = "None"

        if t0 is not None:
            deltaT = f"{(time - t0).toDouble():.3f}"
        else:
            deltaT = "None"

        streamID = f"{net}.{sta}.{loc}.{cha}"
        print(
            f"{phase: <6}, {time.toString('%FT%T')}.{int(time.microseconds()/1000):03d}"
            f", {streamID: <15}, {author}, {deltaT}, {delay}",
            file=sys.stdout,
        )

        t0 = time
    return True


def printStatistics(ep):
    minPickTime = None
    maxPickTime = None
    minPickCTime = None
    maxPickCTime = None
    minAmplitudeTime = None
    maxAmplitudeTime = None
    minOriginTime = None
    maxOriginTime = None
    minOriginCTime = None
    maxOriginCTime = None

    # read picks
    nslc = set()
    authorPick = set()
    authorAmplitude = set()
    authorOrigin = set()
    detectionStreams = set()
    cntPick = ep.pickCount()
    for i in range(cntPick):
        pick = ep.pick(i)

        try:
            authorPick.add(pick.creationInfo().author())
        except ValueError:
            print(
                f"Author information not found in pick {pick.publicID()}: NSLC list may"
                " be incomplete",
                file=sys.stderr,
            )

        try:
            net = pick.waveformID().networkCode()
            sta = pick.waveformID().stationCode()
            loc = pick.waveformID().locationCode()
            cha = pick.waveformID().channelCode()
            nslc.add(f"{net}.{sta}.{loc}.{cha}")
            detectionStreams.add(f".{loc}.{cha}")
        except ValueError:
            print(
                f"Stream information not found in pick {pick.publicID()}: NSLC list "
                "may be incomplete",
                file=sys.stderr,
            )

        if not minPickTime:
            minPickTime = pick.time().value()
        elif pick.time().value() < minPickTime:
            minPickTime = pick.time().value()

        if not maxPickTime:
            maxPickTime = pick.time().value()
        elif pick.time().value() > maxPickTime:
            maxPickTime = pick.time().value()

        try:
            pick.creationInfo().creationTime()
        except ValueError:
            print(
                f"Creation time not found in pick {pick.publicID()}: Statistics may "
                "be incomplete",
                file=sys.stderr,
            )
            continue

        if not minPickCTime:
            minPickCTime = pick.creationInfo().creationTime()
        elif pick.creationInfo().creationTime() < minPickCTime:
            minPickCTime = pick.creationInfo().creationTime()

        if not maxPickCTime:
            maxPickCTime = pick.creationInfo().creationTime()
        elif pick.creationInfo().creationTime() > maxPickCTime:
            maxPickCTime = pick.creationInfo().creationTime()

    # read amplitudes
    cntAmp = ep.amplitudeCount()
    for i in range(cntAmp):
        amp = ep.amplitude(i)
        try:
            authorAmplitude.add(amp.creationInfo().author())
        except ValueError:
            print(
                f"Author information not found in amplitude {amp.publicID()}: NSLC "
                "list may be incomplete",
                file=sys.stderr,
            )
        try:
            net = amp.waveformID().networkCode()
            sta = amp.waveformID().stationCode()
            loc = amp.waveformID().locationCode()
            cha = amp.waveformID().channelCode()
            nslc.add(f"{net}.{sta}.{loc}.{cha}")
            detectionStreams.add(f".{loc}.{cha}")
        except ValueError:
            print(
                f"Stream information not found in amplitude {amp.publicID()}: NSLC "
                "list may be incomplete",
                file=sys.stderr,
            )

        if not minAmplitudeTime:
            minAmplitudeTime = amp.timeWindow().reference()
        elif amp.timeWindow().reference() < minAmplitudeTime:
            minAmplitudeTime = amp.timeWindow().reference()

        if not maxAmplitudeTime:
            maxAmplitudeTime = amp.timeWindow().reference()
        elif amp.timeWindow().reference() > maxAmplitudeTime:
            maxAmplitudeTime = amp.timeWindow().reference()

    # read origins
    cntOrg = ep.originCount()
    for i in range(cntOrg):
        oo = ep.origin(i)

        try:
            authorOrigin.add(oo.creationInfo().author())
        except ValueError:
            print(
                f"Author information not found in origin {oo.publicID()}:",
                file=sys.stderr,
            )

        if not minOriginTime:
            minOriginTime = oo.time().value()
        elif oo.time().value() < minOriginTime:
            minOriginTime = oo.time().value()

        if not maxOriginTime:
            maxOriginTime = oo.time().value()
        elif oo.time().value() > maxOriginTime:
            maxOriginTime = oo.time().value()

        try:
            oo.creationInfo().creationTime()
        except ValueError:
            print(
                f"Creation time not found in oo {oo.publicID()}: Statistics may "
                "be incomplete",
                file=sys.stderr,
            )
            continue

        if not minOriginCTime:
            minOriginCTime = oo.creationInfo().creationTime()
        elif oo.creationInfo().creationTime() < minOriginCTime:
            minOriginCTime = oo.creationInfo().creationTime()

        if not maxOriginCTime:
            maxOriginCTime = oo.creationInfo().creationTime()
        elif oo.creationInfo().creationTime() > maxOriginCTime:
            maxOriginCTime = oo.creationInfo().creationTime()

    print(
        f"""
Picks
  + number:            {cntPick}
  + first pick:        {minPickTime}
  + last pick:         {maxPickTime}""",
        file=sys.stdout,
    )
    if cntPick > 0:
        print(
            f"""    + interval:        {(maxPickTime - minPickTime).toDouble():.3f} s""",
            file=sys.stdout,
        )
        try:
            print(
                f"""  + first created:     {minPickCTime}
  + last created:      {maxPickCTime}
    + interval:        {(maxPickCTime - minPickCTime).toDouble():.3f} s""",
                file=sys.stdout,
            )
        except TypeError:
            print(
                """  + first created:     no creation information
  + last created:      no creation information
    + interval:        no creation information""",
                file=sys.stdout,
            )
            pass

        print(f"  + found {len(authorPick)} pick author(s):", file=sys.stdout)
        for i in authorPick:
            print(f"    + {i}", file=sys.stdout)

    print(
        f"""
Amplitudes
  + number:            {cntAmp}""",
        file=sys.stdout,
    )
    if cntAmp > 0:
        print(
            f"""  + first amplitude:   {minAmplitudeTime}
  + last amplitude:    {maxAmplitudeTime}
    + interval:        {(maxAmplitudeTime - minAmplitudeTime).toDouble():.3f} s""",
            file=sys.stdout,
        )
        print(f"  + found {len(authorAmplitude)} amplitude author(s):", file=sys.stdout)
        for i in authorAmplitude:
            print(f"    + {i}", file=sys.stdout)

    print(
        f"""
Origins
  + number:            {cntOrg}""",
        file=sys.stdout,
    )
    if cntOrg > 0:
        print(
            f"""    + first origin:    {minOriginTime}
    + last origin:     {maxOriginTime}
      + interval:        {(maxOriginTime - minOriginTime).toDouble():.3f} s""",
            file=sys.stdout,
        )
        try:
            print(
                f"""  + first created:     {minOriginCTime}
  + last created:      {maxOriginCTime}
    + interval:        {(maxOriginCTime - minOriginCTime).toDouble():.3f} s""",
                file=sys.stdout,
            )
        except TypeError:
            print(
                """  + first created:     no creation information
  + last created:      no creation information
    + interval:        no creation information""",
                file=sys.stdout,
            )
            pass

        print(f"  + found {len(authorOrigin)} origin author(s):", file=sys.stdout)
        for i in authorOrigin:
            print(f"    + {i}", file=sys.stdout)

    # stream information
    print(f"\nFound {len(detectionStreams)} SensorLocation.Channel:", file=sys.stdout)
    for i in detectionStreams:
        print(f"  + {i}", file=sys.stdout)

    print(f"\nFound {len(nslc)} streams:", file=sys.stdout)
    for i in sorted(nslc):
        print(f"  + {i}", file=sys.stdout)

    return True


class PickPlayback(seiscomp.client.Application):
    def __init__(self, argc, argv):
        super().__init__(argc, argv)

        self.speed = 1.0
        self.timing = "creationTime"
        self.jump = 0.0
        self.print = False
        self.printList = False
        self.group = "PICK"
        self.ampGroup = "AMPLITUDE"
        self.orgGroup = "LOCATION"
        self.fileNames = None
        self.mode = "historic"
        self.authors = None
        self.objects = None

        self.setMessagingUsername("pbpick")
        self.setMessagingEnabled(True)
        self.setPrimaryMessagingGroup("PICK")
        self.setDatabaseEnabled(False, False)

    def createCommandLineDescription(self):
        self.commandline().addGroup("Playback")
        self.commandline().addStringOption(
            "Playback",
            "authors",
            "Author of objects to filter before playing back. Objects from all other "
            "authors are ignored. Separate multiple authors by comma.",
        )
        self.commandline().addDoubleOption(
            "Playback", "jump,j", "Minutes to skip objects in the beginning."
        )
        self.commandline().addOption(
            "Playback",
            "list",
            "Just list important pick information from the read XML file and then "
            "exit without playing back. The sorting of the list depends on '--timing'."
            "Information include: phase hint, pick time, stream ID, author, time to "
            "previous pick, delay.",
        )
        self.commandline().addStringOption(
            "Playback",
            "mode",
            "Playback mode: 'historic' or 'realTime'. "
            "'realTime' mimics current situation. Default: 'historic'.",
        )
        self.commandline().addStringOption(
            "Playback",
            "object,o",
            "Limit the playback to the given list of objects. Supported values are: \n"
            "pick, amplitude, origin.",
        )
        self.commandline().addOption(
            "Playback",
            "print",
            "Just print some statistics of the read XML file and then "
            "exit without playing back. The list of stream codes (NSLC) is printed to "
            "stdout. All other information is printed to stderr. The information can "
            "be used for filtering waveforms (scart) or inventory (invextr), for "
            "creating global bindings or applying author filtering, e.g., in "
            "dump_picks.",
        )
        self.commandline().addDoubleOption(
            "Playback", "speed", "Speed of playback.\n1: true speed."
        )
        self.commandline().addStringOption(
            "Playback",
            "timing",
            "Timing reference: pickTime or creationTime. Default: creationTime. "
            "'pickTime' plays back in order of actual times of objects, "
            "'creationTime' considers their creation times instead. Use 'pickTime' if "
            "creation times are not representative of the order of objects, e.g., when "
            "created in playbacks. 'creationTime' should be considered for playing "
            "back origins since their actual origin time values are always before "
            "picks and amplitudes.",
        )

    def printUsage(self):
        print(
            f"""Usage:
  {os.path.basename(__file__)} [options] [XML file][:PICK:AMPLITUDE:LOCATION]

Play back pick, amplitude and origin objects from one or more XML files in SCML format
sending them to the SeisComP messaging in timely order. Default message groups:
  * PICK for picks,
  * AMPLITUDE for amplitudes.
  * LOCATION for origins,"""
        )

        super().printUsage()

        print(
            f"""Examples:
Play back picks and other objects in file 'pick.xml' at true speed jumping the
first 2 minutes
  {os.path.basename(__file__)} -j 2 picks.xml

Play back picks and other objects from 2 XML files sending the picks, amplitudes
and origins ordered by creation time to different message groups but amplitudes
to the same default group (AMPLITUDE).
  {os.path.basename(__file__)} origins.xml l1origins.xml:L1PICK:AMPLITUDE:L1LOCATION

Just print statistics and stream information
  {os.path.basename(__file__)} --print picks.xml
"""
        )

    def init(self):
        if not super().init():
            return False

        return True

    def validateParameters(self):
        if not super().validateParameters():
            return False

        try:
            self.authors = self.commandline().optionString("authors").split(",")
        except RuntimeError:
            pass

        try:
            self.mode = self.commandline().optionString("mode")
        except RuntimeError:
            pass

        try:
            self.objects = self.commandline().optionString("object")
        except RuntimeError:
            pass

        if self.mode not in ("historic", "realTime"):
            print(f"Unknown mode: {self.mode}", file=sys.stderr)
            return False

        try:
            self.print = self.commandline().hasOption("print")
        except RuntimeError:
            pass

        try:
            self.printList = self.commandline().hasOption("list")
        except RuntimeError:
            pass

        try:
            self.speed = self.commandline().optionDouble("speed")
        except RuntimeError:
            pass

        try:
            self.timing = self.commandline().optionString("timing")
        except RuntimeError:
            pass

        try:
            self.jump = self.commandline().optionDouble("jump")
        except RuntimeError:
            pass

        if self.timing not in ("pickTime", "creationTime"):
            print(f"Unknown timing: {self.timing}", file=sys.stderr)
            return False

        try:
            self.group = self.commandline().optionString("primary-group")
        except RuntimeError:
            pass

        files = self.commandline().unrecognizedOptions()
        if not files:
            print("At least one XML file must be given!", file=sys.stderr)
            return False

        print(files, file=sys.stderr)
        self.fileNames = list(files)

        if self.print or self.printList:
            self.setMessagingEnabled(False)

        return True

    def run(self):
        seiscomp.datamodel.PublicObject.SetRegistrationEnabled(False)

        objects = []
        eps = []

        minTime = None
        maxTime = None

        print("Input:", file=sys.stdout)
        for fileName in self.fileNames:
            group = self.group
            ampGroup = self.ampGroup
            orgGroup = self.orgGroup

            toks = fileName.split(":")
            if len(toks) == 2:
                fileName = toks[0]
                group = toks[1]

            elif len(toks) == 3:
                fileName = toks[0]
                group = toks[1]
                ampGroup = toks[2]

            elif len(toks) == 4:
                fileName = toks[0]
                group = toks[1]
                ampGroup = toks[2]
                orgGroup = toks[3]

            print(
                f"  + file: {fileName}",
                file=sys.stdout,
            )

            ar = seiscomp.io.XMLArchive()
            if not ar.open(fileName):
                print(f"Could not open {fileName}", file=sys.stderr)
                return False

            obj = ar.readObject()
            ar.close()

            if obj is None:
                print("Empty document", file=sys.stderr)
                return False

            ep = seiscomp.datamodel.EventParameters.Cast(obj)

            if self.print:
                printStatistics(ep)
                if not self.printList:
                    return True

            eps.append(ep)

            if ep is None:
                print(
                    f"Expected event parameters, got {obj.className()}", file=sys.stderr
                )
                return False

            # read picks
            cntPick = ep.pickCount()
            if cntPick == 0:
                print(f"No picks found in file {fileName}", file=sys.stderr)

            if self.objects is not None and "pick" not in self.objects:
                print(
                    f"Skipping picks. Supported objects: {self.objects}",
                    file=sys.stderr,
                )
                cntPick = 0

            for i in range(cntPick):
                pick = ep.pick(i)
                if self.authors is not None:
                    try:
                        if (
                            pick.creationInfo().author() not in self.authors
                            and not self.printList
                        ):
                            print(
                                f"Skipping pick {pick.publicID()}: "
                                f"{pick.creationInfo().author()} not in author list",
                                file=sys.stderr,
                            )
                            continue
                    except ValueError:
                        if not self.printList:
                            print(
                                f"Skipping pick {pick.publicID()}: "
                                f"author is not available",
                                file=sys.stderr,
                            )
                            continue

                if self.timing == "creationTime":
                    try:
                        pick.creationInfo().creationTime()
                    except Exception:
                        if not self.printList:
                            print(
                                f"Skipping pick {pick.publicID()}: no creation time",
                                file=sys.stderr,
                            )
                            continue

                # filter by time
                if minTime and pick.time().value() < minTime:
                    continue
                if maxTime and pick.time().value() >= maxTime:
                    continue
                objects.append((pick, group))

            # read amplitudes and add to objects
            cntAmp = ep.amplitudeCount()
            if cntAmp == 0:
                print("No Amplitudes found", file=sys.stderr)

            if self.objects is not None and "amplitude" not in self.objects:
                print(
                    f"Skipping amplitudes. Supported objects: {self.objects}",
                    file=sys.stderr,
                )
                cntAmp = 0

            for i in range(cntAmp):
                amp = ep.amplitude(i)
                if self.authors is not None:
                    try:
                        if (
                            amp.creationInfo().author() not in self.authors
                            and not self.printList
                        ):
                            print(
                                f"Skipping amplitude {amp.publicID()}: "
                                f"{amp.creationInfo().author()} not in author list",
                                file=sys.stderr,
                            )
                            continue
                    except ValueError:
                        if not self.printList:
                            print(
                                f"Skipping amplitude {amp.publicID()}: "
                                f"author is not available",
                                file=sys.stderr,
                            )
                            continue

                if self.timing == "creationTime":
                    try:
                        amp.creationInfo().creationTime()
                    except Exception:
                        print(
                            f"Skipping amplitude {amp.publicID()}: no creation time",
                            file=sys.stderr,
                        )
                        continue

                objects.append((amp, ampGroup))

            # read origins and add to objects
            cntOrgs = ep.originCount()
            if cntOrgs == 0:
                print("No Origins found", file=sys.stderr)

            if self.objects is not None and "origin" not in self.objects:
                print(
                    f"Skipping origins. Supported objects: {self.objects}",
                    file=sys.stderr,
                )
                cntOrgs = 0

            for i in range(cntOrgs):
                oo = ep.origin(i)

                if self.authors is not None:
                    try:
                        if (
                            oo.creationInfo().author() not in self.authors
                            and not self.printList
                        ):
                            print(
                                f"Skipping origin {oo.publicID()}: "
                                f"{oo.creationInfo().author()} not in author list",
                                file=sys.stderr,
                            )
                            continue
                    except ValueError:
                        if not self.printList:
                            print(
                                f"Skipping origin {oo.publicID()}: "
                                f"author is not available",
                                file=sys.stderr,
                            )
                            continue

                if self.timing == "creationTime":
                    try:
                        oo.creationInfo().creationTime()
                    except Exception:
                        try:
                            string = oo.publicID().split("/")[1].split(".")[:2]
                            timeString = string[0] + "." + string[1]
                            timeFormat = "%Y%m%d%H%M%S.%f"
                            t = seiscomp.core.Time()
                            t.fromString(str(timeString), timeFormat)
                            ci = seiscomp.datamodel.CreationInfo()
                            ci.setCreationTime(t)
                            oo.setCreationInfo(ci)
                            print(
                                f"creation time not found in origin {oo.publicID()}: "
                                f"assuming {oo.creationInfo().creationTime()} from "
                                "originID ",
                                file=sys.stderr,
                            )
                        except Exception:
                            if not self.printList:
                                print(
                                    f"Skipping origin {oo.publicID()}: no creation time",
                                    file=sys.stderr,
                                )
                                continue

                objects.append((oo, orgGroup))

        print(
            f"  + considering {cntPick} picks, {cntAmp} amplitudes, {cntOrgs} origins",
            file=sys.stdout,
        )
        if self.print or self.printList:
            print("  + do not send objects to messaging")
        else:
            print(
                f"""  + sending objects to groups
    + picks:      {group}
    + amplitudes: {ampGroup}
    + origins:    {orgGroup}""",
                file=sys.stdout,
            )

        if self.timing == "pickTime":
            try:
                objects.sort(key=timing_pickTime)
            except ValueError:
                print("Time value not set in at least 1 object", file=sys.stderr)
                if not self.printList:
                    return False
        elif self.timing == "creationTime":
            try:
                objects.sort(key=timing_creationTime)
            except ValueError:
                print("Creation time not set in at least 1 object", file=sys.stderr)
                if not self.printList:
                    return False
        else:
            print(f"Unknown timing: {self.timing}", file=sys.stderr)
            return False

        print("Setup:", file=sys.stdout)
        print(f"  + author filter: {self.authors}", file=sys.stdout)
        print(f"  + timing/sorting: {self.timing}", file=sys.stdout)

        if self.printList:
            listPicks(self, objects)
            return True

        seiscomp.datamodel.Notifier.Enable()

        firstTime = None
        lastTime = None
        refTime = None
        addSeconds = 0.0

        sys.stdout.flush()

        for obj, group in objects:
            po = seiscomp.datamodel.Pick.Cast(obj)
            ao = seiscomp.datamodel.Amplitude.Cast(obj)
            oo = seiscomp.datamodel.Origin.Cast(obj)

            if self.isExitRequested():
                break

            if self.timing == "pickTime":
                if ao:
                    refTime = obj.timeWindow().reference()
                elif po:
                    refTime = obj.time().value()
                elif oo:
                    refTime = obj.time().value()
                else:
                    print(
                        "Object neither pick nor amplitude or origin- ignoring",
                        file=sys.stderr,
                    )
                    return False
            else:
                refTime = obj.creationInfo().creationTime()

            if not firstTime:
                firstTime = refTime

                print(f"  + first time: {firstTime}", file=sys.stderr)
                print(f"  + playback mode: {self.mode}", file=sys.stderr)
                print(f"  + speed factor: {self.speed}", file=sys.stderr)

                if self.mode == "realTime":
                    now = seiscomp.core.Time.GMT()
                    addSeconds = (now - firstTime).toDouble()
                    print(
                        f"    + adding {addSeconds: .3f} s to: pick time, amplitude "
                        "reference time, origin time, creation time",
                        file=sys.stderr,
                    )

                print("Playback progress:", file=sys.stderr)

            objectType = "pick"
            if ao:
                objectType = "amplitude"
            if oo:
                objectType = "origin"

            print(
                f"  + {obj.publicID()} {objectType}: {group} - reference time: {refTime}",
                end="",
                file=sys.stderr,
            )

            # add addSeconds to all times in real-time mode
            if self.mode == "realTime":
                objectInfo = obj.creationInfo()
                creationTime = objectInfo.creationTime() + seiscomp.core.TimeSpan(
                    addSeconds
                )
                obj.creationInfo().setCreationTime(creationTime)

                if ao:
                    objectInfo = obj.timeWindow()
                    amplitudeTime = objectInfo.reference() + seiscomp.core.TimeSpan(
                        addSeconds
                    )
                    obj.timeWindow().setReference(amplitudeTime)
                    print(
                        "\n    + real-time mode - using modified reference time: "
                        f"{obj.timeWindow().reference()}, creation time: {creationTime}",
                        end="",
                        file=sys.stderr,
                    )
                elif po or oo:
                    objectTime = obj.time()
                    objectTime.setValue(
                        objectTime.value() + seiscomp.core.TimeSpan(addSeconds)
                    )
                    obj.setTime(objectTime)
                    print(
                        f"\n    + real-time mode - using modified {objectType} time: "
                        f"{obj.time().value()}, creation time: {creationTime}",
                        end="",
                        file=sys.stderr,
                    )
                else:
                    print(
                        "\n    + object not pick, amplitude or origin - ignoring",
                        file=sys.stderr,
                    )
                    return False

            delay = 0
            if lastTime:
                delay = (refTime - lastTime).toDouble() / self.speed

            if (refTime - firstTime).toDouble() / 60.0 >= self.jump:
                delay = max(delay, 0)

                print(f" - time to sending: {delay:.4f} s", file=sys.stderr)
                time.sleep(delay)

                lastTime = refTime

                nc = seiscomp.datamodel.NotifierCreator(seiscomp.datamodel.OP_ADD)
                obj.accept(nc)
                msg = seiscomp.datamodel.Notifier.GetMessage()
                self.connection().send(group, msg)
            else:
                print(" - skipping", file=sys.stderr)

            sys.stdout.flush()

        print("")

        return True


def main(argv):
    app = PickPlayback(len(argv), argv)
    return app()


if __name__ == "__main__":
    sys.exit(main(sys.argv))
