# Copyright 1999-2012. Parallels IP Holdings GmbH. All Rights Reserved.
package XmlLogger;

use strict;

use XmlNode;

sub new {
  my $self = {};
  bless( $self, shift );
  $self->_init(@_);
  return $self;
}

sub _init {
  my ( $self ) = @_;
  $self->{severity} = 'success';
  $self->{object_stack} = [];
  $self->{root} = XmlNode->new('execution-result');
  push @{$self->{objects_stack}}, \$self->{root};
}

my %severity_levels = (
  'success' => 10,
  'info'    => 20,
  'warning' => 30,
  'error'   => 40
);
my %levels_severity = reverse %severity_levels;

sub _max_severity {
  my ($sev1, $sev2) = @_;
  my $nsev1 = 0 + $severity_levels{$sev1};
  my $nsev2 = 0 + $severity_levels{$sev2};
  return $levels_severity{($nsev1>$nsev2)?$nsev1:$nsev2};
}

sub _checkSeverity {
  my ($self, $severity ) = @_;
  return if ($self->{severity} eq 'error');
  $self->{severity} =_max_severity($severity, $self->{severity});
}

sub _linkNodes {
  my ( $self ) = @_;
  my $child;
  foreach my $ref ( reverse @{$self->{objects_stack}}) {
    if ($child) {
      last if ( $$child->getMetadata('link') );
      $$ref->addChild($$child);
      $$child->setMetadata('link',1);
    }
    $child = $ref;
  }
}

sub beginObject {
  my ( $self, $type, $name, $uuid ) = @_;
  my $objectNode = XmlNode->new('object');
  $objectNode->setAttribute('type',$type);
  $objectNode->setAttribute('name',$name);
  if ( defined $uuid ) {
    $objectNode->setAttribute('uuid', $uuid);
  }
  push @{$self->{objects_stack}}, \$objectNode;
}

sub endObject {
  my ( $self ) = @_;
  my $topObjectRef = @{$self->{objects_stack}}[-1];
  if( scalar($$topObjectRef->getChildren('message')) ) {
    $self->_linkNodes();
  }
  pop @{$self->{objects_stack}};
}

sub addMessage {
  my ( $self, $severity, $id, $description, $code, $objectUid ) = @_;

  if (!defined($code) || $code eq '' ) {
    $code = 'msgtext';
  }

  $self->_checkSeverity($severity);
  my $messageNode = $self->createMessageNode($severity, $id, $description, $code);

  if (defined($objectUid)) {
    $self->addMessageToSpecifiedNode($messageNode, $objectUid);
  } else {
    my $topObjectRef = @{$self->{objects_stack}}[-1];
    $$topObjectRef->addChild($messageNode,1);
  }
}

sub serializeToFile {
  my ( $self, $filename, $prettyPrint, $omitXmlDeclaration ) = @_;
  open LOG, "> $filename" or return;
  binmode LOG;
  $self->{root}->setAttribute('log-location', $filename);
  my $res = $self->serialize(\*LOG, $prettyPrint, $omitXmlDeclaration);
  close LOG;
  return $res;
}

sub serialize {
  my ( $self, $fh, $prettyPrint, $omitXmlDeclaration ) = @_;
  while (@{$self->{objects_stack}} >1) {
    $self->endObject();
  }
  $self->{root}->setAttribute('status',$self->{severity} eq 'warning' ? 'warnings' : $self->{severity});
  return $self->{root}->serialize($fh, $prettyPrint, $omitXmlDeclaration);
}

sub createMessageNode {
  my ($self, $severity, $id, $description, $code) = @_;
  
  my $messageNode = XmlNode->new('message'); 
  $messageNode->setAttribute('severity',$severity);
  $messageNode->setAttribute('id',$id);
  $messageNode->setAttribute('code',$code);
  
  my $descriptionNode = XmlNode->new('description');
  $descriptionNode->setText($description);
  $messageNode->addChild($descriptionNode);
  
  return $messageNode;
}

sub addMessageToSpecifiedNode {
  my ( $self, $messageNode, $uuid ) = @_;
  
  foreach my $node (@{$self->{objects_stack}}) {
    if ($$node->isAttributeExist('uuid') && $$node->getAttribute('uuid') eq $uuid) {
      $$node->addChild($messageNode);
    }
  }
}


1;