#  You may distribute under the terms of either the GNU General Public License
#  or the Artistic License (the same terms as Perl itself)
#
#  (C) Paul Evans, 2014-2016 -- leonerd@leonerd.org.uk

package Tickit::Debug 0.72;

use v5.14;
use warnings;

use constant DEBUG => _enabled();

use Exporter 'import';
our @EXPORT = qw( DEBUG );

=head1 NAME

C<Tickit::Debug> - debug logging support for C<Tickit>

=head1 DESCRIPTION

This module implements the debug logging logic for L<Tickit>. It is controlled
by a number of environment variables. It exports a constant called C<DEBUG>
which will be true if the debug logging is enabled; allowing code to
efficiently skip over it if it isn't.

Debug messages themselves each have a flag name, which is a short string
identifying the Tickit subsystem or kind of event that caused it. A given
subset of these flags can be enabled for printing. Flags not enabled will not
be printed.

=cut

=head1 FLAGS

Each flag name starts with a upper-case letters indicating the subsystem it
relates to, then lower-case letters to indicate the particular kind of event
or message.

=head2 B (RenderBuffer)

=head3 Bd

Drawing operations

=head3 Bf

Flushing

=head3 Bs

State stack save/restore

=head3 Bt

Transformations (translate, clip, mask)

=head2 I (Input)

=head3 Ik

Keyboard events

=head3 Im

Mouse events

=head3 Ir

Resize events

=head2 W (Window)

=head3 Wd

Rectangles of damage queued on the root window for re-expose

=head3 Wh

Hierarchy changes on Windows (creates, deletes, re-orderings)

=head3 Ws

Calls to C<< $win->scrollrect >>

=head3 Wsr

Calls to C<< $term->scrollrect >> on the root window as part of scrollrect

=head3 Wx

Expose events on Windows; which may result in calls to its C<on_expose>
handler. As this event is recursive, it prints an indent.

=cut

=head1 ENVIRONMENT

=head2 TICKIT_DEBUG_FLAGS

A comma-separated list of the flags or flag categories to enable for printing.
Each potential flag exists in a category, given by the leading upper-case
letters of its name. Entire categories can be enabled by name, as can
individual flags.

See the L</FLAGS> list above for the available flags.

=head2 TICKIT_DEBUG_FD

If set, debug logging is sent directly to the opened filehandle given by this
file descriptor number, rather than opening a log file.

Typically this is most useful to start a C<Tickit>-based application in a new
terminal but have its debug logging printed to STDERR of the original terminal
the new one was launched from. For example

 $ TICKIT_DEBUG_FD=3 TICKIT_DEBUG_FLAGS=... $TERM perl my-tickit-app.pl 3>&2

This requests that C<Tickit::Debug> log to file descriptor 3, which has been
created by copying the original shell's standard error output, and so logging
is printed to the shell this was run from.

=head2 TICKIT_DEBUG_FILE

Gives the name of a file to open and write logging to, if C<TICKIT_DEBUG_FD>
is not set. If this is not set either, a filename will be generated using the
PID of the process, named as

 tickit-PID.log

=cut

=head1 METHODS

=cut

=head2 log

   Tickit::Debug->log( $flag => $format, @args )

Prints a line to the debug log if the specified C<$flag> is present in the set
of enabled flags.

Any arguments that are C<CODE> references are called and replaced by the
list of values they return, then the line itself is generated by calling
C<sprintf> using the format string and the given arguments. It is then
printed to the log, prefixed by the flag name and with a linefeed appended.

It is not necessary to include the C<\n> linefeed in the C<$format> itself.

=cut

sub log :method
{
   shift;
   my ( $flag, $format, @args ) = @_;

   return unless _enabled();

   my $message = sprintf $format, map { ref eq "CODE" ? $_->() : $_ } @args;

   _log( $flag, $message );
}

=head1 AUTHOR

Paul Evans <leonerd@leonerd.org.uk>

=cut

0x55AA;