=head1 NAME

CFX5::Output::Terminal - default output routines

=head1 SYNOPSIS

  use CFX5::Output;

=head1 DESCRIPTION

The C<CFX5::Output::Terminal> class is the standard output class for
CFX-5 perl scripts using L<CFX5::Output>, and is used by default
unless overridden.

It is also a reasonably simple example of subclassing
L<CFX5::Output::Base>, upon which it is based.

=cut

package CFX5::Output::Terminal;
@ISA=qw(CFX5::Output::Base);
use strict;

use CFX5::Output::Base;

=head2 STANDARD METHODS

=head3 init

The C<init> routine here reads the C<CFX_OUTPUT> environment variable,
and uses it to set up the list of output types to process or ignore.

=cut

sub init {
  my $self=shift;
  
  unless (exists $self->{defaults}) {
    # the default destinations for the various error types, if they
    # are switched on.
    #    2 => send to stdout
    #    3 => send to stderr
    #    4 => send to stderr if available, log if not (for debugging)
    $self->{defaults}=
      {
       'internal' => 3,
       'abort'    => 3,
       'error'    => 3,
       'warn'     => 3,
       'info'     => 3,
       'moreinfo' => 3,
       'trace'    => 4,
       'debug'    => 4,
       'stack'    => 4,
       'print'    => 2,
      };
  }
  
  unless (exists $self->{settings}) {
    # The default on/off settings
    #    1 => display
    #    0 => do not display
    $self->{settings}=
      {
       'internal' => 1,
       'abort'    => 1,
       'error'    => 1,
       'warn'     => 1,
       'info'     => 0,
       'moreinfo' => 0,
       'trace'    => 0,
       'debug'    => 0,
       'stack'    => 0,
       'print'    => 1,
      };
  }

  unless (exists $self->{codes}) {
    # color coding
    $self->{codes}=
      {
       'internal' => ["\033[31m", "\033[0m"],,
       'abort'    => ["\033[31m", "\033[0m"],,
       'error'    => ["\033[31m", "\033[0m"],,
       'trace'    => ["\033[35m", "\033[0m"],
       'debug'    => ["\033[34m", "\033[0m"],
      };
  }

  # set_verbosity changes only the on/off status of the messages
  #
  # we try to be clever to avoid having to load CFX5::Config if it's
  # not necessary.  We also need to check that CFX5::DefaultConfig is
  # loaded, as that's now auto-loaded by CFX5::Config when called.
  my $verb;
  if (exists &CFX5::Config::getconf and exists &CFX5::DefaultConfig::CFX_DATA_DIR) {
    $verb=CFX5::Config::getconf('CFX_OUTPUT');
  } else {
    $verb=$ENV{CFX_OUTPUT};
  }
  $self->set_verbosity($verb) if defined $verb;

  1;
}

=head3 output

This version of the C<output> function uses the on/off settings from
C<set_verbosity> to decide whether to output a given message or not.
Word wrapping is done to the value of the configuration record
C<CFX5_TERMINAL_WIDTH>, or 75 by default; verbatim lines (such as
filenames) are not wrapped.

=cut

sub output {
  my $self=shift;
  my $type=shift;
  my $severity=shift;
  my $title=shift;
  my $text=join('',@_);

  $self->internal_error("Unknown output type $type") 
    unless exists $self->{settings}{$type};
  
  return unless $self->{settings}{$type};

  my $op=$self->{defaults}{$type};

  # colorise the output if we're on a terminal type we recognise.  XXX
  # currently we restrict it to when the debug output is switched on;
  # this should be removed in the next release.
  my ($cstart, $cend)=('','');
  if (($self->have_output('trace') or $self->have_output('debug'))
      and defined $ENV{TERM}
      and $ENV{TERM} =~ m!linux|xterm|Eterm|vt[0-9]+!
      and defined $self->{codes}{$type}) {
    ($cstart,$cend)=@{$self->{codes}{$type}};
  }

  if ($op == 2) {
    print STDOUT $cstart, ($self->text_to_show($title,$text)), $cend;
  } elsif ($op == 3 || $op == 4) {
    print STDERR $cstart, ($self->text_to_show($title,$text)), $cend;
  }

  return 1;
}

=head2 CUSTOM METHODS

=head3 set_verbosity

C<set_verbosity> determines which messages are displayed to the screen
during a run. It should be called with one or more arguments, from the
following list:

=over

=item warn

Warnings. These are displayed by default.

=item info

Informational messages, displayed by L<_note> and L<_info>. These are
off by default, but should be switched on if the configuration
variable C<VERBOSE> is set.

=item moreinfo

This does not correspond to a function, but is used by some other
modules. It's meaning, roughly, is that where a script would normally
give output when C<info> is set, that output should be made more complete.

=item trace

Display a trace of program execution, including when new processes are
spawned or large functions invoked. This is off by default.

=item debug

Display any other information which the programmer thought might be
useful for debugging. This is off by default.

=item noI<keyword>

Turn off I<keyword>

=back

The verbosity is initialised from the environment variable CFX_OUTPUT
when the program starts.

=cut '

sub set_verbosity {
  my $self=shift;
  my $p;
  for $p (map { split(/[, ]/) } @_) {
    my $val=1;
    if ($p =~ m/^no(.*)/) {
      $p=$1;
      $val=0;
    }
    $self->warn("Setting unrecognised output parameter $p")
      unless exists $self->{settings}{$p};
    $self->{settings}{$p}=$val;
  }
}

=head3 query_verbosity

  if (query_verbosity('moreinfo')) {
    _info("This is some more info");
  }

Returns TRUE if the requested level is set, or FALSE (0)
otherwise. Note that queries of the "noI<level>" forms are not
allowed.

If the requested level is not known, returns undef.

=cut

sub query_verbosity {
  my $self=shift;
  my $level=shift;
  return $self->{settings}{$level};
}


1;
