package RISCOS::DrawFile;

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

require RISCOS::DrawFile::Container;

use RISCOS::File 0.03 qw(load filetype settype);
use Carp;
use IO::File;

$VERSION = 0.04;
@ISA = 'RISCOS::DrawFile::Container';

# 0.04
# Add undef as a possible [] of contents, and as a Filetype(undef)
# 0.03
# Write blank DrawFiles.
# Add Write to documentation

sub group {new RISCOS::DrawFile::Group @_}

sub new {
    my $proto = shift;
    my $class = ref($proto) || $proto;
    
    if (defined $_[0] and ref ($_[0]) eq $class) {
	return $_[0]->Clone();
	# Copy it and all done [note that this is derived class safe :-) ]
    }

    my $self = $class->SUPER::new();

    my ($contents, $oldfont, $minor, $creator, $filetype);
    
    if (ref($_[0]) eq 'ARRAY' or !defined $_[0]) {
	($contents, $creator, $oldfont, $filetype) = @_;
	$contents = [] unless defined $contents;
	$filetype = 0xAFF unless defined $filetype;
	$minor = 0;
    } else {
	# arg 0 is filename (whatever)
	# arg 1 is type splitfunction
	my $split = $_[1];
	$split = \&RISCOS::DrawFile::Common::drawplus_split_type
	  if defined $split and $split eq '+';
	my ($file, $a, $b, $load, $exec) = &load;	# Pass on our arguments
	
	unless (defined $file) {
	    carp 'Could not load file' if $^W;
	    return undef;
	}
	$filetype = defined $load ? filetype ($load) : 0xAFF;
	my ($tag, $major);	# Ignore BBox in file header - will recalculate
	($tag, $major, $minor, $creator) = unpack 'a4I2A12', $file;
	unless ($tag eq 'Draw') {
	    carp "File is not a DrawFile ('$tag')" if $^W;
	    return undef;
	}
	unless ($major == 201) {
	    carp "DrawFile major version $major != 201" if $^W;
	    return undef;
	}
	
	($contents, undef, $oldfont) = $self->_split_drawobjs
	  (\(substr $file, 40), $split, \$oldfont, $self->Objfunc(),
	   $self->can ('Second_Font_Table'), $self->can ('Unknown_Obj'));
    }
    $self->Stuff ($contents);
    $self->{'__CREATOR'} = defined $creator ? $creator : "PerlDraw$VERSION";
    $self->{'__MINOR'} = $minor;
    $self->{'__FONT'} = defined ($oldfont) ? $oldfont : [];
    $self->{'__FILETYPE'} = $filetype;
        
    bless ($self, $class);
}

# Really not tested.
sub Pack {
    my $self = shift;

    my $used_fonts = {};
    my $bbox = $self->PrePack($used_fonts);
    $_[1] = RISCOS::DrawFile::FontTable->new($used_fonts);
    pack ('A4I2A12i4', 'Draw', $self->Major(), $self->Minor(), $self->Creator(),
	  ($bbox ? @$bbox : (0,0,0,0)))
      . $_[1]->Pack (@_)	# Fonttable
      . $self->SUPER::Pack (@_);
}

sub Write {
    local $\; undef $\;
    my $self = shift;
    $self = RISCOS::DrawFile->new ([])
      if !defined $self or $self eq __PACKAGE__;
    # Create an empty DrawFile to write

    unless (ref($_[0]) ? (ref($_[0]) eq 'GLOB'
			  || UNIVERSAL::isa($_[0], 'GLOB')
			  || UNIVERSAL::isa($_[0], 'IO::Handle'))
		       : (ref(\$_[0]) eq 'GLOB')) {
	my $file = shift;
	unshift @_ , new IO::File ">$file";
	croak "Unable to open '$file': $!" unless $_[0];
	# Can't overwrite $_[0] as it may be read only.
    }
    my $used_fonts = {};
    my $bbox = $self->PrePack($used_fonts);
    my $good = print {$_[0]} pack 'A4I2A12i4', 'Draw', $self->Major(),
						$self->Minor(),
						$self->Creator(),
						($bbox ? @$bbox : (0,0,0,0));
    # Do the fonttable here.
    if (%$used_fonts) {
        $_[1] = RISCOS::DrawFile::FontTable->new($used_fonts);
        $_[1]->Write (@_);
    }
    $good = settype ($self->{'__FILETYPE'}, $_[0])
      if defined $self->{'__FILETYPE'};
    $good & $self->SUPER::Write (@_);
}

sub Major { 201; }
sub Minor {
    my $self = shift;
    my $minor = $self->{'__MINOR'};
    $self->{'__MINOR'} = $_[0] if defined $_[0];
    $minor;
}
sub Creator {
    my $self = shift;
    my $creator = $self->{'__CREATOR'};
    $self->{'__CREATOR'} = $_[0] if defined $_[0];
    $creator;
}

sub FileType {
    my $self = shift;
    my $filetype = $self->{'__FILETYPE'};
    $self->{'__FILETYPE'} = $_[0] if @_;
    $filetype;
}
1;
__END__

=head1 NAME

RISCOS::DrawFile

=head1 SYNOPSIS

A class to manipulate DrawFiles

=head1 DESCRIPTION

C<RISCOS::DrawFile> provides a class to manipulate DrawFiles. It is derived from
C<RISCOS::DrawFile::Container> (which provides all the really cool methods),
and provides the following additional methods.

=over 4

=item new [<contents>, [<creator>, [<oldfont>, [<filetype>]]]]

=item new <filename>, [<split_function>]

creates a new DrawFile. If the first argument is C<undef> or a reference to an
array it is taken to be an array of objects derived from
<RISCOS::DrawFile::Object> which are to be used as the contents. Otherwise the
first argument is passed to C<RISCOS::File::load>, so I<filename> can actually
be a filehandle, or the file data to use.

I<creator> defaults to C<"PerlDraw$VERSION">, which at 12 characters can cause
problems for some drawing programs (I<e.g.> DrawPlus prior to 2.41). I<oldfont>
if defined should be a reference to an array of fonts found when loading the
DrawFile and isn't really used, as C<RISCOS::DrawFile::TextObject> objects each
store their own font. I<filetype> defaults to 0xAFF (DrawFile).

I<split_function> is passed as the second argument to
C<RISCOS::DrawFile::Object::new> for each object found in the DrawFile to
process the DrawFile object type to extract layer information. If defined this
should either be a code reference, or the string 'C<+>' to use
C<RISCOS::DrawFile::Common::drawplus_split_type>

=item Write <filename>

=item Write <filehandle>

writes the DrawFile to the given filename or filehandle, and attempts to set the
file's filetype to the type set/returned with C<FileType>. Calling this Write as
a class method will write an empty DrawFile:

    
    Write RISCOS::DrawFile ('DrawFile')    # Write a blank DrawFile
    RISCOS::DrawFile->Write ('DrawFile')   # There's More Than One Way To Do It

=item Major

returns the major version number of this DrawFile, which will always be 201.
C<new> will correctly refuse to load DrawFiles with any other major version
number.

=item Minor [<version>]

returns the minor version number of this DrawFile. If an defined argument is
supplied sets the minor verion to this, and returns the old value.

=item Creator [<creator>]

returns the creator string for this DrawFile. If an defined argument is
supplied sets the creator, and returns the old value. Creator strings are
truncated or padded with B<spaces> to give 12 characters when the DrawFile is
written out. Note that 12 character creator names can cause problems for poorly
written programs.

=item FileType [<filetype>]

returns the filetype that C<Write> will give this file. If I<filetype> is
supplied this value is set, and the old value returned. The value is stored
verbatim, relying on C<RISCOS::File::settype> to do any conversion necessary.
If the filetype is C<undef> then C<Write> will not attempt to set the filetype.

Note that while C<RISCOS::DrawFile> has no problem loading Equasor files, the
file written out will have the FontTable as first object, rather than the tagged
empty path that Equasor expects, and so Equasor will refuse to recognise the
file. Regrettably the transparency that C<RISCOS::DrawFile> by automaticaly
tabulating fonts and creating a FontTable means that it is not possible for this
general purpose class to ensure that the FontTable is at a specific loation
within the file. (Well, not without breaking various other programs that wrongly
expect the FontTable to be the B<very> first object in a file. RTFM carefully.)

=back

=head1 BUGS

Not tested enough. Especially C<Pack>

=head1 AUTHOR

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