#!perl -w

=pod

=head1 NAME

Neuron::SWC::Read - Read and parse the SWC file format

=head1 SYNOPSIS

Neuron::SWC::Read provides different parsing functions to return the header or
data portion of the SWC file format used to describe artificial neural
morphologies.

=head1 FUNCTIONS

=over 0

=item *
I<%header> = readHeader(I<file>);

parses the file's informational header and returns a hash containing it.

=item *
printHeader(I<header>);

prints information from header hash in a nicely formatted way.

=item *
I<@neuron> = readData(I<file>);

parses actual neuron data and returns it in an array of hashes.

=back

=head1 AUTHOR

Gunther Schmidl <gschmidl@gmx.at>

=cut

package Neuron::SWC::Read;
use strict;
use warnings;

use Neuron::Morphometrics::Tools qw(initSegments);

# prepare variable export

use vars qw(@ISA @EXPORT @EXPORT_OK $VERSION);
require Exporter;
@ISA = qw(Exporter);
@EXPORT = qw(readHeader readData printHeader);
@EXPORT_OK = qw();
$VERSION = 1.00;






#==============================================================================
#
# readHeader(file) - parse SWC file header and return hash with all values.
#
#==============================================================================

sub readHeader($)
{
    my($dummy, $desc, $val);
    my %header;

    open FILE, "<$_[0]" or die "$_[0] not found: $!";
    while(defined($_ = <FILE>))
    {
        chomp;
        s/^\s+//;                           # kill initial whitespace

        # do this until no more '#' marks are encountered
        last unless m/\#/;
        ($dummy, $desc, $val) = split /\s+/, $_, 3;
        if (defined($desc) && defined($val))
        {
            $header{$desc} = $val;
        }
    }

    close FILE;
    return %header;
}






#==============================================================================
#
# printHeader(hash) - print header from hash.
#
#==============================================================================

sub printHeader(%)
{
    my($desc, $val);

format STDOUT =
@<<<<<<<<<<<<<<<<<<<<< @<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
$desc,                 $val
.

    while (($desc,$val) = each %{$_[0]})
    {
        write(STDOUT);
    }
}






#==============================================================================
#
# readData(file) - parse neuron data and return array of hashes.
#
#==============================================================================

sub readData($)
{
    my (@one, @neuron, $n);

    push @neuron, +{};                      # empty hash to start at @neuron[1]

    open FILE, "<$_[0]" or die "$_[0] not found: $!";
    binmode FILE, ":raw";
    while(defined($_ = <FILE>))
    {
        chomp;
        do
        {
            s/^\s+//;                       # kill initial whitespace
            @one = split /\s+/, $_, 7;      # split input line in components
            $n = +{};                       # create anonymous hash

            # populate hash
            $n->{'number'} = $one[0];       # number of node
            $n->{'flag'}   = $one[1];       # flag to indicate structure part
            $n->{'x'}      = $one[2];       # spatial x coordinate
            $n->{'y'}      = $one[3];       # spatial y coordinate
            $n->{'z'}      = $one[4];       # spatial z coordinate
            $n->{'d'}      = $one[5] * 2;   # diameter
            $n->{'parent'} = $one[6];       # parent node

            # put it in the array
            push @neuron, $n;

            my $parent = $one[6];

            # create link from parent to children, unless we are at the root
            # (we can because a parent will always precede its children)
            if ($parent != -1)
            {
                $neuron[$parent]->{'kids'} = []
                    unless exists ${neuron[$parent]}->{'kids'};
                push @{$neuron[$parent]->{'kids'}}, $n;
            }
        }
        unless m/\#/;
    }

    close FILE;

    initSegments(\@neuron);

    return @neuron;
}