package RISCOS::DrawFile::Common;

use RISCOS::BBox qw(inside inside_or_touching intersect intersect_or_touching
		    outside);
use RISCOS::Clone (Clone);

use strict;
use vars qw ($VERSION @ISA @EXPORT_OK);
use Carp;

$VERSION = 0.03;
# 0.03 adds Translate

@ISA = 'Exporter';
@EXPORT_OK = 'drawplus_split_type';

### use SelfLoader;
sub RISCOS::DrawFile::Common::drawplus_split_type ($);
sub RISCOS::DrawFile::Common::BBox ;
sub RISCOS::DrawFile::Common::Translate ($$$$);
sub RISCOS::DrawFile::Common::Inside ($$);
sub RISCOS::DrawFile::Common::InsideOrTouching ($$);
sub RISCOS::DrawFile::Common::Intersect ($$);
sub RISCOS::DrawFile::Common::IntersectOrTouching ($$);
sub RISCOS::DrawFile::Common::Outside ($$);
1;
### __DATA__
sub drawplus_split_type ($) {
    return $_[0] & 0xFF unless wantarray;
    unpack 'C4', pack 'I', $_[0];
}

sub BBox {
    my $self = shift;
    defined $self->{'__BBOX'} ? $self->{'__BBOX'} : $self->BBox_Calc;
}

sub Translate ($$$$) {
    if (ref ($_[3]) eq 'CODE') {
	&{$_[3]}($_[0], $_[1], $_[2]);
    } elsif (not defined $_[3]) {
	warn "Cannot translate $_[0] by ($_[1], $_[2])\n";
    } elsif ($_[3] eq '') {
	my $self = $_[0];
	my $bbox = defined $self->{'__BBOX'} ? $self->{'__BBOX'}
					     : $self->BBox_Calc;
	if (defined $bbox) {
	    $$bbox[0] += $_[1];
	    $$bbox[1] += $_[2];
	    $$bbox[2] += $_[1];
	    $$bbox[3] += $_[2];
	} else {
	    warn "Cannot translate $_[0] by ($_[1], $_[2])\n";
	}
    } else {
	confess "Illegal third argument to translate ('$_[3]') when attempting to translate $_[0] by ($_[1], $_[2])";
    }
    ();
}

sub Inside ($$) {
    my $bbox = $_[0]->BBox();
    ($bbox and inside $_[1], $bbox) ? $_[0] : ();
    # Return ourself if we have a defined bbox, and if it is inside the supplied
    # box
    # Otherwise, if I've understood things correctly empty list () should be
    # converted to undef in scalar context, and used correctly in list context
    # Using undef will add (undef) to any list which is being accumulated from
    # our return result.
}

sub InsideOrTouching ($$) {
    my $bbox = $_[0]->BBox();
    ($bbox and inside_or_touching $_[1], $bbox) ? $_[0] : ();
}

sub Intersect ($$) {
    my $bbox = $_[0]->BBox();
    ($bbox and intersect $_[1], $bbox) ? $_[0] : ();
}

sub IntersectOrTouching ($$) {
    my $bbox = $_[0]->BBox();
    ($bbox and intersect_or_touching $_[1], $bbox) ? $_[0] : ();
}

sub Outside ($$) {
    my $bbox = $_[0]->BBox();
    ($bbox and outside $_[1], $bbox) ? $_[0] : ();
}

1;
__END__

=head1 NAME

RISCOS::DrawFile::Common

=head1 SYNOPSIS

Methods common to DrawFiles and objects within DrawFiles.

=head1 DESCRIPTION

C<RISCOS::DrawFile::Common> provides methods common to DrawFiles and to objects
within DrawFiles. It provides one function C<drawplus_split_type>.

=head2 drawplus_split_type

	$type = drawplus_split_type 0x00010402;		# $type = 0x02
	($type, $layer, $flags, $spare) = drawplus_split_type $type;

C<drawplus_split_type> takes an integer and interprets it as a DrawPlus
"extended tag". In scalar context it returns the standard draw type, in array
context the list (type, layer, flags, spare), as described in the DrawPlus
documentation.

=head2 Methods

=over 4

=item Clone

returns a copy of this object. Derived class implementors should see
L<RISCOS::Clone> for the cloning teqnique, and the B<assumptions> it makes.

=item BBox

returns a reference to an array giving the bounding box, or C<undef> if there is
is no bounding box for this object (I<i.e.> font tables, empty paths, option
objects). Note that option objects and empty paths store a bounding box of
(0,0,0,0) when saved. C<BBox> will attempt to call C<BBox_Calc> (which the
derived class B<must> provide) if the bounding box is currently unknown.

As the returned array reference B<is> the internal copy of the bounding box it
must not be modified.

=item Translate <x> <y> [<barf_func>]

translates the object by (I<x>, I<y>), or calls
&I<barf_func> (I<object>, I<x>,  I<y>) for any object for which translation is
not possible (I<i.e.> unknown objects and tagged objects, as the tag data might
contain co-ordinate information. If I<barf_func> is undefined a warning is
issued, while an empty string silences any warning, and assumes that altering
the bounding box of any unknown object is sufficient to perform the translation.

=item Inside <bbox>

checks whether this object is entirely within the bounding box (passed as an
array reference). Returns a reference to the object if it is, an empty list if
it touches, intersects or lies outside the box. The empty list C<()> is
converted to C<undef> in scalar context, whereas returning C<undef> in list
context would generate a one element list C<(undef>) which can cause surprises.

=item InsideOrTouching <bbox>

checks whether this object is entirely within or touching the bounding box
(passed as an array reference). Returns a reference to the object if it is,
C<()> if it intersects or lies outside the box.

=item Intersect <bbox>

checks whether any of this object's bounding box is within the bounding box
(passed as an array reference). Returns a reference to the object if it is,
C<()> if it lies outside the box (including just touching the edge).

=item IntersectOrTouching <bbox>

checks whether any of this object's bounding box is within the bounding box, or
is touching the box (passed as an array reference). Returns a reference to the
object if it is, C<()> if it lies outside and is not touching the box.

=item Outside <bbox>

checks whether this object's bounding box is entirely outside the bounding box
(passed as an array reference). Returns a reference to the object if it is,
C<()> if any part of the bounding box touches or intersects the box.

=back

=head2 Methods derived classes must supply

In addition to the overriding above methods where appropriate (in particular
C<Type>) derived classes (DrawFile and DrawFile objects) must provide the
following methods. All objects within DrawFiles provide further classes as
specifed in C<RISCOS::DrawFile::Object>.

=over 4

=item BBox_Calc

(re)calculates the bounding box, returning a reference to an array, or undef if
there is no bounding box. As it has no idea about the data it contains
C<OpaqueObject> simply returns the bounding box it was given when it was called.

=item PrePack <hash_reference>

a hook to perform calculations immediately before saving a DrawFile. The hash
reference is used to store the names of fonts needed in the FontTable, keys are
font names, values the number of text objects that use that font (see C<PrePack>
in C<RISCOS::DrawFile::Text> if you really must know).

=item Pack <undef>, fonttable, ...

returns a scalar containing the object packed ready to save into a DrawFile.

=item Write <filehandle>, <fonttable>, ...

writes the object to the given filehandle. C<Write> should return true unless
there was an error.

=back

=head1 BUGS

Not tested enough.

=head1 AUTHOR

Nicholas Clark <F<nick@unfortu.net>>
