eval 'exec perl -x $0 ${1+"$@"}' # -*-perl-*-
  if 0;
#!perl -w
#
# ======================================================================
# This file is Copyright 1998,1999 by the Purdue Research Foundation and
# may only be used under license.  For terms of the license, see the
# file named COPYRIGHT included with this software release.
# AAFID is a trademark of the Purdue Research Foundation.
# All rights reserved.
# ======================================================================
#
# AAFID::Common
#
# AAFID project, COAST Laboratory, CERIAS, 1998-1999.
# 
# Diego Zamboni, Feb 25, 1998
#
# $Id: Common.pm,v 1.7 1999/09/03 17:08:52 zamboni Exp $
# $Log: Common.pm,v $
# Revision 1.7  1999/09/03 17:08:52  zamboni
# Changed the start line to something that is path-independent, and
# updated the copyright notice.
#
# Revision 1.6  1998/06/29 20:11:23  zamboni
# Added copyright message
#
# Revision 1.5  1998/04/27 15:09:58  zamboni
# - Added splitList.
#
# Revision 1.4  1998/03/14 05:54:49  zamboni
# - Added newErrorMsg and hashToStr
#
# Revision 1.3  1998/03/13 17:01:52  zamboni
# - Added $VERSION declaration.
#
# Revision 1.2  1998/03/06 07:12:49  zamboni
# - Added "use strict"
#
# Revision 1.1  1998/02/26 05:34:26  zamboni
# Initial revision
#
#
# NOTE: This file is in Perl's POD format. For more information, see the 
#       manual page for perlpod(1).
#

package AAFID::Common;

# The following keeps up with the RCS version number. The self-assignment
# keeps the -w switch from complaining (because $VERSION may not be used
# here, but it is used in our base class).
$VERSION = do { my @r = (q$Revision: 1.7 $ =~ /\d+/g); sprintf "%d."."%02d" x $#r, @r }; $VERSION = $VERSION;

use vars qw(
	    @ISA
	    @EXPORT
	   );
use strict;
use Carp;
use Exporter();
use Data::Dumper;
use AAFID::Message;

@ISA=qw(Exporter);

@EXPORT=qw(
	   checkref
	   newErrorMsg
	   hashToStr
	   splitList
	  );

=pod

This package contains some commonly used routines.

=head1 Checking for a reference.

Many subroutines are intended to be called only as instance methods, and
thus we would like to check for this and generate an error in a 
non-instance call is attempted. The common (not foolproof) way of doing
this is to check that the first argument to the method is a reference. It
is not foolproof because the first method could be a reference to some
other thing, but it is good enough for our current purposes.

After writing a ton of lines like this:

  sub blabla {
    my $self=shift;
    ref($self) or croak "blabla can only be called as an instance method";
  }

i decided to write this subroutine. It should be called like this:

  sub blabla {
    my $self=checkref(shift);
  }

it will check that its argument is a reference, and generate an error
on behalf of the caller if not.

If we know the class that the object should be, we can pass that as a
second argument. Thus, we can check the type of certain objects. In this
case, an inheritance tree search is done, so if the message is of the
specified class or one of its descendants, it is ok.

=cut

sub checkref {
  my $arg=shift;
  my $argtype=shift;
  my ($callerpackage, $callersub)=(caller(0))[0,3];
  if (!$argtype) {
    ref($arg) or confess "${callerpackage}::${callersub} can only be called as an instance method";
  }
  else {
    my $realtype=ref($arg);
    $realtype or confess "Argument is not a reference";
    $arg->isa($argtype) or confess "Argument must be of type $argtype and it is of type $realtype";
  }
  return $arg;
}

=head1 Generating an error message

The C<newErrorMsg> subroutine takes a hash reference as argument, and
returns a message with type ERROR, no subtype, and the stringified
version of the hash in the DATA field.

=cut

sub newErrorMsg {
  # TODO: How to check if this is a hash?
  my $data=hashToStr(shift);
  return AAFID::Message->new(TYPE	=> "ERROR",
			     DATA	=> $data,
			    );
}

=head1 "Stringifying" a hash

The C<hashToStr> subroutine takes a hash reference, and returns a
string that contains the representation of the hash as produced by
B<Data::Dumper>, in a single line, without the opening and closing
braces. It is responsability of the caller to ensure that the elements
of the hash do not contain any newlines if the thing is supposed to be
in a single line.

=cut

sub hashToStr {
  my $hashref=shift;
  $Data::Dumper::Indent=0;
  $Data::Dumper::Terse=1;
  my $datadump=Dumper($hashref);
  $datadump =~ s/^\s*\{(.*)\}\s*/$1/;
  return $datadump;
}

=head1 Splitting a list

Many parameters in the AAFID system are strings that contain lists of
things, usually separated by comma-and-spaces. Any of the following
would be valid lists:

  "item1,item2,item3"
  "item1, item2,item3"
  "item1 item2, item3"

The C<splitList> subroutine is simply a wrapper to the C<split> statement
that provides a default comma-and-space separator, and returns the
resulting list.

Notice that multiple commas with nothing in between will B<not> result 
in multiple C<undef> items, they will simply be ignored as a single
separator.

=cut

sub splitList {
  my $str=shift;
  return split(/[,\s]+/, $str);
}

1;
