package PS::MOPS::Test::Instance;

## @class PS::MOPS::Test::Instance
#
# @par DESCRIPTION
# A Test Instance contains a PS-MOPS Instance (see PS::MOPS::DC::Instance).
# The Test Instance is automatically removed by the destructor.
#
# @par REQUIREMENTS
#
# Environment variable MOPS_TESTING_DB_SERVER must be set to the DB server
# used for testing.
#
# @par CONSTRUCTOR ARGUMENTS
# test_instance_name - Specifies a name for the test instance. If not defined,
# then the test instance will be given a generated name.
#
# delete_on_finish - {0|1} Value 1 indicates instance will be deleted at
# object destruction time.
#
# config_file - Full path to configuration file that will be loaded into the instance DB.
#
# @par OBJECT ATTRIBUTES
# _NAME - String corresponding to the name of the PS-MOPS Instance.
# _PSMOPS_INSTANCE - Scalar reference to PS-MOPS Instance.
# _DB - Database object linked to the Test Instance.
# _DELETE_ON_FINISH - {0|1} Remove the PS-MOPS Instance at exit.
# _TESTING_DB_SERVER - name of DB server used for testing.

use strict;
use warnings;

use Env;
use PS::MOPS::DC::Build qw(modcb_build modcb_remove);
use PS::MOPS::DC::Config;
use PS::MOPS::DC::Instance;
use PS::MOPS::Test::Utility qw(getFormattedTime);
use PS::MOPS::Test::Database;
use Params::Validate;

my $_init=sub{};
my $_buildInstance=sub{};
my $_removeInstance=sub{};

# Constructor.
# @param test_instance_name - If a name is given, the test instance will be given that name.
# @param delete_on_finish
# @return Object reference.
sub new {
    my ($class,%arg)=@_;
    my $self={};

    # verify necessary env vars are set
    if(!$ENV{MOPS_TESTING_DB_SERVER}){
	print STDERR "Environment variable MOPS_TESTING_DB_SERVER is not set.\n";
	exit;
    }

    $self->{_NAME}=undef;
    $self->{_PSMOPS_INSTANCE}=undef;
    $self->{_DB}=undef;
    $self->{_DELETE_ON_FINISH}=undef;
    $self->{_TESTING_DB_SERVER}=$ENV{MOPS_TESTING_DB_SERVER};
    
    if(defined($arg{test_instance_name})){
        $self->{TEST_INSTANCE_NAME}=$arg{test_instance_name}; # Set the name of the test instance.
    }
    else {
        $self->{TEST_INSTANCE_NAME}=undef; # Instance name will be generated.
    }
    if(defined($arg{delete_on_finish})){
        $self->{_DELETE_ON_FINISH}=$arg{delete_on_finish};
    }
    else {
        $self->{_DELETE_ON_FINISH}=1; # default to delete on finish.
    }

    bless($self,$class);
    $self->$_init();
    return $self;
}

# Intialize member variables.
# Create PSMOPS Test instance.
$_init=sub
{
    my($self)=shift;

    # Generate unique name for test instance.
    my $test_db_name;
    if(defined($self->{TEST_INSTANCE_NAME})){
        $test_db_name=$self->{TEST_INSTANCE_NAME};
    }
    else { # Generate instance name.
        $test_db_name="psmops_test_";
        $test_db_name.=$ENV{USER} . "_";
        $test_db_name.=getFormattedTime();
    }
    # @todo Validate Test Instance name.

    my $inst=PS::MOPS::DC::Instance->new(DBNAME=>$test_db_name);
    $self->{_PSMOPS_INSTANCE}=$inst;

    $self->{_NAME}=$test_db_name;
    $self->$_buildInstance();

    # Make a new database object
    $self->{_DB}=PS::MOPS::Test::Database->new(psmops_instance=>$self->{_PSMOPS_INSTANCE},
                                               name=>$test_db_name);
};

# Destructor.
#
# Remove PSMOPS Test instance.
sub DESTROY {
    my ($self)=shift;
    if($self->{_DELETE_ON_FINISH}==1){
        $self->$_removeInstance();
    }
}

# Setting the name in build indicates which directory under $ENV{MOPS_HOME}/var
# to use. An empty instance is created.
$_buildInstance = sub {
    my ($self) = shift;
    my $res = modcb_build(name=>$self->{_NAME},
                          model=>'',
                          noprompt=>1 # Don't prompt to drop database.
                          );
};

# Return current PSMOPS instance.
sub getPSMOPSInstance {
    my($self)=shift;
    return $self->{_PSMOPS_INSTANCE};
}

# Return database name in PSMOPS instance.
sub getName {
    my($self)=shift;
    return $self->{_NAME};
}

# Return reference to the database associated with the Test Instance.
sub getDB {
    my($self)=shift;
    return $self->{_DB};
}

# Remove an instance.
# @return None.
$_removeInstance=sub
{
    my ($self)=shift;
    print STDERR "Removing instance...\n";

    # @note possible error dealing with backend hash in PS::MOPS::Config during
    # object destruction, so backend is explicitly set here. Parameter hostname
    # is all that is needed.
    my %backend=(hostname=>$self->{_TESTING_DB_SERVER}); 

    my $res=modcb_remove(name=>$self->{_NAME},backend=>\%backend);
    if(!$res){ print STDERR "\nRemove failed: " . Dumper($res); }
    else { print STDERR "\nPSMOPS instance $self->{_NAME} removed.\n"; }
};

1;
