package LIMS::Controller::Search;

use base 'LIMS::Base';

use Moose;
	with (
		'LIMS::Controller::Roles::History',
		'LIMS::Controller::Roles::DataMap',
		'LIMS::Controller::Roles::RecordHandler',
		'LIMS::Controller::Roles::ResultHandler',
		'LIMS::Controller::Roles::SearchConstraint', # generate_search_constraints()
	);
__PACKAGE__->meta->make_immutable(inline_constructor => 0);

use Data::Dumper;

# can't use __PACKAGE__->authz->authz_runmodes() - crashes on non-logged-in user

#-------------------------------------------------------------------------------
sub default : StartRunmode {
    my $self = shift; $self->_debug_path($self->get_current_runmode);
    my $errs = shift; $self->stash(errs => $errs);

	return $self->forbidden() unless $self->user_can('search');

    my $trials = $self->model('ClinicalTrial')->get_trials;

    $self->tt_params( trials => $trials );

    return $self->tt_process($errs);
}

#-------------------------------------------------------------------------------
# recieves url for a single record, by request.id:
sub load : Runmode {
    my $self = shift; $self->_debug_path($self->get_current_runmode);
	return $self->forbidden() unless $self->user_can('search');

    my $id = $self->param('id') || return $self->forward('default');

    return $self->_get_single_record($id);
}

#-------------------------------------------------------------------------------
sub do_search : Runmode {
    my $self = shift; $self->_debug_path($self->get_current_runmode);

	return $self->forbidden() unless $self->user_can('search');

	my $dfv = $self->check_rm('default', $self->validate('search') )
	|| return $self->dfv_error_page;

    my $data = $dfv->valid; # $self->debug($data);

    my $search_constraints = $self->generate_search_constraints($data)
    || return $self->forward('default'); # protect against submission of empty form
        # $self->debug($search_constraints);

	# how many records match submitted search params:
    my $requests_count = $self->model('Request')
		->search_requests_count($search_constraints); # $self->debug($requests_count);

	# stash requests_count for possible use later (eg _get_multiple_records):
	$self->stash( requests_count => $requests_count );
	
    # zero hits, or too many to handle:
    if (! $requests_count || $requests_count > 1000 ) {
        $self->stash->{status_msg} = $requests_count ?
            sprintf $self->messages('search')->{too_many_records}, $requests_count
                : $self->messages('search')->{no_records_found};

        my $html = $self->forward('default');
        return $self->fill_form($html);
    }

    # if we only have 1 record, get request.id & pass to _get_single_record():
    elsif ($requests_count == 1) { 
		my $request_id
			= $self->model('Request')->get_request_id($search_constraints);
        return $self->_get_single_record($request_id);
    }
	
	# have between 2 & 1000 records
	else { 
		return $self->_get_multiple_records($search_constraints);
	}
}

#-------------------------------------------------------------------------------
sub _get_multiple_records {
	my ($self, $search_constraints) = @_; $self->_debug_path();
	
	my $q = $self->query;
		
	my %args_for_search = (
		sort_by => join ' ', $q->param('sort_by'), uc $q->param('sort_order'),		
	); # $self->debug(\%args_for_search);
	
	# retrieve requests_count from do_search():
	my $requests_count   = $self->stash->{requests_count};
	# entries per page from form or use config default:
	my $entries_per_page = $q->param('entries_per_page')
	|| $self->cfg('settings')->{entries_per_page}; # warn $entries_per_page;

	# if > 10, invoke pager for template and add limit & offset params to \%args:
	if ( $requests_count > $entries_per_page ) {
		$self->pager({ query => \%args_for_search, total => $requests_count });
	}  #  $self->debug(\%args_for_search);
	
	{ # get record & specimens map data structures into tt_params:
		my %local_args = (
			search_constraints => $search_constraints,
			args_for_search    => \%args_for_search,
		); # warn Dumper \%local_args;

		# get records matching search_contraints + args_for_search:
		my $records	= $self->model('Request')->find_requests(\%local_args);
		
		# get specimen_map for all requests so we have 1 db hit not 1 per request:
		my @request_ids = map { $_->id } @$records;
		my $specimen_map = $self->specimen_map(\@request_ids);

		$self->tt_params(
			records      => $records,
			specimen_map => $specimen_map,
		);
	}
	
	# get request_histories for all requests so we have 1 db hit not 1 per request:
   	# my $history_map = $self->get_request_histories($records); # using 'requests.created_at' now
	
    $self->tt_params( total_count => $requests_count );

	# send template through render_view() to apply symbolise() function:
    return $self->render_view('search/multiple_records.tt');	
}

#-------------------------------------------------------------------------------
sub _get_single_record {
    my $self = shift; $self->_debug_path();

    my $request_id = shift
	|| return $self->error('no id passed to '.$self->get_current_runmode);

    # functions transferred to LIMS::Controller::Roles::RecordHandler
    my $request_data = $self->get_single_request_data($request_id)
	|| return $self->error("request_id '$request_id' does not exist");

    # format lab_test data for template:
    $self->format_raw_lab_test_data($request_data);	
	$self->process_raw_lab_test_data($request_data);
	
	# log event:
	$self->history_log_event({ request_id => $request_id, event => 'view' });

    # using render_view() for access to join_hash_values:
    return $self->render_view('record/default.tt', $request_data);
}

1;
