package EnsEMBL::Web::Data::Record;

use strict;
use warnings;
use base qw(EnsEMBL::Web::Data::Trackable);
use EnsEMBL::Web::DBSQL::UserDBConnection (__PACKAGE__->species_defs);

__PACKAGE__->add_fields(cloned_from => 'int');
__PACKAGE__->add_queriable_fields(type => 'string');

###################################################################################################
##
## New constructor is a bit different for Record
## It's used to access existing Record when record type is not known
## Input parameter is hash:
## owner => 'user'/'group'/$user/$group
## id    => $id
##
###################################################################################################

sub new {
  my $class = shift; 

  return $class->SUPER::new(@_)
     unless $class eq 'EnsEMBL::Web::Data::Record';

  my %args  = @_;

  die "Owner & id is necessary for the $class"
    unless $args{owner} && $args{id};
  my $self = bless {}, $class;
  $self->owner($args{owner});
  return $self->retrieve($args{id});
}

###################################################################################################
##
## Record is always owned by someone (user or group so far)
## Below is some functions related to this matter
##
###################################################################################################

sub owner {
  my $class = shift;
  my $owner = shift;
  no strict 'refs';

  if ((ref $owner && $owner->isa('EnsEMBL::Web::Data::User')) || lc($owner) eq 'user') {
    $class->table($class->species_defs->ENSEMBL_USER_DATA_TABLE);
    $class->set_primary_key($class->species_defs->ENSEMBL_USER_DATA_TABLE.'_id');
    $class->has_a(user => 'EnsEMBL::Web::Data::User');
    *{ "$class\::owner" } = sub { shift->user(@_) };
    *{ "$class\::owner_type" } = sub { return 'user' };
  } elsif ((ref $owner && $owner->isa('EnsEMBL::Web::Data::Group')) || lc($owner) eq 'group') {
    $class->table($class->species_defs->ENSEMBL_GROUP_DATA_TABLE);
    $class->set_primary_key($class->species_defs->ENSEMBL_GROUP_DATA_TABLE.'_id');
    $class->has_a(webgroup => 'EnsEMBL::Web::Data::Group');
    *{ "$class\::owner_type" } = sub { return 'group' };
    *{ "$class\::group" }      = sub { shift->webgroup(@_) };
    *{ "$class\::owner" }      = sub { shift->group(@_) };
  }
}

sub add_owner {
  my $class = shift;
  my $owner = shift;
  my $relation_class = $class .'::'. ucfirst(lc($owner));
  my $package = "package $relation_class;
                use base qw($class);
                $relation_class->owner('$owner');
                1;";
  eval $package;
  die "Compilation error: $@" if $@;
  return $relation_class;
}

## hacky sub, used for making group records out of user ones
sub clone {
  my $self  = shift;

  my %hash  = map { $_ => $self->$_ } keys %{ $self->queriable_fields };
  delete $hash{user_id};

  my $clone = EnsEMBL::Web::Data::Record::Group->new(\%hash);
  $clone->cloned_from($self->id);
  $clone->type($self->type);

  return $clone;
}
###################################################################################################
##
## Cache related stuff
##
###################################################################################################

sub propagate_cache_tags {
  my $proto = shift;

  $proto->SUPER::propagate_cache_tags($proto->_type);
}
sub invalidate_cache {
  my $self  = shift;
  my $cache = shift;

  my $owner_type = $self->owner_type;
  my $owner = $self->$owner_type;

  $self->SUPER::invalidate_cache($cache, "${owner_type}[$owner]", $self->type);
}

1;