package Audio::Tagger::File;
use strict;
use warnings;

# Audio::Tagger::Meta usses Class::Accessor, which for the time being does not
# seem to conflict with Class::Accessor::Fast
use base qw(Audio::Tagger::Meta);

# TODO try and auto dectect wich file types we can support!
use Audio::Tagger::File::MP3;
use Audio::Tagger::File::Ogg;
use Audio::Tagger::Error;
use File::Spec;

# Prevent File::Copy from exporting functions as we want to define our own
# move()
use File::Copy qw//;


#	print "Filename:     " . $file->filename   . "\n";
#	print "Basename:     " . $file->base       . "\n";
#	print "Folder:       " . $file->folder     . "\n";
#	print "Files in dir: " . $file->count      . "\n";
#	print "Extension:    " . $file->ext        . "\n";
#	print "Samplerate:   " . $file->samplerate . "\n";
#	print "Bitrate:      " . $file->bitrate    . "\n";

sub open {
	# TODO Try and load varoius modules at runtime at provide a function
	# "supported"
	my ($class, $filename) = @_;

	my $self;

	throw Audio::Tagger::File::Error("No file specified")               unless defined $filename;
	throw Audio::Tagger::File::Error("File does not exsist: $filename") unless -f $filename;
	throw Audio::Tagger::File::Error("File not readable: $filename")    unless -r $filename;

	my ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,$atime,$mtime,$ctime,$blksize,$blocks) = stat($filename);
	throw Audio::Tagger::File::Error("File is zero bytes long: $filename") if $size == 0;

	# Samplerate and bitrate should be handled by subclasses.
	if ($filename =~ m/\.mp3$/i ) {
		$self = Audio::Tagger::File::MP3->new($filename);
		$self->{ext} = "mp3";
	}
	elsif ($filename =~ m/\.ogg$/i ) {
		$self = Audio::Tagger::File::Ogg->new($filename);
		$self->{ext} = "ogg";
	}
	else {
		if ($filename =~ m/\.(.+?)$/) {
			throw Audio::Tagger::File::Error("$1 filetype is not supported");
		}
		else {
			throw Audio::Tagger::File::Error("Couldn't determine filetype of $filename");
		}
	}

	$self->{filename} = $filename;

	$filename = File::Spec->rel2abs($filename);
	my ($volume,$directories,$file) = File::Spec->splitpath($filename);

	# TODO add volume
	$self->{folder}         = $directories;
	$file =~ s/\.(ogg|mp3)$//;
	$self->{base}           = $file;
	$self->{absname}        = $filename;

	my $ext = $self->{ext};


	$self->{size} = $size;

	# =()= forces the glob to scalar contect, ie number of elements
	$self->{count} =()= <$directories/*.$ext> if defined $ext;

	return $self;
}

#FIXME this function shouldn't be in the lib!
sub move {
	my ($self, $dest, $options) = @_;

	my $file = $self->absname;
	my $ext  = $self->ext;

	$dest .= ".$ext" if not $dest =~ m/\.\Q$ext\E$/;

	if ($file ne $dest) {
		my @folders = split /\//, $dest;
		pop @folders;

		# Create missing folders TODO cross-platform...
		my $folder = "/";
		while (@folders) {
			$folder .= shift(@folders) . "/";
			(mkdir $folder or throw Audio::Tagger::File::Error("Could not create folder $folder")) unless -d $folder;
		}

		# Name file [0-9].ext if the file allready exsists TODO make
		# this optional?
		$dest =~ s/(?:\.(\d+))?\.(\w+)$/sprintf(".%d.%s",($1||0)+1,$2);/e while -e $dest;

		File::Copy::move($file,$dest)
			or throw Audio::Tagger::File::Error("Could not move file $file to $dest");

		# Use filename  function to ensure that all the file variables
		# are updatet
		# TODO this way ouf keeping data in sync i s deprecated
		$self->filename($dest);

		# Try to clean up empty folders TODO make optional
		@folders = split /\//, $file;
		pop @folders;

		while (@folders) {
			rmdir join "/", @folders or last;
		}
	}

	return $dest;
}

sub new {
	my ($class, $file) = @_;

	my $self = {};
	bless $self, $class;

	$self->_open($file) if defined $file;

	return $self;
}

sub filename   { return shift->{filename} }
sub folder     { return shift->{folder} }
sub base       { return shift->{base} }
sub ext        { return shift->{ext} }
sub absname    { return shift->{absname} }
sub count      { return shift->{count} }
sub samplerate { return shift->{samplerate} }
sub bitrate    { return shift->{bitrate} }
sub size       { return shift->{size} }

1;

__END__

=head1 NAME

Audio::Tagger::File - Open and manipulate audio files.

=head1 SYNOPSIS

	my $file = Audio::Tagger::File->open($filename);

	print "Artist: " . $file->artist->name;

	# Change title
	$file->track->name("New title");

	# Save changes to file
	$file->save;

=head1 DESCRIPTION



=head1 METHODS

=over

=item C<open>

Open supplied file and load metadata into memory

=item C<move>

Moves file safely and makes sure the create needed folders and clean up empty
folders.

	$file->move($new_filename);

This implies that any directories that are needed will be created , and if the
file allready exsists it will not be replaced but the new filename will become
test.1.mp3 instead of test.mp3.

Throws an Audio::Tagger::File error if something goes, ie can't create folder
or move file

=item C<base>

Return the basename of file (see L<File::Basename>)

=item C<absname>

Return absolute path + filename

=item C<filename>

Return filename that was passed to open

=item C<folder>

Return path to folder containing file.

=item C<ext>

Return extension of file.

=item C<bitrate>

Get the bitrate of the audio file.

=item C<samplerate>

Get the samplrate of the audio-file

=item C<count>

Number of files in the same folder as file with the same extension

=item C<size>

Size of file in bytes.

=back

=head1 SEE ALSO

Audio::Tagger::Meta

=cut
