package Audio::Tagger;

use strict;
use warnings;
use vars qw($VERSION);

$VERSION = "0.01";

use Audio::Tagger::File;
use Audio::Tagger::Lookup;
use Audio::Tagger::Meta;
#use Audio::Tagger::Match;
use Audio::Tagger::Error;

use Data::Dumper::Simple;

# TODO our should be based on File!?
use base qw/Audio::Tagger::Meta/;


# People should use Audio::Tagger->lookup insted of new.
sub new {
	# Create new tagger object and bless with Audio::Tagger as type
	my $type = shift;
	my $self = {};
	bless $self, $type;
	return $self;
}

sub lookup {
	my ($self, $file, $config) = @_;

	unless (ref($self) eq "Audio::Tagger") {
		$self = Audio::Tagger->new();
	}

	if (defined $file) {
		$self->{file}  = Audio::Tagger::File->open($file);
		$self->_meta($self->{file});
	}

	# TODO this check should be done in File!!
	throw Audio::Tagger::Error("Could not find file to lookup.") if not defined $self->{file};

	# Send query to MusicBrainz through Samfundet::Query and get scored and
	# sorted result back, if query fails warn should contain the
	# the reason.

	# TODO Not quite sure about if the switch to non-00 was a good idea...
	my @result = Audio::Tagger::Lookup::lookup($self);

	# if musicbrainz id's are set, but we didn't get any results then try again
	# most likely the track/artist/album has been merged into something else (and then the id is lost)

	# TODO this should be moved to Lookup! (also goes for scoring)

	if (!@result && (defined $self->track->id || defined $self->album->id || defined $self->artist->id)) {
		$self->track->id ("");
		$self->album->id ("");
		$self->artist->id("");
		@result = Audio::Tagger::Lookup::lookup($self);
	}

	# Add score and sort result
	for my $res (@result) {
		last if not defined $res;

		my $score = Audio::Tagger::Lookup::score($self, $res, $config->{ignore});
		$res->track->score($score);
	}
	@result = sort {$b->track->score <=> $a->track->score} @result;

	$self->{result} = \@result;

	return $self;
}

sub results {
	throw Audio::Tagger::Error('Incorrect, usage: $tagger->results()')
		if @_ != 1;

	my $self =  shift;
# FIXME
#	throw Audio::Tagger::Error('Object not blessed as Audio::Tagger')
#		if !UNIVERSAL::isa('Audio::Tagger', $self);

	if (not defined $self->{result}) {
		record Audio::Tagger::Error('No results present in Audio::Tagger::Object');
		return;
	}

	return @{$self->{result}} if wantarray;
	return   $self->{result};
}

sub select {
	throw Audio::Tagger::Error('Incorrect, usage: $tagger->select($meta)')
		if @_ != 2;

	my ($self, $meta) = @_;
# FIXME
#	throw Audio::Tagger::Error('Object not blessed as Audio::Tagger')
#		if !UNIVERSAL::isa('Audio::Tagger', $self);
# FIXME keep this check here? or move error checking to _meta?
#	throw Audio::Tagger::Error('Meta not of type hash')
#		if ref $meta ne 'HASH';

	$self->_meta($meta);

	# TODO move to Audio::Tagger::Lookup...
	shift @{$self->{last}} if defined $self->{last} &&  scalar @{$self->{last}} > 2;
	push @{$self->{last}}, $meta;

	return 1;
}

## FIXME Should $self have base 'Audio::Tagger::File' ??
sub save {
	throw Audio::Tagger::Error('Incorrect, usage: $tagger->save()')
		if @_ != 1;
	my $self = shift;

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

	$file->_meta($self);
	$file->save;

	# TODO "Fix" last support! (register 'last' with lookup module)
	my $meta = pop @{$self->{last}} if defined $self->{last};
	$meta->_meta($self);
	push @{$self->{last}}, $meta;
}

sub file {
	return shift->{file};
}

1;

__END__

=pod

=head1 NAME

Tagger a framework designed for scanning and tagging of music-collections

=head1 SYNOPSIS

	my $tagger = Audio::Tagger->scan($file);

	my @result = $tagger->result();

	$tagger->select;
	$tagger->save;

=head1 DESCRIPTION

Nice long rambel about what we want this class to do...

=head1 METHODS

=head2 Prossesing files

=over

=item lookup

Lookup given file and return new Audio::Tagger object, throws errors if something went wrong.

	my $matches = $tagger->lookup($file);

=back

=head3 Viewing results

=over

=item result

Returns an anonymous hash ref containing the results from the lookup.

Will return an array with all results unnless given a spesific result
number as the first argument, returns undef if result $num isn't found.

	my $result = $tagger->result(3);
	print "Track name: " .           $result->track->name . "\n";
	print "Albumartist sortname: " . $result->album->artist->sortname . "\n";

	# or ...

	for my $result ($tagger->result) {
		print "Artist Id: " . $result->artist->id . "\n";
	}

Results are thus either a Audio::Tagger::Meta object or and array of these.

See: L<Audio::Tagger::Meta>

=back

=head3 Selecting and or modifing result to use

=over

=item select

Load result into main tagger object, changes are not made permanent until C<save> is called.

Returns undef if result $num doesn't exsist, see C<result> for information about how to view results.

	$tagger->select(2);

If no paramter is given the default is always result 0, ie the best result after scoring.

=item artist

Print information kept in Audio::Tagger::Meta:Artist object:

	print "Name:          " . $tagger->artist->name . "\n";
	print "Sortname:      " . $tagger->artist->sortname . "\n";
	print "Musibrainz ID: " . $tagger->artist->id . "\n";

Change the values:

	$tagger->artist->name("The Cure");
	$tagger->artist->sortname("Cure, The");
	$tagger->artist->name("69ee3720-a7cb-4402-b48d-a02c366f2bcf");

Access to the albumartist is done in the same way:

	$tagger->album->artist->name("Various Artists");

=item album

	print "Name:             " . $tagger->album->name . "\n";
	print "Trackcount:       " . $tagger->album->count . "\n";
	print "Musibrainz ID:    " . $tagger->album->id . "\n";
	print "Albumartist name: " . $tagger->album->artist->name . "\n";

=item track

	print "Name:             " . $tagger->track->name . "\n";
	print "Track number:     " . $tagger->track->number . "\n";
	print "Musibrainz ID:    " . $tagger->track->id . "\n";
	print "Length:           " . $tagger->track->duration . "\n";

=back

=head2 Saving changes and moving files

=over

=item save

Commit any changes to file; no changes will be made unless you have told the
tagger which result you want to save with C<select>, or by directly modifying
the file data.

	$tagger->save;

=item file

Accessor for the file that we are currently looking up.

	print $tagger->file->filename . "\n";

See L<Audio::Tagger::File> for more information.

=back

=head1 BUGS

...

