package Slim::Buttons::Search;

# $Id: Search.pm 11972 2007-05-12 07:32:19Z kdf $

# SlimServer Copyright (c) 2001-2007 Logitech.
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License,
# version 2.

=head1 NAME

Slim::Buttons::Search

=head1 DESCRIPTION

L<Slim::Buttons::Search> is a SlimServer module to create a UI for searching
the user track database.  Seach by ARTIST, ALBUM and SONGS is added to the home 
menu structure as well as options for adding to the top level.  Search input uses the 
INPUT.Text mode.

=cut

use strict;
use File::Spec::Functions qw(:ALL);
use File::Spec::Functions qw(updir);
use Slim::Buttons::Common;
use Slim::Display::Display;

# button functions for search directory
my @defaultSearchChoices = qw(ARTISTS ALBUMS SONGS);
my $rightarrow = Slim::Display::Display::symbol('rightarrow');

our %current    = ();
our %context    = ();
our %menuParams = ();

sub init {
	my %subs = (

		'SEARCH_FOR_ARTISTS' => sub {
			return Slim::Buttons::Search::searchFor(shift, 'ARTISTS');
		},

		'SEARCH_FOR_ALBUMS' => sub {
			return Slim::Buttons::Search::searchFor(shift, 'ALBUMS');
		},

		'SEARCH_FOR_SONGS' => sub {
			return Slim::Buttons::Search::searchFor(shift, 'SONGS');
		}
	);

	#
	%menuParams = (
		'SEARCH' => {
			'listRef' => \@defaultSearchChoices,
			'stringExternRef' => 1,
			'header' => 'SEARCH',
			'stringHeader' => 1,
			'headerAddCount' => 1,
			'callback' => \&searchExitHandler,
			'overlayRef' => sub { return (undef, Slim::Display::Display::symbol('rightarrow')) },
			'overlayRefArgs' => '',
			'submenus' => {

				'ARTISTS' => {
					'useMode' => 'INPUT.Text',
					'header' => 'SEARCHFOR_ARTISTS',
					'stringHeader' => 1,
					'cursorPos' => 0,
					'charsRef' => 'UPPER',
					'numberLetterRef' => 'UPPER',
					'callback' => \&searchHandler,
				},

				'ALBUMS' => {
					'useMode' => 'INPUT.Text',
					'header' => 'SEARCHFOR_ALBUMS',
					'stringHeader' => 1,
					'cursorPos' => 0,
					'charsRef' => 'UPPER',
					'numberLetterRef' => 'UPPER',
					'callback' => \&searchHandler,
				},

				'SONGS' => {
					'useMode' => 'INPUT.Text',
					'header' => 'SEARCHFOR_SONGS',
					'stringHeader' => 1,
					'cursorPos' => 0,
					'charsRef' => 'UPPER',
					'numberLetterRef' => 'UPPER',
					'callback' => \&searchHandler,
				}
			}
		}
	);

	for my $name (sort keys %menuParams) {
		Slim::Buttons::Home::addMenuOption($name,$menuParams{$name});
	}	

	for my $name (sort keys %subs) {
		Slim::Buttons::Home::addMenuOption($name,$subs{$name});
	}
}

sub searchExitHandler {
	my ($client,$exitType) = @_;
	
	$exitType = uc($exitType);

	if ($exitType eq 'LEFT') {
		my $oldlines = $client->curLines();

		Slim::Buttons::Home::jump($client, 'SEARCH');
		while (Slim::Buttons::Common::popMode($client, 1)) {};
		Slim::Buttons::Common::pushMode($client, 'home');

		$client->pushRight($oldlines, $client->curLines());

	} elsif ($exitType eq 'RIGHT') {

		my $current = $client->param('valueRef');

		my %nextParams = searchFor($client, $$current) ;

		Slim::Buttons::Common::pushModeLeft($client, $nextParams{'useMode'}, \%nextParams);
	}
}

sub searchFor {
	my $client = shift;
	my $search = shift;
	my $value  = shift;
 
	$context{$client} = (defined($value) && length($value)) ? ($value) : ('A');

	my %nextParams = %{$menuParams{'SEARCH'}{'submenus'}{$search}};

	$nextParams{'valueRef'} = \$context{$client};

	$client->searchFor($search);

	return %nextParams;
}

sub searchHandler {
	my ($client,$exitType) = @_;

	$exitType = uc($exitType);

	if ($exitType eq 'BACKSPACE') {
		Slim::Buttons::Common::popModeRight($client);
	} else {
		$context{$client} =~ s/$rightarrow//;
		startSearch($client);
	}
}

sub startSearch {
	my $client = shift;
	my $mode = shift;
	my $oldlines = $client->curLines();

	my $term = searchTerm($client);
	$client->showBriefly($client->string('SEARCHING'));

	if ($client->searchFor eq 'ARTISTS') {

		Slim::Buttons::Common::pushMode($client, 'browsedb', {
			'search'    => $term,
			'hierarchy' => 'contributor,album,track',
			'level'     => 0,
		});

	} elsif ($client->searchFor eq 'ALBUMS') {

		Slim::Buttons::Common::pushMode($client, 'browsedb', {
			'search'    => $term,
			'hierarchy' => 'album,track',
			'level'     => 0,
		});

	} else {

		Slim::Buttons::Common::pushMode($client, 'browsedb', {
			'search'    => $term,
			'hierarchy' => 'track',
			'level'     => 0,
		});
	}

	$client->pushLeft($oldlines, $client->curLines());
}

sub searchTerm {
	my $client = shift;

	# do the search!
	@{$client->searchTerm} = split(//, Slim::Utils::Text::ignoreCaseArticles($context{$client}));

	my $term = '';

	# Bug #738
	# Which should be the default? Old - which is substring always?
	if (Slim::Utils::Prefs::get('searchSubString')) {
		$term = '%';
	}

	for my $a (@{$client->searchTerm}) {

		if (defined($a) && ($a ne $rightarrow)) {
			$term .= $a;
		}
	}

	$term .= '%';

	# If we're searching in substrings, return - otherwise append another
	# search which is effectively \b for the query. We might (should?)
	# deal with alternate separator characters other than space.
	if (Slim::Utils::Prefs::get('searchSubString')) {
		return [ $term ];
	}

	return [ $term, "% $term" ];
}

=head1 SEE ALSO

L<Slim::Buttons::Common>

L<Slim::Buttons::Input::Text>

L<Slim::Player::Client>

=cut

1;

__END__
