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

use strict;
use warnings;
use Logging;
use XmlNode;
use File::Temp;
use AgentConfig;
use Encoding;
use POSIX;
use IPC::Run;
use Symbol;
use HelpFuncs;



sub checkResponceResult{
  my $response = shift;
  if( $response =~ /\<\?xml.*\?\>\s*([\w\W\n\r\s]*){1}/mg  ){
    return $1;
  }
  return;
}


my $debugparser = 0;

sub getXPath{
  my ( $xmlbody, $elementValue, $elementAttributes, $xpath, $tail ) = @_;
  my $idx = 0;
  my $len = scalar(@{$xpath});
  die "Invalid xpath\n" if $len==0;
  Logging::debug( "Parse xml:$xmlbody\n" ) if $debugparser;
  while($xmlbody =~ m/\<(.+?)(\s.*?)?\>(.*?)\<\/\1\>/sg or $xmlbody =~ m/\<(.+?)(\s.*?)?\/\>/sg ){
    if( $1 eq $xpath->[$idx] ){
      ${$tail} = HelpFuncs::trim( $' ) if defined $tail;
      $xmlbody = $3;
      Logging::debug( "Found '$1'.xml:$xmlbody\n" ) if $debugparser;
      $idx += 1;
      if( $idx==$len ){
        ${$elementValue} = ( defined $3 ? HelpFuncs::trim( $3 ) : "" ) if defined $elementValue;
        ${$elementAttributes} = HelpFuncs::trim( $2 ) if defined $elementAttributes;
        return 1;
      }
    }
    else {
      $xmlbody = $';
      Logging::debug( "Read next:$xmlbody\n" ) if $debugparser;
    }
  }
  return 0;
}

sub getErrorFromResult{
  my( $response, $errCode, $errMsg ) = @_;
  my @xpath = ( 'response', 'errcode' );
  if( getXPath( $response, $errCode, undef, \@xpath ) ){
    $xpath[1] = 'errmsg';
    getXPath( $response, $errMsg, undef, \@xpath );
    return 1;
  }
  return;
}


sub analyzeResponseErrCode{
  my( $errCode, $errMsg ) = @_;
  $errMsg = "" if not defined $errMsg;
  $errMsg = ": $errMsg" if $errMsg;
  die "Invalid parameter$errMsg\n" if $errCode == 1;
  die "Invalid task id$errMsg\n" if $errCode == 2;
  die "Invalid session id$errMsg\n" if $errCode == 3;
  die "Low disk space for backup$errMsg\n" if $errCode == 11;
  die "Subprocess execute error from pmmcli$errMsg\n" if $errCode == 1000;
  die "Runtime errror from pmmcli$errMsg\n" if $errCode == 1001;
  die "Unhandled exception from pmmcli$errMsg\n" if $errCode == 1002;
  die "Unknown error from pmmcli$errMsg\n" if $errCode != 0;
  return;
}

sub getResponseErrCode{
  my $xmlbody = shift;
  my( $errCode, $errMsg, $taskId );
  getErrorFromResult( $xmlbody, \$errCode, \$errMsg  ) or die "Could parse responce. Error code not found:  $xmlbody\n";
  return analyzeResponseErrCode( $errCode );
}

sub getTaskIdFormResult{
  my $xmlbody = shift;
  $xmlbody = checkResponceResult( $xmlbody ) or die "Could not get task id. Invalid xml response:  $xmlbody\n";
  getResponseErrCode( $xmlbody );
  my @xpath = ( 'response', 'data', 'task-id' );
  my $taskId;
  if ( !getXPath( $xmlbody, \$taskId, undef, \@xpath ) ) {
    die "Could not obtain taskId from responce: $xmlbody\n";
  }
  return $taskId;
}

# 0 - dumping
# 1 - finished
# 2 - starting
sub getTaskProgressFormResult{
  my ( $xmlbody, $progress, $finished, $logLocation ) = @_;
  $xmlbody = checkResponceResult( $xmlbody ) or die "Could not get task status. Invalid xml response:  $xmlbody\n";
  getResponseErrCode( $xmlbody );
  my $taskStatus;
  my @xpath = ( 'response', 'data', 'task-status' );
  getXPath( $xmlbody, \$taskStatus, undef, \@xpath ) or die "Could not parse responce. Task status not found:  $xmlbody\n";
  @xpath = ( 'working' );
  my( $working );
  if( getXPath( $taskStatus, \$working, undef, \@xpath ) ){
    @xpath = ( 'starting' );
    if( getXPath( $working, undef, undef, \@xpath ) ){
      return 2;
    }
    @xpath = ( 'dumping' );
    my $dumping;
    if( !getXPath( $working, undef, \$dumping, \@xpath ) ){
      die "Could not parse working status: $working\n";
    }
    my ( $totalDomains, $totalAccounts, $doneDomains, $doneAccounts, $currectObj );
    $totalDomains = $totalAccounts = $doneDomains = $doneAccounts = $currectObj = "";
    $totalAccounts = $1 if $dumping =~ /total-accounts=\"([\+\-\d]+)\"/;
    $totalDomains = $1 if $dumping =~ /total-domains=\"([\+\-\d]+)\"/;
    $doneDomains = $1 if $dumping =~ /completed-domains=\"([\+\-\d]+)\"/;
    $doneAccounts = $1 if $dumping =~ /completed-accounts=\"([\+\-\d]+)\"/;
    $currectObj = $1 if $dumping =~ /current-object=\"([\w\.]+)\"/;
    my $progressValue = "";
    $progressValue .= "Accounts [$doneAccounts/$totalAccounts]" if $doneAccounts or $totalAccounts;
    if( $doneDomains or $totalDomains ){
      $progressValue .= ", " if $progressValue;
      $progressValue .= "Domains [$doneDomains/$totalDomains]";
    }
    if( $currectObj ){
      $progressValue .= ", " if $progressValue;
      $progressValue .= "Dumping '$currectObj' in progress";
    }
    $progressValue = "Dumping" if not $progressValue;
    ${$progress} = $progressValue if $progress;
    return 0;

  }
  @xpath = ( 'finished' );
  my $finishedData;
  if( getXPath( $taskStatus, undef, \$finishedData, \@xpath ) ){
    my ($log, $finishState );
    $log = $finishState = "";
    $log = $1 if $finishedData =~ /log\-location=\"(.+)\"/;
    if( $finishedData =~ /status=\"(\w+)\"/ ){
      $finishState = $1;
      if( $finishState ne 'success' and $finishState ne 'error' and $finishState ne 'warnings' ) {
        Logging::error( "Unknown finished state '$finishState'", 'UtilityError' );
        $finishState = 'error';
      }
    }
    else {
      Logging::error( "Cannot parse finished status. Return error",'UtilityError' );
      $finishState = 'error';
    }
    ${$finished} = $finishState if $finished;
    ${$logLocation} = $log if $logLocation;
    return 1;
  }
  die "Could not parse task status: $taskStatus\n";
}

sub parseCheckDumpResult{
  my $xmlbody = shift;
  $xmlbody = checkResponceResult( $xmlbody ) or die "Could not check dump. Invalid xml response:  $xmlbody\n";
  my @xpath = ( 'dump', 'dump-status' );
  my ( $content, $attributes, $tail );
  my $ret = 0;
  if (getXPath($xmlbody, \$content, \$attributes, ['dump'], \$tail)) {
    $xmlbody = $content;
    while (getXPath($xmlbody, \$content, \$attributes, ['dump-status'], \$xmlbody)) {
      Logging::debug( "Found dump status: '$attributes'\n" );
      my ($status) = $attributes =~ /dump-status=\"([\w-]+)\"/;
      if( $status ne 'OK' ) {
        $ret = 1;
        last;
      }
    }
  } else {
      $ret = 1;
  }
  return $ret;
}

sub test{
  print "Check pmm api responces\n";

  my $errMsg = "This is error Message";

  my $data  = <<EOF;
<?xml version="1.0" encoding="UTF-8"?>
<response>
<errcode>0</errcode>
<errmsg>$errMsg</errmsg>
<data>
  <task-id>123987</task-id>
  <task-status>
    <working>
        <dumping total-domains="12" total-clients="24" completed-domains="2" completed-clients="2" current-object="beper"/>
    </working>
  </task-status>
</data>
</response>
EOF


  print "Check task id\n";
  my $taskId = getTaskIdFormResult( $data );
  print "Get task id: $taskId\n";
  die "Could not get task id " if $taskId != 123987;

  print "Check task progress\n";
  my $progress;
  getTaskProgressFormResult( $data, \$progress );
  print "Get task progress: $progress\n";
  return;
}




1;