package LIMS::Model::Base;

# base package for LIMS::Model classes that want $self->user_profile
# generic Rose::DB::Object::Manager methods - all require $args
# (hashref of object_class (required) & args_for_search (optional)

use Moose;
with (
	'LIMS::Model::Roles::SessionData', # user_profile()
	'LIMS::Model::Roles::DBIxSimple',  # lims_dbix(), dbix_get_meta()
);
use namespace::clean -except => 'meta';

# passed in from LIMS::model as my $model = $package->new(%args):
has _lims_db  => ( is => 'ro', isa => 'LIMS::DB', required => 1 );

has does_authorisation => ( is => 'ro', isa => 'Int', lazy_build => 1 );

__PACKAGE__->meta->make_immutable;

use LIMS::Local::Debug;
use LIMS::Local::Utils;

use Data::Dumper;

# return LIMS::DB object passed in from LIMS::model():
sub lims_db { return shift->_lims_db }
# return LIMS config settings:
sub lims_cfg { LIMS::Local::Config->instance; }

#-------------------------------------------------------------------------------
sub get_objects {
    my $self  = shift;
    my $class = shift; # scalar
    my $args  = shift || {}; # optional hashref, passed straight to Manager
    my $with  = shift || []; # optional with_objects scalar or arrayref

    my $rows = Rose::DB::Object::Manager->get_objects(
       object_class => 'LIMS::DB::' . $class,
		with_objects => $with,
       %$args,
    );

    return $rows;
}

#-------------------------------------------------------------------------------
sub get_objects_count {
    my $self  = shift;
    my $class = shift; # scalar
    my $args  = shift || {}; # optional hashref, passed straight to Manager
	my $with  = shift || []; # optional with_objects scalar or arrayref

    my $count = Rose::DB::Object::Manager->get_objects_count(
        object_class => 'LIMS::DB::' . $class,
		with_objects => $with,
        %$args,
    ); # warn $count;

    return $count;
}

#-------------------------------------------------------------------------------
sub get_meta_data { # !!!!!!! must not clash with M::R::DBIxSimple::dbix_get_meta()
    my $self  = shift;
    my $class = shift; # warn $class; # scalar

    my $object_class = 'LIMS::DB::' . $class;

    return $object_class->new->meta;
}

#-------------------------------------------------------------------------------
sub get_objects_iterator {
    my $self  = shift;
    my $class = shift; # scalar
    my $args  = shift || {}; # optional hashref, passed straight to Manager

    my $iterator = Rose::DB::Object::Manager->get_objects_iterator(
        object_class => 'LIMS::DB::' . $class,
        %$args,
    );

    return $iterator;
}

#-------------------------------------------------------------------------------
sub time_now { # returns DateTime object
	my $self = shift;

	return LIMS::Local::Utils::time_now; # considers BST
}

#-------------------------------------------------------------------------------
# generic update method - uses insert_or_update(), and will update record if 'id'
# supplied, otherwise insert new. Assumes any unique_key(s) has passed validation
# check & belongs to record being edited. Expects hashref with keys 'class' & 'data':
sub update_object {
    my $self = shift;
    my $args = shift; # $self->debug( $args );

    my $class = $args->{class}; # warn $class;
    my $data  = $args->{data}; # warn Dumper $data;

    my $object_class = 'LIMS::DB::' . $class;
    my $o = $object_class->new();

    my %args = ( data => $data, obj => $o );

    # get form_params for required table into $o object:
    $self->populate_object_with_form_data(\%args);

#$self->set_rose_debug(1);
    eval { # warn Dumper $o->as_tree;
        $o->insert_or_update( changes_only => 1 ); # doesn't do 'changes_only'
    };
#$self->set_rose_debug(0);

    return $@ if $@;
}

#-------------------------------------------------------------------------------
# expects array of class_name => { column_name => column_value }
sub get_object_by_param {
    my $self = shift;

    my $class = shift; # $self->debug($args);
    my $query = shift; # hashref of column_name => column_value

    my $object_class = 'LIMS::DB::'.$class;
#$self->set_rose_debug(1);
    my $o = $object_class->new(%$query)->load(speculative => 1);
#$self->set_rose_debug(0);
    return $o;
}

#-------------------------------------------------------------------------------
# accepts hash(ref) of object to be populated, and submitted form_params
# and populates object with form_params - returns nothing:
sub populate_object_with_form_data {
    my $self = shift;
    my $args = shift; # $self->debug($args);

    my $data = $args->{data};
    my $obj  = $args->{obj};

    my @cols = $obj->meta->column_names;

    # foreach table col:
    foreach my $col (@cols) {
        # value = corresponding form_param value:
        my $val = $data->{$col};
        # populate object accessor with value:
        $obj->$col($val);
    }
}

#-------------------------------------------------------------------------------
sub set_rose_debug {
    my ($self, $switch) = @_;

    $Rose::DB::Object::Debug =
        $Rose::DB::Object::Manager::Debug
            = $switch || 0; # zero probably not captured in $switch ??
}

#-------------------------------------------------------------------------------
sub debug {
    my ($self, $str) = @_;

    warn Dumper $str;

    DEBUG($str);
}

#-------------------------------------------------------------------------------
# same as LIMS::Role::Base method, but doesn't use stash():
sub get_yaml_file {
	my ($self, $filename) = @_; # warn $filename;

	my $cfg = $self->lims_cfg;

    my %args = (
        yaml_dir => $cfg->{settings}->{yaml_dir},
        app_root => $cfg->{path_to_app_root},
        filename => $filename,
    );
    my $yaml = LIMS::Local::Utils::get_yaml(\%args);
	return $yaml;
}

# ------------------------------------------------------------------------------
sub _build_does_authorisation { # returns true if authorisation stage in use
    my $o = LIMS::DB::StatusOption->new(description => 'authorised')->load;
    return $o->is_active eq 'yes' ? 1 : 0; # must return int for Moose isa
}

1;
