class Ticket implements Comparable<Ticket>
    {
        private final ZTicket      parent;
        private final TimerHandler handler;
        private final Object[]     args;
        private long               start;
        private long               delay;
        private boolean            alive = true;

        private Ticket(ZTicket parent, long now, long delay, TimerHandler handler, Object... args)
        {
            assert (args != null);
            this.parent = parent;
            this.start = now;
            this.delay = delay;
            this.handler = handler;
            this.args = args;
        }

        /**
         * Resets the ticket.
         */
        public void reset()
        {
            if (alive) {
                parent.sort = true;
                start = parent.now();
            }
        }

        /**
         * Cancels a ticket.
         * @return true if cancelled, false if already cancelled.
         */
        public boolean cancel()
        {
            if (alive) {
                alive = false;
                parent.sort = true;
                return true;
            }
            return false;
        }

        /**
         * Changes the delay of the ticket.
         * @param delay the new delay of the ticket.
         */
        public void setDelay(long delay)
        {
            if (alive) {
                parent.sort = true;
                this.delay = delay;
            }
        }

        @Override
        public int compareTo(Ticket other)
        {
            if (alive) {
                if (other.alive) {
                    return Long.compare(start - other.start, other.delay - delay);
                }
                return -1;
            }
            return other.alive ? 1 : 0;
        }
    }

    private final List<Ticket> tickets;

    private final Supplier<Long> clock;

    private boolean sort;

    public ZTicket()
    {
        this(() -> TimeUnit.NANOSECONDS.toMillis(Clock.nowNS()));
    }

    ZTicket(Supplier<Long> clock)
    {
        this(clock, new ArrayList<>());
    }

    ZTicket(Supplier<Long> clock, List<Ticket> tickets)
    {
        this.clock = clock;
        this.tickets = tickets;
    }

    private long now()
    {
        return clock.get();
    }

    private void insert(Ticket ticket)
    {
        sort = tickets.add(ticket);
    }

    /**
     * Add ticket to the set.
     * @param delay the expiration delay in milliseconds.
     * @param handler the callback called at the expiration of the ticket.
     * @param args the optional arguments for the handler.
     * @return an opaque handle for further cancel and reset.
     */
    public Ticket add(long delay, TimerHandler handler, Object... args)
    {<FILL_FUNCTION_BODY>

        if (handler == null) {
            return null;
        }
        Utils.checkArgument(delay > 0, "Delay of a ticket has to be strictly greater than 0");
        final Ticket ticket = new Ticket(this, now(), delay, handler, args);
        insert(ticket);
        return ticket;
    
<no_super_class>