package BAST::M::File;

use strict;
use warnings;
use IO::File;
use base qw/Catalyst::Base/;

sub process {
  my ($self, $c) = @_;
  my $path = $self->filename($c);
  if (my $in = $c->req->document) {
    if (my ($file) = $in->findnodes("/node/file")) {
      if (-e $path) {
        die "${path} exists but is not a file" unless -f _;
      }
      if (my ($data) = $file->findnodes("data")) {
        $self->write_file($c, $data->string_value);
      }
    } elsif (my ($dir) = $in->findnodes("/node/directory")) {
      if (-e $path) {
        die "${path} exists but is not a file" unless -d _;
      } else {
        mkdir($path) || die "Couldn't create directory ${path}: $!";
      }
    }
  }
  $c->res->document($self->return_document($c));
}

sub return_document {
  my ($self, $c) = @_;
  my $doc = new XML::LibXML::Document;
  my $node = $doc->createElement('node');
  my $path = $self->filename($c);
  if (-f $path) {
    my $file = $doc->createElement('file');
    my $data = $doc->createElement('data');
    $data->appendChild($doc->createTextNode($self->read_file($c)));
    $file->appendChild($data);
    $node->appendChild($file);
  } elsif (-d $path) {
    my $dir = $doc->createElement('directory');
    my $dirhandle;
    opendir($dirhandle, $path);
    while (my $sub = readdir($dirhandle)) {
      my $el = $doc->createElement('entry');
      $el->appendChild($doc->createTextNode($sub));
      $dir->appendChild($el);
    }
    $node->appendChild($dir);
  }
  $doc->setDocumentElement($node);
  return $doc;
}

sub filename {
  my ($self, $c) = @_;
  return '/'.join('/',@{$c->req->args});
}

sub read_file { # Not used by default, provided for stuff that inherits from us
  my ($self, $c) = @_;
  my $file = $self->filename($c);
  local $/ = undef;
  my $fh = new IO::File;
  $fh->open($file, '<')
    || die "Error: $! opening file";
  my $data = $fh->getline;
  defined $data || die "Error: $! reading data";
  $fh->close
    || die "Error: $! closing file";
  return $data;
}

sub write_file {
  my ($self, $c, $data) = @_;
  my $file = $self->filename($c);
  my $fh = new IO::File;
  $fh->open($file.'.new', '>')
          || die "Error: $! opening new file";
  $fh->print($data) || die "Error: $! writing output";
  $fh->close
    || die "Error: $! closing new file";
  if (-e $file) {
    link($file,$file.'.old')
      || die "Error: $! linking backup to master";
    unlink($file)
      || die "Error: $! unlinking master";
  }
  link($file.'.new',$file)
    || die "Error: $! linking master to new file";
  unlink($file.'.new')
    || die "Error: $! unlinking new file";
  if (-e $file.'.old') {
    unlink($file.'.old')
      || die "Error: $! unlinking backup";
  }
}

1;
