package DX::Var;

use Moo;

has id => (is => 'ro', required => 1);

has root_set => (is => 'ro', predicate => 1);

has bound_stream => (
  is => 'lazy', predicate => 1, clearer => 1,
  builder => sub {
    my ($self) = @_;
    $self->root_set->to_stream;
  }
);

has bound_value => (is => 'lazy', predicate => 1, clearer => 1, builder => sub {
  if (defined(my $next = $_[0]->bound_stream->next)) {
    return $next;
  }
  DX::State->return_from_op('backtrack');
  return;
});

has action => (is => 'ro');

sub is_bound {
  my ($self) = @_;
  $self->has_bound_value || $self->has_bound_stream || $self->has_root_set;
}

sub with_stream {
  my ($self, $stream) = @_;
  $self->new(%$self, bound_stream => $stream);
}

sub with_value {
  my ($self, $stream) = @_;
  $self->new(%$self, bound_value => $stream);
}

sub with_action {
  my ($self, $action) = @_;
  $self->new(%$self, action => $action);
}

sub with_root_set {
  my ($self, $set) = @_;
  $self->new(%$self, root_set => $set);
}

sub copy {
  my ($self) = @_;
  ref($self)->new(%$self);
}

1;
