package RDFcloud;

require RDF::Notation3::Triples;

my %ns = (
	  earl => 'http://www.w3.org/2001/03/earl/0.95#',
	  rdf => 'http://www.w3.org/1999/02/22-rdf-syntax-ns#',
	  rdfs => 'http://www.w3.org/2000/01/rdf-schema#',
	  td => 'http://www.w3.org/QA/Tools/MUTAT/ns#',
	  foaf => 'http://xmlns.com/foaf/0.1/',
);

my %rev_ns = ();

my @rdfs = ();

sub new {
  my ($class, $stuff) = @_;

  my $arrs = {};
  my $hashes = {};
  my $self = {
	      hashes=>$hashes,
	      arrs=>$arrs,
	      ns=>\%ns,
	      rev_ns=>\%rev_ns,
	     };
  bless $self, $class;

  $self->add($stuff) if $stuff;

  return $self;
}

sub add_ns {
  my ($self, $new_ns) = @_;
  for my $doc_ns (keys %$new_ns) {
    if (!grep $_ = $new_ns->{$doc_ns}, @ns) {
      my $val = $new_ns->{$doc_ns};
      if ($ns{$doc_ns} and $ns{$doc_ns} ne $val) {
	$val =~ /.*\/([a-z]\w*).*?$/i;
	$doc_ns .= $1 ? $1 : 'asdf';
      }
      $ns{$doc_ns} = $val;
    }
  }
}

sub parse {
  my ($self) = @_;
  foreach $type (map {@{$_->get_triples(undef, '<' . $ns{'rdf'} . 'type>', undef)}} @rdfs) {
    my $class_name = &clean($type->[2]); # $self->add_triples($rdf);
    my $tArr = (); # $self->{arrs}{$class_name};
    my $tHash = (); # $self->{hashes}{$class_name};
    foreach $case (map {@{$_->get_triples(undef, '<' . $ns{'rdf'} . 'type>', $type->[2])}} @rdfs) {
      push (@$tArr, clean($case->[0])) unless ($tHash->{clean($case->[0])});
      foreach $property (map {@{$_->get_triples($case->[0], undef, undef)}} @rdfs) {
	$tHash->{clean($property->[0])}{clean($property->[1])} = clean($property->[2]); 
      }
    }
    $self->{hashes}->{$class_name} = $tHash;
    $self->{arrs}->{$class_name} = $tArr;
  }
}

sub add {
  my ($self, $stuff) = @_;
  my $rdf = new RDF::Notation3::Triples;
  $rdf->parse_string($stuff);
  $self->add_ns($rdf->{ns}->{'<>'});
  push @rdfs, $rdf;
}

sub clean {
  my $text = $_[0];
  $text =~ s/\"(.*)\"/$1/;
  $text =~ s/<(.*)>/$1/;
  return $text;
}

sub identifier {
  my ($uri) = @_;
  $uri =~ /(.*)#(.*)/;
    return $2;
}

sub expand {
  my ($self, $property) = @_;
  unless ($property =~ "http://") {
    $property =~ s/^(.*?):/$ns{$1}/;
    $rev_ns{$ns{$1}} = $1;
   }
  return $property;
}

sub contract {
  my ($self, $property) = @_;
  $property =~ /^(.*#)(.*)$/;
  if ($rev_ns{$1}) {
    return $rev_ns{$1}.':'.$2;
  }
  foreach (sort keys %ns) {
    next unless ($ns{$_} eq $1);
    $rev_ns{$1} = $_;
    return $_ ? "$_:$2" : $2;
  }
  return $property;
}

sub n3contract {
  my ($self, $property) = @_;
  return $property unless ($property =~ 'http://');
  $property =~ /^(.*#)(.*)$/;
  if ($rev_ns{$1}) {
    return $rev_ns{$1}.':'.$2;
  }
  foreach (sort keys %ns) {
    next unless ($ns{$_} eq $1);
    $rev_ns{$1} = $_;
    return "$_:$2";
  }
  return $property;
}

sub get_property {
  my ($self, $class, $id, $property) = @_;
  $class = $self->expand($class);
    if (!$property) {
      return $self->{arrs}{$class}[$id];
    } else {
      $property = $self->expand($property);
      $id = $self->{arrs}{$class}[$id] unless ($id =~ "http://");
      return $self->{hashes}{$class}->{$id}{$property};
    }
}

sub get_properties {
  my ($self, $class, $id) = @_;
  $class = $self->expand($class);
  $id = $self->{arrs}{$class}[$id] unless ($id =~ "http://");
  return $self->{hashes}{$class}->{$id};
}

sub get_incidence {
  my ($self, $class) = @_;
  $class = $self->expand($class);
  return ($self->{arrs}{$class}, $self->{hashes}{$class});
}

sub get_filtered_properties {
  my ($self, $class, $property, $value) = @_;
  ($class, $property, $value) = map { $self->expand($_); } ($class, $property, $value);
  @results = ();
  foreach my $thing (@{$self->{arrs}{$class}}) {
    my $thing_value = $self->{hashes}{$class}->{$thing}{$property};
    next unless $thing_value;
    push @results, $thing if ($thing_value eq $value);
  }
  return @results; 
}

sub get_unique {
  my ($self, $class, $property) = @_;
  $property = $self->expand($property);
  $class = $self->expand($class);
  @results = ();
  foreach my $thing (@{$self->{arrs}{$class}}) {
    my $value = $self->{hashes}{$class}->{$thing}{$property};
    next if (!$value);
    push @results, $value unless (grep $_ eq $value, @results);
  }
  return @results;
}

sub size {
  my ($self, $class) = @_;
  $class = $self->expand($class);
  return $#{$self->{arrs}{$class}};
}

sub exists_class {
  my ($self, $class) = @_;
  $class = $self->expand($class);
  return $self->{arrs}{$class} ? 1 : 0;
}

"1";
