package Sequence;

use strict;
use XML;
use Message;

use methods;

use members ( scalar => [ 'name',
			  'title',
			  'old',
			  'start' ],
	        text => 'description',
	       index => 'grants' );

sub new {
	my $package = shift;
	return (bless {}, $package)->init( start => 1, @_ );
}

sub sql_create {
	my ($this) = @_;
	return qq{create sequence $this->{name} start $this->{start}},
		map { $_->sql_create($this) } $this->grants;
}

sub sql_drop {
	my ($this) = @_;
	return 
		(map { $_->sql_drop($this) } $this->grants),
		qq{drop sequence $this->{name}},
}

sub sql_alter {
	my ($old, $diff, $new) = @_;

	error "start for sequence `$new->{name}' is decreasing from `$old->{start}' to `$new->{start}' - this is probably a bad thing - be careful!"
		if $new->start < $old->start;

	if ($new->start == $old->start) {
		my @commands;
		push @commands, $old->grant($_)->sql_drop($old) for $diff->removed_grants;
		die "internal error: it is nonsensical to change a grant" for $diff->changed_grants; 
		push @commands, $new->grant($_)->sql_create($new) for $diff->added_grants;
		die "internal error: it is nonsensical to rename a grant" for $diff->renamed_grants; 
		return @commands;
	}

	return $old->sql_drop,
	       $new->sql_create;
}

sub sql_rename {
	my ($this, $new_name) = @_;
	my $old_name = $this->name;
	my @commands;
	push @commands, $this->sql_drop;
	$this->name($new_name);
	push @commands, $this->sql_create;
	$this->name($old_name);
	return @commands;
}

sub sql_parse {
	my ($this, $sql) = @_;

	$this = $this->new unless ref $this;
	while (1) {
		$$sql =~ s/^\s+//s;
		return if $$sql eq '';
		if ($$sql =~ s/^start\s+(?:with\s+)?(\d+)//si) {
			my $start = $1;
			$this->start($start);
		} elsif ($$sql =~ s/^(increment(\s+by)?|maxvalue|minvalue|cache)\s+\d+//si ) {
		} elsif ($$sql =~ s/^no\s+(maxvalue|minvalue)\s+//si ) {
		} else {
			last;
		}
	}
	return $this;
}

sub diff {
	my ($old, $new) = @_;
	my $diff = $old->methods::diff($new);

	if ($new->start < $old->start) {
		delete $diff->{change}{start};
		delete $diff->{change} unless %{$diff->{change}};
	}

	my $n = keys %$diff;
	if ($n && (! $$diff{name} || $n >= 2)) {
		return $diff;
	}
	return undef;
}

sub realize {
	my ($this) = @_;
	$this->$_(undef) for qw(description title);
	$this->recurse();
}

1
