The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.

package Xmldoom::Schema::Table;

use Xmldoom::Schema::Column;
use Xmldoom::Schema::ForeignKey;
use Xmldoom::Threads;
use strict;

sub new
{
	my $class = shift;
	my $args  = shift;

	my $parent;
	my $name;

	if ( ref($args) eq 'HASH' )
	{
		$parent = $args->{parent};
		$name   = $args->{name};
	}
	else
	{
		$parent = $args;
		$name   = shift;
	}

	my $self = {
		parent       => $parent,
		name         => $name,
		columns      => [ ],
		foreign_keys => [ ]
	};

	bless  $self, $class;
	return Xmldoom::Threads::make_shared($self, $args->{shared});
}

sub DESTROY
{
	my $self = shift;

	# we don't need no stinking weak references!
	$self->{parent} = undef;
}

sub get_schema { return shift->{parent}; }
sub get_name   { return shift->{name}; }

sub get_columns
{
	my $self = shift;
	my $args = shift;

	# deal with the simplest case
	if ( not defined $args )
	{
		return $self->{columns};
	}

	my $names;
	my $primary_key = 0;
	my $data_only   = 0;

	if ( ref($args) eq 'ARRAY' )
	{
		$names = $args;
	}
	elsif ( ref($args) eq 'HASH' )
	{
		$primary_key = $args->{primary_key} if defined $args->{primary_key};
		$data_only   = $args->{data_only}   if defined $args->{data_only};
	}

	my @cols;
	foreach my $col ( @{$self->{columns}} )
	{
		if ( defined $names )
		{
			# only add those colums matched in the names list
			foreach my $name ( @$names )
			{
				if ( $col->get_name() eq $name )
				{
					push @cols, $col;
					last;
				}
			}
		}
		else
		{
			if ( $primary_key and $col->is_primary_key() )
			{
				# only the primary key
				push @cols, $col;
			}
			elsif ( $data_only and not $col->is_primary_key() )
			{
				# only the data
				push @cols, $col;
			}
		}
	}
	
	return \@cols;
}

sub get_column_names
{
	my $self = shift;

	my $columns = $self->get_columns(@_);
	my @ret = map { $_->get_name() } @$columns;

	return \@ret;
}

sub get_column
{
	my ($self, $name) = @_;

	my @cols = grep { $_->{name} eq $name } @{$self->{columns}};
	if ( scalar @cols != 1 )
	{
		return undef;
	}

	return $cols[0];
}

sub get_primary_key
{
	my $self = shift;

	my @columns;

	foreach my $col ( @{$self->{columns}} )
	{
		if ( $col->{primary_key} )
		{
			push @columns, $col;
		}
	}

	return \@columns;
}

sub get_column_type 
{
	my ($self, $name) = @_;

	my $column  = $self->get_column($name);
	if ( defined $column )
	{
		return $column->get_data_type();
	}
	return undef;
}

sub get_foreign_keys { return shift->{foreign_keys}; }

# TODO: this function operates like before but before it was broken!
sub get_foreign_key
{
	my ($self, $name) = @_;
	
	foreach my $key ( @{$self->get_foreign_keys()} )
	{
		my $pair_name = $key->get_foreign_pair_name( $name );

		if ( defined $pair_name )
		{
			return {
				foreign_table  => $key->get_reference_table_name(),
				local_column   => $name,
				foreign_column => $pair_name
			};
		}
	}

	return undef;
}

sub add_column
{
	my $self;
	my @args;

	# sneak the parent argument in.
	if ( ref($_[1]) eq 'HASH' )
	{
		$self = shift;
		@args = ( $_[1] );
		$args[0]->{parent} = $self;
	}
	else
	{
		$self = $_[0];
		@args = @_;
	}

	my $col = Xmldoom::Schema::Column->new(@_);

	if ( $self->get_column( $col->{name} ) )
	{
		die "Table already has a column named \"$col->{name}\"";
	}

	push @{$self->{columns}}, $col;
}

sub add_foreign_key
{
	my $self = shift;
	my $args = shift;

	if ( ref($args) eq 'HASH' )
	{
		$args->{parent} = $self;
	}
	else
	{
		$args = {
			parent          => $self,
			reference_table => $args,
			local_columns   => shift,
			foreign_columns => shift
		};
	}

	push @{$self->{foreign_keys}}, Xmldoom::Schema::ForeignKey->new($args);
}

1;