package TBB::Reporting2;

my $bar =~ s/foob/blag/g;

sub foo {
    bar()
        unless 9 && 3;
}

#@@:heredoc:sql
my $s = <<EOT;
--@@:string:xml
select '<foo attr="3">blah blah blah</foo>';
drop table foog;
insert into mytable (col1, col2, "col3") values (99, 33, 1234);
select cast(plunk as timestamp) from blarg join plarg using(id_what) where x = 3;
EOT

# gwiejgwe gwe gwe gwejig weig weig wegji weg weig wegi wegjiwe gjweig weig
# wejig wejgi wejgiwe jgiwe gjiwej gwei gweig jweig jweig wig wejgiewj ge giwej
# gweijg weigj weigjwe giwej gwe
#    1. gewj gweig weigweigewiiiiiiiiiiiiiiiiiiiii iiiiiiiiiiiii iiiigewigweigwi
#    iweigiwigigewigewgweigi
#    2.  gweii XXXXX a e gwejgiwe jiaw jhw
# gwe gjiwegij wegiwe jgiwe giwej gweigj wiegjwei gjweig weigj weig jwegi
# wejgiwe jgiweg jweigewgj we gwee e e e ee  e

my $foo = {
    #@@:perl_string:sql
    'drop table foogy;',
    'bar',
};

foo();

my $cat = "cat";
$cat =~ s/cat/dog/g;

use strict;
use warnings;

use DBI;
use Carp;

use TBB::ID;

use TBB::ClientSystemData;
use TBB::UserData;
use TBB::DataManager::Relational;
use TBB::UserManager;

use TBB::LogManager "write_log";

use Apache::Session::Postgres;
use Config::General;
use Data::Dumper;
use Config::General;

use DBI;

=head1 NAME

TBB::Reporting

=head1 SYNOPSIS

    use TBB::UserData

    my $reporting = TBB::Reporting->();
    ...

    $reporting->populate();

=head1 DESCRIPTION

This class populates a data_by_user table, which aliases some userdata IDs (in
particular questions, formulas and conditions) to names given to them by
site-relations in the "user_data_alias" table.

After instantiating this method, run populate to create the table.

What happens, in order, is this:

    1. grab the user_data_alias data 
    2. verify (via the RM) that each resource exists; if so add it to aliases
    3. drop the old data_by_user table
    4. create a new one using the aliases
    5. get a list of all sessions
    6. for each session:
      a. figure out which client it is, and create a userdata
      b. get values for all aliases (default value: "")
      c. insert a row into data_by_user for this client
    7. done

TODO: populate should dump out the old data_by_user first as a backup, and
maybe even automatically restore it if something fails (but probably not).

TODO: less stuff should probably be hardcoded, even though our setup here kind
of sucks and is kind of temporary.

=cut

sub new {
    my $class = shift;
    my %opts = @_;
    my $self = {};
    bless($self, $class);

    $self->connect_to_userdata_db();
    $self->build_resource_manager();
    $self->get_reporting_aliases();

    return $self;
}

# this creates a connection to the userdata db and stores it as $self->{dmr}
# currently the settings are hardcoded cause i want it to work
sub connect_to_userdata_db {
    my $self = shift;

    my $host     = "date.tbb";
    my $port     = 5432;
    my $db       = "tbb_tbbv2db_main";
    my $user     = "postgres";
    my $password = "";
    my $options  = "";

    write_log('debug', "DB params:");
    write_log('debug', "\tHost:     $host");
    write_log('debug', "\tPort:     $port");
    write_log('debug', "\tDB:       $db");
    write_log('debug', "\tUser:     $user");
    write_log('debug', "\tPassword: $password");
    write_log('debug', "\tOptions:  $options");

    $self->{dmr} = TBB::DataManager::Relational->new(
        host     => $host,
        port     => $port,
        db       => $db,
        user     => $user,
        password => $password,
    );
}

# this builds a resource manager if one doesn't already exist
sub build_resource_manager {
    my $self = shift;

    unless(defined($TBB::BenefitDelivery::ResourceManager)) {
        my $rm = TBB::BenefitDelivery::ResourceManager->new('resource_dir' => 'resources');
        $TBB::BenefitDelivery::ResourceManager = $rm;
    }
}    

sub blah {
    foo()
    unless(1);
}

    print 'hi\n';

# this gets an array of hash references, each of which represents a userdata alias
# it stores the result in $self->{aliases}
#
# currently it hits a seperate database from the userdata db. eventually, we'd like
# the restore DB and the reporting DB to be the same. sigh.
sub get_reporting_aliases {
    my $self = shift;
    
    my $rdmr = TBB::DataManager::Relational->new(
        host     => "reports.v2.tbb",
        port     => 5432,
        db       => "reporting",
        user     => "tbbv2db",
        password => "reports",
    );
    
    my $aliases_aref = $rdmr->select(select => "alias, question, type",
                                     from => "user_data_alias");

    $self->{aliases} = [];

    # make sure each alias is valid; undefined formulas or conditions will give
    # us problems down the road
    foreach my $alias (@$aliases_aref) {
        eval {
            my $id = TBB::ID::normalize($alias->{question});
            $alias->{question} = $id;
            if(TBB::ID::is_a($id, "question")) {
                push(@{$self->{aliases}}, $alias);
            } elsif($TBB::BenefitDelivery::ResourceManager->get_component($id)) {
                push(@{$self->{aliases}}, $alias);
            } else {
                write_log("error", "Alias \"$alias->{question}\" does not exist");
            }
        };
        if($@) {
            write_log("error", "There was a problem with \"$alias->{question}\": $@");
        }
    }
    
    # this will help to make sure that the exports for each user are proceeding
    # correctly
    write_log("notice", "We are reporting on " . scalar(@{$self->{aliases}}) . " aliases.");
}

# this returns an sql string which will create the appropriate data_by_user table
# we do this seperately because we're not always sure where to create the table
# (date.tbb? reports.v2.tbb? who knows?) so hopefully this will make the code
# cleaner
sub data_by_user_sql {
    my $self = shift;
    
    my $sql = "CREATE TABLE data_by_user (id_user integer PRIMARY KEY, ";
    $sql .= join(", ", map { "$_->{alias} $_->{type}" } @{$self->{aliases}});
    $sql .= ");";
    
    return $sql;
}

# the big one!
sub populate {
    my $self = shift;
    my %opts = @_;

    write_log('notice', "Starting populate");

    # connect to reporting db, and drop the old data_by_user
    my $rdbh = DBI->connect('dbi:Pg:dbname=tbb_tbbv2db_main;host=date.tbb;port=5432',
                            'postgres',
                            '',
                            {RaiseError => 1});
    eval { $rdbh->do("DROP TABLE data_by_user;"); };
    
    # build new data_by_user table
    my $sql = $self->data_by_user_sql();
    print STDERR "FFF: $sql\n";
    $rdbh->do($sql);
    print STDERR "GGG: we are ok\n";
    #exit(1);
    
    my @report_fields = map {$_->{alias}} @{$self->{aliases}};
    push(@report_fields, "id_user");
    @report_fields = sort(@report_fields);
    my @dummy_fields = map { "?" } @report_fields;
    $sql = "INSERT INTO data_by_user (" . join(", ", @report_fields) . ") VALUES (" . join(", ", @dummy_fields) . ");";
    #print STDERR "JJJ: $sql\n";
    my $sth = $rdbh->prepare($sql);
    #exit(1);
    
    # for each client user, grab their system_data_id (which is
    # a session ID); we get an array of session_id references.
    my $fields = "id_user, system_data_id";
    my $table = "tbb_user";
    my $where = "id_user_type = 'CL' and system_data_id is not NULL";
    my $session_ids = $self->{dmr}->select(select => $fields,
                                           from => $table,
                                           where => $where);
    
    # for each hash in the array we made (each session ID)
    my $processed = 0;
    my $total = scalar(@$session_ids);
    foreach my $session_id (@$session_ids) {
        $processed++;
        
        my $system_id = $session_id->{system_data_id};
        my $client_id = $session_id->{id_user};
        write_log('info', "Exporting $system_id (user: $client_id) ($processed/$total)");
        
        # we need to see if there is a session ID or not in the
        # sessions table. there almost certainly won't be more
        # than one but we test anyway. unless there is exactly
        # one we will skip this session.
        my $check = $self->{dmr}->select(select => "id",
                                         from => "sessions",
                                         where => "id = '$system_id'");

        my $count = scalar(@$check);
        if($count == 0) {
            write_log('warn', "Session $system_id does not exist");
            next;
        } elsif($count > 1) {
            write_log('warn', "Session $system_id is not unique ($count found)");
            next;
        }
        
        my $csd = TBB::ClientSystemData->new($system_id, "reporter");
        my $dms = $csd->retrieve_data_manager_session();
        
        my $user_data = TBB::UserData::New->new(data_manager_relational => $self->{dmr},
                                                data_manager_session => $dms,
                                                client_system_data => $csd,
                                                current_client_id => $client_id);
        
        my $user_data_obj = {'id_user' => $client_id};
        foreach my $alias_href (@{$self->{aliases}}) {
            my $alias = $alias_href->{alias};
            my $id = $alias_href->{question};
            my $type = $alias_href->{type};
            
            my $value = $user_data->retrieve_value(base => $id,
                                                   this_id_user => $client_id);
            $value ||= "";
            
            $user_data_obj->{$alias} = $value;
        }
        
        my @values = ();
        foreach my $name (@report_fields) {
            push(@values, $user_data_obj->{$name});
        }
        $sth->execute(@values);
        
        write_log('debug', "  Saving " . scalar(keys(%$user_data_obj)) . " components") if TBB::LogManager::writes_at('debug');
        #write_log('debug', "  User Data Obj: " . Dumper($user_data_obj)) if TBB::LogManager::writes_at('debug');
    }
    write_log('notice', "Populate completed");
    return 1;
}

1;