package Common::WriteXML;

# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#   Copyright RoyaltyShare, Inc. 2005
#   All Rights Reserved.  Licensed Software.
#
#   THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF RoyaltyShare, Inc.
#   The copyright notice above does not evidence any actual or
#   intended publication of such source code.
#
#   PROPRIETARY INFORMATION, PROPERTY OF RoyaltyShare, Inc.
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#
#    $Id$
#    $Source$
#
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

# ---------------------------------------------------------------------------
# Common::WriteXML is designed to be a easy interface to writing XML.
#
# GetXMLString, the public function, simply takes a hashref. This
# hashref should have all data that needs to be printed to XML.
#
# Any necessary structure can be written in XML using this hashref.
#
# Here are some examples (courtesey of Data::Dumper):
#
# DATA:
# {
#          'foo' => {
#                     'list' => [
#                                 {
#                                   'text' => 'one',
#                                   'value' => 1
#                                 },
#                                 {
#                                   'text' => 'two',
#                                   'value' => 2
#                                 },
#                                 {
#                                   'text' => 'three',
#                                   'value' => 3
#                                 },
#                                 {
#                                   'text' => 'four',
#                                   'value' => 4
#                                 },
#                                 {
#                                   'text' => 'five',
#                                   'value' => 5
#                                 }
#                               ]
#                   }
#        };
# ---------------------------------------------------------------------------
#
# The resulting XML:
#
#  <Root>
#    <Foo>
#      <List>
#        <Text>one</Text>
#        <Value>1</Value>
#      </List>
#      <List>
#        <Text>two</Text>
#        <Value>2</Value>
#      </List>
#      <List>
#        <Text>three</Text>
#        <Value>3</Value>
#      </List>
#      <List>
#        <Text>four</Text>
#        <Value>4</Value>
#      </List>
#      <List>
#        <Text>five</Text>
#        <Value>5</Value>
#      </List>
#    </Foo>
#  </Root>
# ---------------------------------------------------------------------------

use strict;

#use warnings;
use lib '/app/tools/common/lib';
use Common::XMLWriter;
use Common::XMLFileWriter;
use Common::Assert;

sub WriteXMLFile {
    my ( $data, $path, $rootTag ) = @_;

    open XMLFILE, "> $path" or die "ERROR - unable to open $path for writing: $!\n";

    my $xw = Common::XMLFileWriter->new(*XMLFILE);

    $rootTag = 'Root' unless defined $rootTag;

    # Make sure we have both of our variables, and that $hr_data is a hashref.
    assert($data);
    assert($xw);

    writeXML( $xw, $data, $rootTag );

    close(XMLFILE);
}

# -----------------------------------------------
# sub: GetXMLString
#  in: hashref data structure
# out: string containing XML
# -----------------------------------------------
# Just a wrapper around _writeXMLhash.
# Create the XMLWriter object here so
# the caller doesn't need to know about it.
# -----------------------------------------------
sub GetXMLString {
    my ( $data, $rootTag, %options ) = @_;

    my $xw = Common::XMLWriter->new(%options);

    $rootTag = 'Root' unless defined $rootTag;

    # Make sure we have both of our variables, and that $hr_data is a hashref.
    assert($data);
    assert($xw);

    writeXML( $xw, $data, $rootTag );

    return $xw->{XML_STR};
}

sub writeXML {
    my ( $xw, $data, $tag, %params ) = @_;

    my $type = ref($data);
    if ($type) {

        if ( 'HASH' eq $type ) {
            _writeXMLHash( $xw, $data, $tag, %params );
        } elsif ( 'ARRAY' eq $type ) {
            _writeXMLArray( $xw, $data, $tag, %params );
        } elsif ( $data->can('writeXML') ) {
            $data->writeXML( $xw, $tag, %params );
        }

    } else {

        # Just a scalar.
        #
        $xw->element( $tag, $data, %params );
    }
}

# ----------------------------------------------
# sub: _writeXMLHash
#  in: xml writer, hash ref, tag name
# out: 1 (updated xml writer obj)
# ----------------------------------------------
# go through the data structure and
# find the hashes, arrays, and basic
# elements. Use the XMLWriter to make
# the resulting XML.
# ----------------------------------------------
sub _writeXMLHash {
    my ( $xw, $hr_data, $tagname, %params ) = @_;

    if ($tagname) {
        $xw->starttag( $tagname, %params );
    }

    foreach my $elem ( keys %{$hr_data} ) {
        writeXML( $xw, $hr_data->{$elem}, $elem );
    }

    if ($tagname) {
        $xw->endtag($tagname);
    }

    return 1;
}

# ----------------------------------------------
# sub: _writeXMLarray (private)
# ----------------------------------------------
#  in: xml writer, array ref, tag name
# out: 1 (updated xml writer obj)
# ----------------------------------------------
# go through the array ref and
# find the hashes and arrays. Use the
# XMLWriter to make the resulting XML.
# ----------------------------------------------
sub _writeXMLArray {
    my ( $xw, $ar_data, $tagname, %params ) = @_;

    my $i         = 0;
    my $arraySize = scalar @$ar_data;
    foreach my $elem ( @{$ar_data} ) {
        my %outParams;
        unless ( $xw->{OPTIONS}{skip_array_indexing} ) {
            $outParams{i}    = $i;
            $outParams{size} = $arraySize;
            foreach my $key ( keys %params ) {
                $outParams{$key} = $params{$key};
            }
        }
        writeXML( $xw, $elem, $tagname, %outParams );
        $i++;
    }

    return 1;
}

###
1;    # Play nicely.
###
