package A2B::CLI;

use A2B;

use File::Path;

use GetOpt::OO
	'?'	=> 'help',
	l	=> 'list',
	O	=> 'options',
	A	=> 'args',
	p	=> 'path',
	g	=> 'grep',
	G	=> 'nogrep',
	m	=> 'type',
	x	=> 'extension',
	n	=> 'names',
	c	=> 'content',
	C	=> 'nocontent',
	i	=> 'in',
	o	=> 'out',
	f	=> 'from',
	t	=> 'to',
	d	=> 'dir',
	D	=> 'tempdir',
	q	=> 'quiet',
	Q	=> 'silent',
	y	=> 'force',
	;

@ISA = "GetOpt::OO";
use strict;

sub new {
	my ($package, $a2b) = @_;
	ref $a2b or
		die "usage: A2B::CLI->new(\$a2b)\n";
	my $this = bless {
		path => 0,
		a2b => $a2b,
	}, $package;
	return $this;
}

# < methods that can be called from the options ...

# GetOpt::OO really SUCKS at the moment!  I'm sure it was a good idea, just not
# done quite right...  this "proxy" object should not be here at all...  l8r

# I was using Pod::Usage, but it's only in perl 5.6

sub help {
	open HELP, $0 or
		die "cannot open `$0' to read help!";

	my $c == 0;
	while (<HELP>) {
		last if /^=head1 OPTIONS/;
		print if /^=head1 SYNOPSIS/ .. 0 and $c++ >= 2;
	}
	exit 0;
}

sub in {
	my $self = shift;
	$self->{in} = [@_];
}

sub out {
	my $self = shift;
	$self->{out} = shift;
	@_ and die "usage: --out=foo\n";
}

sub path {
	my $self = shift;
	$self->{path} = shift;
	$self->{path} > 0 and !@_ or
		die "usage: --path=9\n";
}

sub dir {
	my $self = shift;
	$self->{dir} = shift;
	defined $self->{dir} and !@_ or
		die "usage: --dir=workdir\n";
}

sub tempdir {
	my $self = shift;
	$self->{dir} = shift;
	defined $self->{dir} and !@_ or
		die "usage: --tempdir=workdir\n";
	$self->{dir_temp} = 1;
}

sub from {
	my $self = shift;
	$self->{from} = shift;
	defined $self->{from} and !@_ or
		die "usage: --from=mime/type\n";
}

sub to {
	my $self = shift;
	@_ or 
		die "usage: --to: mime/type ...\n";
	$self->{to} = [@_];
}

sub list {
	my $self = shift;
	$self->{list} = shift;
	@_ and die "usage: --list or --list=3\n";
}

sub args {
	my $self = shift;
	$self->{list} = shift;
	@_ and die "usage: --args or --args=3\n";
	$self->{details} = 2;
}

sub options {
	my $self = shift;
	$self->{list} = shift;
	@_ and die "usage: --details or --details=3\n";
	$self->{details} = 1;
}

sub type {
	my $self = shift;
	$self->{type} = 1;
}

sub names {
	my $self = shift;
	$self->{names} = 1;
}

sub extension {
	my $self = shift;
	$self->{type} = 1;
	$self->{extension} = 1;
}

sub content {
	my $self = shift;
	$self->{content} = 1;
}

sub nocontent {
	my $self = shift;
	$self->{content} = -1;
}

sub quiet {
	my $self = shift;
	$self->{a2b}->{quiet} = 1;
}

sub silent {
	my $self = shift;
	$self->{a2b}->{quiet} = 2;
}

sub force {
	my $self = shift;
	$self->{a2b}->{force} = 1;
}

sub grep {
	my $self = shift;
	$self->{a2b}->{grep} = [map qr/$_/, @_];
}

sub nogrep {
	my $self = shift;
	$self->{a2b}->{nogrep} = [map qr/$_/, @_];
}

# > end methods that can be called from options

sub run {
	my $self = shift;

	if ($self->{type}) {
		$self->do_type(@_);
		return;
	}

	if (@_) {
		if (@_ == 2 && (!$self->{in} || !@{$self->{in}}) && !$self->{out}) {
			$self->{in} = [$_[0]];
			$self->{out} = $_[1];
		} else {
			die "extra arguments not understood: @_\n";
		}
	}

	defined $self->{to} or
		($self->{out} and $self->{to} = $self->{a2b}->identify_by_extension($self->{out})) or
		die "a `to' type must be specified\n";

	defined $self->{from} or
		($self->{in} and @{$self->{in}} >= 1 and $self->{from} = $self->identify($self->{in}[0])) or
		die "a `from' type must be specified\n";

	if (exists $self->{list}) {
		$self->do_list();
	} else {
		$self->do_convert();
	}
}

sub do_list {
	my $self = shift;
	# we output a list of paths
	my $paths = $self->{a2b}->paths($self->{from}, $self->{to}, $self->{list});
	my $i = 1;
	for my $path (@$paths) {
		if (!$self->{path} || $i == $self->{path}) {
			printf "%3d (%5.3f)  %s\n", $i, $path->goodness, $path->as_string($self->{details});
		}
		++$i;
	}
}

sub do_convert {
	my $self = shift;

	defined $self->{in} or
		die "an `in' file must be specified";

	# we do a conversion
	$self->{path} ||= 1;
	my $paths = $self->{a2b}->paths($self->{from}, $self->{to}, $self->{path});
	my $path = $paths->[$self->{path}-1] or
		die "there is no conversion path".($self->{path} != 1 ? "numbered `$self->{path}'" : "");

	-e $self->{dir} && $self->{dir_temp} and
		die "tempdir `$self->{dir}' already exists; delete it, or use --dir\n";
	$self->{a2b}->convert($path, $self->{in}, $self->{out}, $self->{dir});
	if ($self->{dir_temp} && $self->{dir}) {
		rmtree $self->{dir} or
			warn "cannot rmtree `$self->{dir}': $!";
	}
}

sub do_type {
	my $self = shift;
	my @files = @_;

	for my $file (@files) {
		my $type = $self->identify($file);
		$type ||= "";
		if ($self->{extension}) {
			$type = $self->{a2b}->type($type)->extension;
		}
		if ($self->{names}) {
			print "$file\t$type\n";
		} else {
			print "$type\n";
		}
	}
}

sub identify {
	my $self = shift;
	my $file = shift;
	my $type;
	if ($self->{content} == 1) {
		$type = $self->{a2b}->identify_by_content($file);
	} elsif ($self->{content} == -1) {
		$type = $self->{a2b}->identify_by_extension($file);
	} else {
		$type = $self->{a2b}->identify($file);
	}
	return $type;
}

1
