package App::Clifton::Set;

use Scalar::Util qw(blessed);
use Moo::Role;

requires '_set_of_class';
requires '_set_over';

has _set => (is => 'ro', default => sub { {} });

sub add {
  my ($self, $spec) = @_;
  $self->_set->{$self->_spec_to_key($spec)} = $self->_spec_to_object($spec);
}

sub get {
  my ($self, $spec) = @_;
  $self->_set->{$self->_spec_to_key($spec)};
}

sub flatten {
  my ($self) = @_;
  my $set = $self->_set;
  map $set->{$_}, sort keys %$set;
}

sub _spec_to_object {
  my ($self, $spec) = @_;
  if (blessed($spec) && $spec->isa($self->_set_of_class)) {
    $spec;
  } else {
    $self->_new_member($self->_spec_to_constructor_args($spec));
  }
}

sub _new_member {
  my ($self, $args) = @_;
  $self->_set_of_class->new($args);
}

sub _spec_to_constructor_args {
  my ($self, $spec) = @_;
  $spec;
}

sub _spec_to_key {
  my ($self, $spec) = @_;
  my $key = $self->_set_over;
  die "key ${key} is required" unless $spec->{$key};
  $spec->{$key};
}

1;
