#---------------------------------------------------------------------#
# This source code is (c)1999 Dave Belfer-Shevett - shevett@pobox.com #
# see http://www.stonekeep.com/license.html for licensing information #
#---------------------------------------------------------------------#

# ----------------------------------------------------------------------
#  Written by David H. Silber for Stonekeep Consulting.
#  david@SilberSoft.com -- http://www.SilberSoft.com/
# ----------------------------------------------------------------------

# ----------------------------------------------------------------------
#  Slip.pm
#  $Id:
# ----------------------------------------------------------------------

# ----------------------------------------------------------------------
package Slip;

# ----------------------------------------------------------------------
#  This provides access to the status table for use in expanding status
#  flags.
require Status;

# ----------------------------------------------------------------------
#  To keep me honest.
use strict;

# ----------------------------------------------------------------------
#  Used to format the summary for the full display.
use Text::Wrap qw(wrap $columns);


=head1 NAME

Slip - The Keystone database `slips' table

=head1 SYNOPSIS 

        require Slip;

	$slip = new Slip ( \%sliphash );

	$sid = $slip->sid();

	$fieldlist = fields Slip ();

	$slip->brief( $format );

	$slip->full( $format );

	$slip->oneline( $format );

=head1 DESCRIPTION

Slip provides methods that operate on a Slip.

=head1 DATA FORMAT

A Slip object contains a hash of slip data.
The keys are database column names.

=head1 METHODS

=cut



# ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

=head2 new() -- Construct a Slip object.

Given a hash containing the information for a keystone slip, make a
Slip object.

=over 4

=item Use:

  require Slip;

  $slip = new Slip ( \%sliphash );

=item Parameters:

=over 4

=item slip

Hash of slip information.
Keys are database column names.

=back

=item Returns:

A Slip object.

=back

=cut # +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

sub new {
  my $package = shift;
  my ($slip) = @_;   #  Reference to hash of slip information.

  $main::debug && print STDERR "Entering " . $package . "::new().\n";


#  #  For debugging:
#  foreach $field (keys( %$slip )) {
#    $$slip{$field} && print uc($field) . ": " . $$slip{$field} . ".\n";
#  }

  #  Make the data provided *be* a Slip:
  bless $slip, $package;


  $main::debug && print STDERR "Returning from " . $package . "::new().\n";

  #  Return the reference to this Slip.
  return $slip;
}



# ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

=head2 sid() -- Get the ID number of this Slip.

Return the sid field of this slip.

=over 4

=item Use:

  require Slip;

  $sid = $slip->sid();

=item Returns:

The slip ID of this Slip.

=back

=cut # +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

sub sid {
  my $self = shift;

  return $self->{sid};
}



# ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

=head2 fields() -- List the fields in a slip.

Provide a list of the slip fields as a single string.

As this provides general information, rather than data from a specific
Slip object, a reference to an actual Slip object is not required.

=over 4

=item Use:

  require Slip;

  $fieldlist = fields Slip ();

=item Returns:

A hard-coded list of the fields which comprise a slip record.

=back

=cut # +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

sub fields {
  my $self = shift;
  my ($format) = @_;


  $main::debug && print "Entering " . $self . "::fields( " . $format . " ).\n";

  my $fields =  "sid spid depend o_date o_tech c_date c_tech " .
      "currtech status priority ctag problem summary so_date " .
      "sc_date grp is_public l_activity l_tech num_children " .
      "num_follows";

  if ($format eq "csv") {
    $fields =~ s/\b/"/g;
    $fields =~ s/ /, /g;
  }
  elsif ($format eq "sql") {
    $fields =~ s/ /, /g;
  }


  $main::debug && print "Returning qw( " . $fields . " ) from " . $self . "::fields().\n";

  return $fields;
}



# ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

=head2 brief() -- Display a slip in a brief format.

Display the main information from a slip in a single line.

=over 4

=item Use:

  require Slip;

  $slip->brief( $format );

=item Parameters:

=over 4

=item format

This format string has been adjusted so that the columns for the slip ID
and date are just wide enough for the size of the slip number and date format.
The problem statement will use as much space as is left available.

=back

=item Returns:

One line of text, briefly describing a slip.

=back

=cut # +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

sub brief {
  my $self = shift;
  my ($format) = @_;

  $main::debug && print STDERR "Entering " . $self . "::brief().\n";


  my $retval;     #  String to return.
  my $problem;    #  Temporary problem string.
  my $summary;    #  Temporary summary holder.

  #  Problem:
  #  Clean up the case where there are 7(!) backslashes before an
  #  apostrophe in the problem field.
  $problem = $self->{problem};
  $problem =~ s/\\\\\\\\\\\\\\(.)/$1/;
  $problem =~ s/\\(.)/$1/g;

  #  Summary:
  #  Clean up the case where there are 7(!) backslashes before an
  #  apostrophe in the summary field.
  $summary = $self->{summary};
  $summary =~ s/\\\\\\\\\\\\\\(.)/$1/;
  $summary =~ s/\\(.)/$1/g;

  $retval = sprintf( $format, $self->{"sid"},
      expand Status ( $self->{status} ),
      $main::keystone->dateformat( $self->{o_date} ),
      ($self->{o_tech} || "none"), $problem );


  $main::debug && print STDERR "Returning from " . $self . "::brief().\n";

  return $retval;
}



# ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

=head2 full() -- Display a slip in a full format.

Display all of the information in a slip.

=over 4

=item Use:

  require Slip;

  $slip->full( $format );

=item Parameters:

=over 4

=item format

Ignored.
Accepted only so that all of the display methods use the same set of
parameters.

=back

=item Returns:

A multi-line block of text, describing a single Slip.

=back

=cut # +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

sub full {
  my $self = shift;

  $main::debug && print STDERR "Entering " . $self . "::full().\n";


  my $retval;     #  String to return.
  my $problem;    #  Temporary problem holder.
  my $summary;    #  Temporary summary holder.
  my $datewidth;  #  Space to allocate for a date string.
  my $format;     #  Temporary string to contain variable formats.

  #  Clean up the case where there are 7(!) backslashes before an
  #  apostrophe in the problem field.
  $problem = $self->{problem};
  $problem =~ s/\\\\\\\\\\\\\\(.)/$1/;
  $problem =~ s/\\(.)/$1/g;

  $datewidth = Utilities::min( $main::keystone->datewidth(), 27 );

  #  Problem:
  $retval = sprintf( "Problem:  %-70.70s\n", $problem );

  #  Child of:
  if ($self->{spid}) {
    $retval .= sprintf ( "Child of: %-4i\n", $self->{spid} );
  }
  $retval .= sprintf( "Slip # :  %-4i\n", $self->{"sid"} );

  #  Status:
  $retval .= sprintf( "Status:   %-15.15s  ",
      expand Status ( $self->{status} ) );

  #  Current Tech:
  $retval .= sprintf( "Current Tech:  %-10.10s         ",
      ($self->{currtech} || "none") );

  #  Contact:
  $retval .= sprintf( "Contact: %-10.10s\n", $self->{ctag} );

  #  Priority:
  $retval .= sprintf( "Priority: %-7i          ", $self->{priority} );

  #  Slip open details:
  $format = sprintf( "Open:          %%-%i.%is by %%-7.7s\n",
      $datewidth, $datewidth );
  $retval .= sprintf( $format, $main::keystone->dateformat( $self->{o_date} ),
      ($self->{o_tech} || "none"));

  #  Group: 
  $retval .= sprintf( "Group:    %-10.10s       ", $self->{grp} );

  #  Slip last activity details, if any:
  if ($self->{l_activity} && $self->{l_tech}) {
    $format = sprintf( "Last Activity: %%-%i.%is by %%-7.7s",
	$datewidth, $datewidth );
    $retval .= sprintf( $format,
	$main::keystone->dateformat( $self->{l_activity} ),
	($self->{l_tech} || "none"));
  }
  $retval .= "\n";

  #  Public?:
  $retval .= sprintf( "Public:   %-3.3s              ",
      $self->{is_public} ? "Yes" : "No " );

  #  Slip close details, if any:
  if ($self->{c_date} && $self->{c_tech}) {
    $format = sprintf( "Closed:        %%-%i.%is by %%-7.7s",
	$datewidth, $datewidth );
    $retval .= sprintf( $format, $main::keystone->dateformat( $self->{c_date} ),
        ($self->{c_tech} || "none"));
  }
  $retval .= "\n";
  
  #  Clean up the case where there are 7(!) backslashes before an
  #  apostrophe in the summary field.
  $summary = $self->{summary};
  $summary =~ s/\\\\\\\\\\\\\\(.)/$1/;
  $summary =~ s/\\(.)/$1/g;

  #  Format the summary text to fit in a standard screen.
  $columns = 80;
  $retval .= wrap( "", "", $summary );
  $retval .= "\n\n";


  $main::debug && print STDERR "Returning from " . $self . "::full().\n";

  return $retval;
}



# ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

=head2 oneline() -- Display a slip in a oneline format.

Display this slip as a comma-separated list of values.
The list will be in the same order as the C<fields()> method provides
them.
Each element will be enclosed by a pair of double quotes.
Any double quotes or slash characters will be escaped by a preceeding
slash.

=over 4

=item Use:

  require Slip;

  $slip->oneline( $format );

=item Parameters:

=over 4

=item format

Ignored.
Only accepted to make all of the display methods use the same set of
parameters.

=back

=item Returns:

One line of text, containing all of the information in a Slip record.

=back

=cut # +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

sub oneline {
  my $self = shift;
  my ($format) = @_;

  $main::debug && print STDERR "Entering " . $self . "::oneline().\n";


  my $retval;     #  String to return.
  my $problem;    #  Temporary problem string.

  #  Problem:
  #  Clean up the case where there are 7(!) backslashes before an
  #  apostrophe in the problem field.
  $self->{problem} =~ s/\\\\\\\\\\\\\\(.)/$1/;
  $self->{summary} =~ s/\\\\\\\\\\\\\\(.)/$1/;
  $self->{problem} =~ s/\\(.)/$1/g;
  $self->{summary} =~ s/\\(.)/$1/g;

#  $retval = sprintf( "%s, %s, %s, %s, %s, %s", $format, $self->{sid},
#      expand Status ( $self->{status} ),
#      $main::keystone->dateformat( $self->{o_date} ),
#      ($self->{o_tech} || "none"), $problem );

#  foreach my $field (@fieldlist) {
  foreach my $field (split / /, $self->fields()) {
    $retval .= Utilities::enquote( $self->{$field} ) . ", ";
  }
  $retval =~ s/..$/\n/;


  $main::debug && print STDERR "Returning qw( " . $retval . " ) from " .
      $self . "::oneline().\n";

  return $retval;
}

1;

__END__

=head1 CAVEATS

=head1 BUGS

None that I know of.

=head1 AUTHOR

David H. Silber
of Silber Software Engineering
F<E<lt>david@SilberSoft.comE<gt>>
wrote this for StoneKeep Consulting
as part of the B<keycli> development effort.

=head1 SEE ALSO

L<Keystone>,
L<Status>

=cut

