################################################################
# AutoDIA - Automatic Dia XML.   (C)Copyright 2001 A Trevena   #
#                                                              #
# AutoDIA comes with ABSOLUTELY NO WARRANTY; see COPYING file  #
# This is free software, and you are welcome to redistribute   #
# it under certain conditions; see COPYING file for details    #
################################################################
package Autodia::Handler::DBI;

require Exporter;

use strict;

use warnings;
use warnings::register;

use vars qw($VERSION @ISA @EXPORT);
use Autodia::Handler;

@ISA = qw(Autodia::Handler Exporter);

use Autodia::Diagram;
use Data::Dumper;
use DBI;

#---------------------------------------------------------------

#####################
# Constructor Methods

# new inherited from Autodia::Handler

#------------------------------------------------------------------------
# Access Methods

# parse_file inherited from Autodia::Handler

#-----------------------------------------------------------------------------
# Internal Methods

# _initialise inherited from Autodia::Handler

sub _parse_file { # parses dbi-connection string
  my $self     = shift();
  my $filename = shift();
  my %config   = %{$self->{Config}};

  # new dbi connection
  my $dbh = DBI->connect("DBI:$filename", $config{username}, $config{password});

  my $escape_tablenames = 0;
  my $unescape_tablenames=0;
  my $database_type =  $dbh->get_info( 17 );
  warn "DBI - processing database type : $database_type\n";

  my $schema = '' ;
  # only keep tables in schema public for PostgreSQL
  # could be given as a parameter... (+ a list of tables...)
  $schema = 'public' if (lc($database_type) =~ m/(oracle|postgres)/);

  print "database type : $database_type $schema\n";

  # Manage database tablenames that need to be escaped before calling DBI
  # and those that need to be unescaped before calling DBI 
  $escape_tablenames = 1 if (lc($database_type) =~ m/(oracle|postgres)/);
  $unescape_tablenames = 1 if (lc($database_type) =~ m/(mysql)/);
  print "esc : $escape_tablenames unescape $unescape_tablenames\n";

  # pre-process tables
  foreach my $table ($dbh->tables(undef, $schema, '%', '')) {
      $table =~ s/['`"]//g;
      my $esc_table = $table;
      $esc_table = qq{"$esc_table"} if ($escape_tablenames);
      my $sth = $dbh->prepare("select * from $esc_table where 1 = 0");
      $sth->execute;
      $self->{tables}{$table}{fields} = $sth->{NAME};
#      $self->{tables}{$table}{fields_hash} = map { $_ => 1 } $sth->{NAME};
      $sth->finish;
  }


  # got to about here applying dbi datatypes patch
  foreach my $table (keys %{$self->{tables}}) {
    # create new 'class' representing table
    my $Class = Autodia::Diagram::Class->new($table);
    # add 'class' to diagram
    $self->{Diagram}->add_class($Class);

    # get fields
    my $esc_table = $table;
    $esc_table = qq{"$esc_table"} if ($escape_tablenames);

#    warn "table : $esc_table\n";

    for my $field (@{$self->{tables}{$table}{fields}}) {
      $Class->add_attribute({
			     name => $field,
			     visibility => 0,
			     type => '',
			    });

      if (my $dep = $self->_is_foreign_key($table, $field)) {
	$self->{foreign_tables}{$dep} = {field => $field, table => $table, class => $Class }
      }
    }
  }

  foreach my $fk_table (keys %{$self->{foreign_tables}} ) {
    $self->_add_foreign_keytable($self->{foreign_tables}{$fk_table}{table},
				 $self->{foreign_tables}{$fk_table}{field},
				 $self->{foreign_tables}{$fk_table}{class},
				 $fk_table);
  }

  $dbh->disconnect;
}


sub _add_foreign_keytable {
  my ($self,$table,$field,$Class,$dep) = @_;

  my $Superclass = Autodia::Diagram::Superclass->new($dep);
  my $exists_already = $self->{Diagram}->add_superclass($Superclass);
  if (ref $exists_already) {
    $Superclass = $exists_already;
    # create new relationship
    my $Relationship = Autodia::Diagram::Inheritance->new($Class, $Superclass);
    # add Relationship to superclass
    $Superclass->add_inheritance($Relationship);
    # add Relationship to class
    $Class->add_inheritance($Relationship);
    # add Relationship to diagram
    $self->{Diagram}->add_inheritance($Relationship);
  } else {
    warn "misguessed foreign key : $field\n";
  }
  return;
}

sub _is_foreign_key {
  my ($self, $table, $field) = @_;
  my $is_fk = undef;
  $field =~ s/'"`//g;
  if (($field !~ m/$table.u?id/i) && ($field =~ m/^(.*)_u?id$/i)) {
      $is_fk = ($self->{tables}{$1}) ? $1 : undef;
  } elsif (($field ne $table ) && ($self->{tables}{$field})) {
      $is_fk = $field;
  }
  return $is_fk;
}

sub _discard_line
{
  warn "not implemented\n";
  return 0;
}

1;

###############################################################################

=head1 NAME

Autodia::Handler::DBI.pm - AutoDia handler for DBI connections

=head1 INTRODUCTION

This module parses the contents of a database through a dbi connection and builds a diagram

%language_handlers = { .. , dbi => "Autodia::Handler::DBI", .. };

=head1 CONSTRUCTION METHOD

use Autodia::Handler::DBI;

my $handler = Autodia::Handler::DBI->New(\%Config);
This creates a new handler using the Configuration hash to provide rules selected at the command line.

=head1 ACCESS METHODS

$handler->Parse($connection); # where connection includes full or dbi connection string

$handler->output(); # any arguments are ignored.

=cut






