package FormBase;
use Moose;
use File::Temp qw/tempfile tempdir/;
use File::Copy qw/copy/;
use Archive::Zip();
use strict;
use warnings;
use CGI::FormBuilder;
use File::Basename;
use DBI;
use CGI;
use Data::Dumper;
use HTML::Template;

has 'database' => (
    is => 'rw', 
    isa => 'Str' 
);

has 'form_title' => (
    is => 'rw',
    isa => 'Str'
);

has 'fields' => (
    is => 'rw', 
    isa => 'ArrayRef'
);

has 'archivekeyfields' => (
    is => 'rw',
    isa => 'ArrayRef',
    default => sub{
        ['last_name','first_name','id']
    }
);

has 'filefields' => (
    is => 'rw',
    isa => 'HashRef',
    default => sub{
        { resume => 1, letter_of_interest => 1, writing_sample => 1, personal_statement => 1, work_outline => 1, recent_publication => 1, academic_transcript => 1 }
    }
);

has 'template' => (
    is => 'rw',
    isa => 'Str'
);

has 'admin_template' => (
    is => 'rw',
    isa => 'Str'
);

sub dbhandle{
    my $self = shift;
    if(-e 'data/' . $self->database()){
        my $dbh = DBI->connect("dbi:SQLite:dbname=data/".$self->database(),"","", {RaiseError => 1}) or die($DBI::errstr);
        return $dbh;
    } else {
        my $dbh = DBI->connect("dbi:SQLite:dbname=data/".$self->database(),"","", {RaiseError => 1}) or die($DBI::errstr);
        $self->create_tables();
        return $dbh;
    }
}

sub create_tables{
    my $self = shift;
    my $dbh = $self->dbhandle();
    my $fields = $self->fields();
    my $columns = join(',', map{"$_ TEXT"} @$fields);
    my $create_statement = "CREATE TABLE IF NOT EXISTS applications(id INTEGER PRIMARY KEY AUTOINCREMENT, $columns)";
    #warn('Create table :' . $create_statement);
    $dbh->do($create_statement);
}

sub process_file{
    my($self,%p) = @_;
    my $form = $p{'form'};
    my $id = $p{'id'};
    if($form->cgi_param($p{'field_name'})){
        my $database_name = $self->database();
        my $dbh = $self->dbhandle();

        my $file = $form->field($p{'field_name'});
        my $file_name = $form->cgi_param($p{'field_name'});

        my $extension;
        if($file_name =~ m/[^\.]+\.([^\.]+)$/){
            $extension = $1;
            $extension =~ s/[^a-z\d]//gis;
        }
        open F, "> data/$database_name-" . $p{'field_name'} ."-$id.$extension" or die $!;
        while (<$file>) {
            print F;
        }
        close F;
        $dbh->do('update applications set ' . $p{'field_name'}. ' = ? where id = ?', {}, ("$database_name-" . $p{'field_name'} . "-$id.$extension",$id)); 
    }
}

sub debug_data{
	my ($self, %p) = @_;
	my $fields = $self->fields();
    my $form = $p{'form'};
	my @debug = map{"$_ -> " . ($form->cgi_param($_) || '')} @$fields;
	warn(Dumper($form));
	warn(join("\n",@debug));
}

sub insert_data{
    my ($self,%p) = @_;
    my $dbh = $self->dbhandle();
    my $database_name = $self->database();
    my $form = $p{'form'};

    if($form->cgi_param("can_has_javascriptz")){
        my $fields = $self->fields();
        my $fields_sql = join(',', @$fields);
        my $placeholders = join(',', map {"?"} @$fields);
        my @values = map{$form->cgi_param($_) || ''} @$fields;
        my $insert_statement = "insert into applications($fields_sql) values($placeholders)";
        #warn('insert statement: ' . $insert_statement);
        #warn('parameters:' . Dumper(\@values));
        $dbh->do($insert_statement,{},(@values));
        my $id = $dbh->func('last_insert_rowid');

        foreach my $file_field (keys %{$self->filefields()}){
            $self->process_file(field_name => $file_field, id => $id, form => $form);
        }
#        $self->process_file(field_name => 'letter_of_interest', id => $id, form => $form);
#        $self->process_file(field_name => 'writing_sample', id => $id, form => $form);
#        $self->process_file(field_name => 'personal_statement', id => $id, form => $form);
#        $self->process_file(field_name => 'work_outline', id => $id, form => $form);
#        $self->process_file(field_name => 'recent_publication', id => $id, form => $form);
#        $self->process_file(field_name => 'academic_transcript', id => $id, form => $form);

    }
    return;
}

sub export{
    my ($self,$q) = @_;
    my $dbh = $self->dbhandle();
    my $dir = tempdir( CLEANUP => 1, DIR => '/var/tmp' );
    my $sql = '';
    if($q->param('ids')){
        $sql = 'select * from applications where id in(' . join(',',map{$dbh->quote($_)} $q->param('ids')) . ')'; 
    }else {
        $sql = 'select * from applications';
    }
    my $apps = $dbh->selectall_arrayref($sql,{Columns => {}});
    my $output = '';
    for my $row(@$apps){
        my $dir_tmp_key = join('-',map{$row->{$_}} @{$self->archivekeyfields()});
        $dir_tmp_key =~ s/[^a-z\d\-]//gi;

        my $root_dir = "$dir/$dir_tmp_key/";
        mkdir($root_dir);
        for my $field(keys %{$self->filefields()}){
            if(exists $row->{$field} && $row->{$field}){
                #It's a file
                copy('data/' . $row->{$field}, $root_dir . $row->{$field}) or warn($!);
            }
        }
        my $output = '';
        for my $field (@{$self->fields()}){
            unless(exists $self->filefields->{$field}){
                $output .= "$field\n----------------------------\n";
                $output .= $row->{$field}."\n\n";
            }
        }
        open(APPLICATION,'>',$root_dir . 'application.txt') or warn($!);
        print APPLICATION $output;
        close APPLICATION;
    }
    my $zip = Archive::Zip->new();
    $zip->addTree($dir,'applications');
    my ($fh,$name) = tempfile(UNLINK => 1, DIR => '/var/tmp');
    $zip->writeToFileHandle($fh);
    print $q->header(-attachment => $self->database() . '_archive.zip', -type=> 'application/octet-stream');
    close($fh);
    open(ZIPFILE, '<', $name) or warn($!);
    while(<ZIPFILE>){
        print $_;
    }
}

sub list{
    my ($self,$q)=@_;
	my $dbh = $self->dbhandle();
	my $fields = $self->fields();
	unshift(@$fields, 'id');
	my $fields_sql = join(',',@$fields);
	my $applications = $dbh->selectall_arrayref("select $fields_sql from applications order by id", {Columns => {}});
	my $tmpl = HTML::Template->new('filename' => 'templates/'.$self->admin_template, die_on_bad_params => 0) or die($!);
	my @fields_params = map{{FIELD_NAME => $_}} @$fields;
	my @rows = ();
	foreach my $row(@$applications){
		my $row_data = [];
		foreach my $key(@$fields){
			my $data = $row->{$key};
			my $hash = {};
			if(exists $self->filefields()->{$key}){
				$hash->{'IS_FILE'} = 1;
			}
			$hash->{'DATA'} = $data;
			push @$row_data, $hash;
		}
		$row->{ROWS} = $row_data;
		push @rows, $row;
	}
	$tmpl->param('fields' => \@fields_params);
	$tmpl->param('applications' => \@rows);
	$tmpl->param('form-title' => $self->form_title );
	print $tmpl->output;
}

1;
