package LIMS::Model::Roles::DBIxSimple;

use Moose::Role;

has params => ( is => 'rw', isa => 'HashRef', default => sub { {} } );
has constraint => ( is => 'rw', isa => 'Str' ); 
has constraint_title => ( is => 'rw', isa => 'Str' ); # for chart & template titles

use DateTime::Format::MySQL;
# requires 'lims_dbix'; # LIMS::Model::Base method

use Data::Dumper;

sub get_cols {
	my ($self, $table) = @_;
	
	my $dbh = $self->lims_dbix;
	
	my $meta = $self->get_meta($table); # warn Dumper $meta;
	
	my @cols = keys %$meta; # warn Dumper \@cols;
	return \@cols;
}

sub get_meta {
	my ($self, $table) = @_;
	
	my $dbh = $self->lims_dbix;
	
	my $t = $dbh->query("show columns from $table")->hashes; # warn Dumper $t;
	
	my %meta = map { $_->{field} => $_ } @$t; # warn Dumper \%meta;	
	return \%meta;
}

sub get_enum_opts {
	my ($self, $table, $col) = @_;

	my $meta = $self->get_meta($table);
	
	my $col_type = $meta->{$col}->{type};
	
	my ($enum) = $col_type =~ /enum\((.*)\)/; # warn $enum;
	my @opts = sort grep { $_ =~ s/\'//g } split ',', $enum; # warn Dumper \@opts;
	return \@opts;
}

sub inflate_mysql_dates_to_datetime {
	my $self = shift;
	my $data = shift; # hashref
	my $cols = shift; # array(ref) of cols to inflate
	
	map {
		$data->{$_} = DateTime::Format::MySQL->parse_date($data->{$_});
	} grep $data->{$_}, @$cols;	
}

sub inflate_mysql_timestamp_to_datetime {
	my $self = shift;
	my $data = shift; # hashref
	my $cols = shift; # array(ref) of cols to inflate
	
	map {
		$data->{$_} = DateTime::Format::MySQL->parse_datetime($data->{$_});
	} grep $data->{$_}, @$cols;	
}

sub get_sql_with_constraint {
    my $self  = shift;
    my $entry = shift; # sql lib entry
    my $time_column = shift; # to set duration on
    my $default_constraint_type = shift || ''; # optional - to override return

    # set constraint & constraint_title params:    
    $self->_set_search_constraints($time_column, $default_constraint_type); 
    my $constraint = $self->constraint;

	my $sql = $self->sql_lib->retr($entry);
    $sql =~ s/%CONSTRAINT%/$constraint/; # warn $sql;

    return $sql;
}

=begin
my $type = $vars->{constraint_type};
my $method = "_build_${type}_sql";
my $sql = $self->$method($vars);
and have sub _build_lastyear_sql { ... } and such

you'll always have a constraint_type and you can dispatch by that,
e.g. simply use it to call a method named "handle_${constraint_type}_query"

the nice thing about dispatching to different methods per constraint type means
you can do things like put them into reusable roles and such
=cut

# sets __PACKAGE__->constraint & __PACKAGE__constraint_title:
sub _set_search_constraints {
    my $self = shift;
    my $time_column = shift; # warn $time_column;
    my $default_constraint_type = shift || ''; # optional - to override return

    my $vars = $self->params; # warn Dumper $vars;
    
    my $constraint_type # undef on 1st call, unless default set in model method 
        = $vars->{constraint_type} || $default_constraint_type || ''; 
    
    my ($constraint, $title);
    
    # for checkboxes it's safe to examine $constraint_type, for textboxes &
    # selects, need to test for defined query param as it's possible to submit an
    # empty field, where constraint_type is defined but equivalent param is undef
    if ( $constraint_type eq 'all_data' ) {
        $constraint = qq!year($time_column) IS NOT NULL!; # ie everything
        $title = 'all requests';
    }
    elsif ( $constraint_type eq 'this_year' ) {
        my $this_year = DateTime->now->year;
        $constraint = qq!year($time_column) = $this_year!;
        $title =  'year ' . $this_year;
    }
    elsif ( $constraint_type eq 'one_month' ) {
        $constraint = qq!$time_column between date_sub(curdate(), interval
            1 month) and curdate()!;
        $title = 'last 1 month';
    }
    elsif ( $constraint_type eq 'year_since' && $vars->{year} ) { # check var sent
        $constraint = qq!year($time_column) >= $vars->{year}!;
        $title = 'all from ' . $vars->{year};
    }
    # textboxes & select fields:
    elsif ( my $days = $vars->{days} ) { # $constraint_type eq 'days'
        $constraint = qq!$time_column between date_sub(curdate(), interval $days
            day) and curdate()!;
        $title = 'previous ' . $days . ' days';
    }
    elsif ( my $year = $vars->{year} ) { # $constraint_type eq 'year'
        $constraint = qq!year($time_column) = $year!;
        $title = 'year ' . $vars->{year};
    }
    # need both 'from' & 'to' dates:
    elsif ( $vars->{date_from} && $vars->{date_to} ) { # $constraint_type eq 'date_range'
        # NB: silently fails if date is invalid:
        my $start_date = LIMS::Local::Utils::date_to_mysql($vars->{date_from});
        my $end_date   = LIMS::Local::Utils::date_to_mysql($vars->{date_to});
        
        # need to ensure no date conversion error:
        if ($start_date && $end_date) {
            $constraint = qq!$time_column between '$start_date' and '$end_date'!;
            $title = 'between ' . $vars->{date_from} . ' & ' . $vars->{date_to};
        }
    }
    # set default to previous calendar year if no form constraint or invalid date: 
    $constraint ||= qq!$time_column between date_sub(curdate(), interval 1 year)
        and curdate()!;
    $title ||= 'last 365 days';
    
    # set package accessors:
    $self->constraint($constraint);
    $self->constraint_title($title);
}

1;