package Catalog::XML;
use Catalog::RF;
use base 'Catalog::RF';
use strict;

#
# Resource File (RF) utilities
# Author: Christian Cadieux
# Transform back and forth between storade resource files and XML documents.
#
# <property name=category type=agent>storade</property>
#    { property => { 
#                    category => { 
#                           _VAL => 'storade',
#                           _ATT => { name => "category", type => "agent" },
#                                }
#                  }
#    }

##########################################
#  XML Conversions
##########################################

use XML::LibXML;
use System;
use strict;
use vars qw($ERR);

sub parseFile {
  my($class, $file, $arg) = @_;

  if (open(O, $file)) {
     my @l = <O>; close(O);
     my $report = $class->parse("@l", $arg);
     bless($report, "Catalog::XML");
  } else {
     $class->err("opening $file: $! \n");
     return undef;
  }
}


# { ROOT => "implementation",
#   hash  => { interface => "name" },
#   array => { args => 1 },
# }

sub parse {
   my($class, $string, $arg) = @_;
   my $parser = XML::LibXML->new();
   $ERR = undef;

   my $dom;
   eval {
     $dom  = $parser->parse_string($string);
   };
   if ($@) {
      $class->err("Error in parse: $@ " . substr($string, 0, 100));
      return undef;
   }
   my $elem = $dom->getDocumentElement();
   if (!$elem) {
      $class->err("Error in parse: " . substr($string, 0, 100));
      return undef;
   }
   $arg->{ROOT} = $elem->nodeName() if (!$arg->{ROOT});

   my $rep1 = $class->_parse($elem, $arg, 0, "");
   my $report = {};
   $report->{$arg->{ROOT}} = $rep1;
   $report->{_ARG} = $arg;
   return $report;
}



sub _parse {
  my($class, $node, $arg, $level, $key) = @_;
  my $report = {};
  my $attr = {};
  my $nodeName = $node->getName();
  $key .= "." if ($key);
  $key .= $nodeName;
  my @attributes = $node->attributes();
  my $attr_cnt;
  foreach my $att (@attributes) {
     my $t = $att->getType();
     my $name = $att->name();
     my $val  = $att->value();
     if ($name) {
       $attr->{$name} = $val; $attr_cnt++;
     }
  }
  $report->{_ATT} = $attr if ($attr_cnt > 0);
  my @nodeChilds = $node->getChildNodes();
  if ($#nodeChilds == 0) {
     $report->{_VAL} = $node->textContent();
     return $report;
  } 

  foreach my $el (@nodeChilds) {
    next if ($el->getType() != &XML::LibXML::ELEMENT_NODE() );
    my $name = $el->getName();
    my $pr;
    my @ch1 = $el->getChildNodes();

    my $rep1 =  $class->_parse($el, $arg, $level+1, $key);
    my($rc);
    if ( $rc = $class->compare("hash", $arg, $key, $name)) {
      my $k = $rep1->{_ATT}{$rc};
      $report->{$name}{$k} = $rep1;
      $report->{$name}{_ATT}{_KEY} = $rc;

    } elsif ( $rc = $class->compare("array", $arg, $key, $name)) {
      push(@{$report->{$name}}, $rep1);

    } else {
      $report->{$name} = $rep1;
    }
  }
  return $report;
}

sub compare {
  my($class,$type, $arg, $key, $name) = @_;
  my @L = split(/\./, $key);

  if (exists $arg->{$type}{$name}) {
    return $arg->{$type}{$name};
  }
  return undef;
}

# turn into dot delimited report
#
sub toText {
  my($class, $obj) = @_;
  $obj = $class if (ref($class));

  print &_toText($obj, "");
}

sub _toText {
   my($obj, $prefix) = @_;

   my $out;
   $prefix = "$prefix." if ($prefix);
   if (ref($obj) eq "HASH") {
      if (exists $obj->{_ATT}) {
         my $att = $obj->{_ATT};
         foreach my $a (keys %$att) {
            $out .= $prefix . "_attribute.$a\t$att->{$a}\n";
         }
      }
      foreach my $el (sort keys %$obj) {
         $out .= &_toText($obj->{$el}, "$prefix$el");
      }
   } elsif (ref($obj) eq "ARRAY") {
      my $x;
      for ($x=0; $x <= $#$obj; $x++) {
         $out .= &_toText($obj->[$x], "$prefix$x");
      }
   }
   return $out;
}


1;
