package Wiki::Toolkit::Store::Trivial;
use base Wiki::Toolkit::Store;
our $VERSION = '0.00_01';
use strict; use warnings; use Carp;

#
# WARNING: This module is for development use only. In particular, it does NOT
# bother with file locking.
#


use IO::File;
use File::Glob ':glob';

sub _name2filename {
  my ($self,$name,$version) = @_;
  $version ||= 'latest';
  croak "'$name' v. $version is an illegal node name"
    unless $self->valid_name($name,$version);
  ($name) = $name =~ /^([^\/]+)$/;
  ($version) = $version =~ /^(latest|\d+)$/;
  return wantarray 
    ? ($self->_store_dir,$name,$version)
    : join '/', ($self->_store_dir(),"$name.$version");
}

sub _store_dir {
  my $self = shift;
  my $dir = $self->registry->get($self->name,'store_dir');
  $dir =~ s|(.)/$|$1|;
  return $dir;
}

sub node_exists {
  my $self = shift;
  my $filename = $self->_name2filename(@_);
  return ( -e "$filename.txt" ) && ( -e "$filename.meta" );
}

sub latest_version {
  my $self = shift;
  my $name = shift;
  my ($v1, $v2);

  # cleanup $name
  $name = ( $self->_name2filename($name) )[1];

  # FIXME not quite right:
  my @files = bsd_glob( $self->_store_dir . "/$name.[0-9]*.txt" ); 
  @files = sort { $a =~ /\.([0-9]+)\.txt/; $v1 = $1;
                  $b =~ /\.([0-9]+)\.txt/; $v2 = $1;
                  $v1 <=> $v2
                } @files;

  $files[-1] =~ /\.([0-9]+)\.txt/;
  return $1;
}

sub _open_files {
  my $self = shift;
  my @list = map { $_ =~ /([^\/]+)\.(latest|[0-9]+)\.txt$/;
                   $self->open_node($1,$2); } @_;
  return wantarray ? @list : \@list;
}
  

sub delete_node {
  my $self = shift;
  my $name = shift;
  my $filename = $self->_name2filename( $name ); 
  return unlink "$filename.txt" && unlink "$filename.meta";
}

sub read_metadata {
  my $self = shift;
  my ($name,$version) = @_;
  $version ||= 'latest';
  my $filename = $self->_name2filename($name,$version);

  croak "Could not open '$name' (v. $version) because it does not exist"
    unless ($self->node_exists($name,$version));
  my $fh = IO::File->new( "$filename.meta", '<' );
  croak "Could not open '$name' (v. $version) metadata for reading: $!" unless $fh;

  {
    local $/; # undefine INPUT_RECORD_SEPARATOR to slurp file
    return $self->default_node_class()->text2meta(<$fh>)
  } # note that text2meta returns either a hashref or a hash, depending on context
}

sub write_metadata {
  my $self = shift;
  my $node = shift;
  my $name = $node->name();
  my $version = $node->version();

  croak "I can't store a node '$name'" unless ($self->valid_name($name,$version));
  my $filename = $self->_name2filename($name,$node->version());
  my $fh = IO::File->new( "$filename.meta", '>' );
  croak "Could not open '$node' (v. $version) metadata for writing: $!" unless $fh;
  
  print $fh $node->meta2text();
  undef $fh;

  return $node;
}

sub read_content {
  my $self = shift;
  my ($name,$version) = @_;
  $version ||= 'latest';
  my $filename = $self->_name2filename($name,$version);

  croak "Could not open '$name' (v. $version) because it does not exist"
    unless ($self->node_exists($name,$version));
  my $fh = IO::File->new( "$filename.txt", '<' );
  croak "Could not open '$name' (v. $version) content for reading: $!" unless $fh;

  {
    local $/; # undefine INPUT_RECORD_SEPARATOR to slurp file
    return <$fh>
  }
}

sub write_content {
  my $self = shift;
  my $node = shift;
  my $name = $node->name();
  my $version = $node->version();

  croak "I can't store a node '$name'" unless ($self->valid_name($name,$version));
  my $filename = $self->_name2filename($name,$node->version());
  my $fh = IO::File->new( "$filename.txt", '>' );
  croak "Could not open '$node' (v. $version) content for writing: $!" unless $fh;
  
  print $fh $node->content();
  undef $fh;

  return $node;
}

sub valid_name {
  my ($self,$name,$version) = @_;
  return ($version =~ /^\d+$/ || $version eq 'latest') && $name && !($name =~ /\//);
}

sub _list_all_nodes {
  my $self = shift;
  my @files = bsd_glob( $self->_store_dir . "/*.latest.txt" );
  return $self->_open_files( @files );
}

sub _list_all_nodes_all_version {
  my $self = shift;
  my @files = bsd_glob( $self->_store_dir . "/*.[0-9]*.txt" );
  return $self->_open_files( @files );
}

sub _set_latest {
  my ($self,$name,$version) = @_;
  my $filename = $self->_name2filename($name,'latest');
  # cleanup
  ($name,$version) = ( $self->_name2filename($name,$version) )[1,2];
  unlink ("$filename.txt", "$filename.meta");
  symlink "$name.$version.txt", "$filename.txt";
  symlink "$name.$version.meta", "$filename.meta";
  return $version;
}
