################################################################
#
# Module for BuildMonitor DB logging.
#
package notify_buildmonitor;

use BSConfig;
use plugins::BuildMonitorDB;
use Data::Dumper;
use BSRPC;
use MIME::Base64;
use JSON::XS;

use strict;

sub new {
  my $self = {};
  bless $self, shift;
  return $self;
}

my %event_handlers = (
  'SRCSRV_START' => \&BuildMonitorDB::srcsrv_start,

  'SRCSRV_CREATE_PROJECT' => \&BuildMonitorDB::srcsrv_create_project,
  'SRCSRV_UPDATE_PROJECT' => \&BuildMonitorDB::srcsrv_update_project,
  'SRCSRV_DELETE_PROJECT' => \&BuildMonitorDB::srcsrv_delete_project,

  'SRCSRV_CREATE_PACKAGE' => \&BuildMonitorDB::srcsrv_create_package,
  'SRCSRV_UPDATE_PACKAGE' => \&BuildMonitorDB::srcsrv_update_package,
  'SRCSRV_DELETE_PACKAGE' => \&BuildMonitorDB::srcsrv_delete_package,

  'SRCSRV_REQUEST_ACCEPTED' => \&BuildMonitorDB::srcsrv_request_accepted,
  'SRCSRV_REQUEST_STATECHANGE' => \&BuildMonitorDB::srcsrv_request_statechange,

  'SRCSRV_COMMIT' => \&BuildMonitorDB::srcsrv_commit,

  'BUILD_START' => \&BuildMonitorDB::build_start,
  'BUILD_KILL' => \&BuildMonitorDB::build_kill,
  'BUILD_UNCHANGED' => \&BuildMonitorDB::build_unchanged,
  'BUILD_SUCCESS' => \&BuildMonitorDB::build_success,
  'BUILD_FAIL' => \&BuildMonitorDB::build_fail,
  'BUILD_BROKEN' => \&BuildMonitorDB::build_broken,
  'BUILD_UNRESOLVABLE' => \&BuildMonitorDB::build_unresolvable,
  'BUILD_EXCLUDED' => \&BuildMonitorDB::build_excluded,
  'BUILD_DISABLED' => \&BuildMonitorDB::build_disabled,

  'REPO_PUBLISH_STATE' => \&BuildMonitorDB::repo_publish_state,
  'REPO_PUBLISHED' => \&BuildMonitorDB::repo_published,
);

sub extract_name_desc {
  my ($hash) = @_;

  my $extracted_hash = {};

  for my $key (keys %$hash) {
    #next if $key ne 'name' && $key ne 'description';
    next if $key ne 'name';
    $extracted_hash->{$key} = $hash->{$key};
  }

  return $extracted_hash;
}

sub extract_proj_in_projpack {
  my ($p) = @_;

  my @extracted_project;
  for my $proj (@{$p->{'projpack'}->{'project'}}) {
    my $proj_name = $proj->{'name'};
    if( BuildMonitorDB::check_proj_pattern_for_relay($proj_name) ) {
      next;
    }
    my $exp = extract_name_desc($proj);
    my @pkgs;
    for my $pack (@{$proj->{'package'}}) {
      push @pkgs, extract_name_desc($pack);
    }
    $exp->{'package'} = \@pkgs;
    push @extracted_project, $exp;
  }

  return @extracted_project;
}

sub relay_src_server {
  my ($type, $p) = @_;

  return unless $BSConfig::relay_obs_server;

  if( $type ne 'SRCSRV_START' ) {
    my $proj_name = "";
    $proj_name=$p->{'project'} if defined $p->{'project'};
    $proj_name=$p->{'targetproject'} if defined $p->{'targetproject'};

    return if $proj_name eq "";

    if( BuildMonitorDB::check_proj_pattern_for_relay($proj_name) ) {
      print "[", __FILE__, ":", __LINE__, "] Skip relaying $proj_name.\n";
      return;
    }
  }

  my $uri= "$BSConfig::relay_obs_server/source";
  my $param = {
    'request' => 'POST',
    'uri' => $uri,
    'timeout' => 60,
  };
  $param->{'proxy'} = $BSConfig::proxy if defined $BSConfig::proxy;
  my $args = {};
  for my $key (sort keys %$p) {
    next if $key eq 'dispatches';
    next if $key eq 'projpack';
    next if $key eq 'description';
    if( $key eq 'reason') {
      $args->{$key} = BuildMonitorDB::parse_reason($p->{$key});
    } else {
      $args->{$key} = $p->{$key} if defined $p->{$key};
    }
    print "  key=[$key] value=[$args->{$key}]\n";
  }
  if( $type eq 'SRCSRV_START') {
    my @extracted_project = extract_proj_in_projpack($p);
    print "extracting...\n";
    my $projpack = {};
    $projpack->{'project'} = [];
    for my $proj (@extracted_project) {
      select STDOUT;
      my $proj_name = $proj->{'name'};
      print "Sending project $proj_name\n";
      $projpack->{'project'} = [$proj];
      my @aargs = map {"$_=$args->{$_}"} sort keys %$args;
      push @aargs, "projpack=".encode_base64(encode_json($projpack),'');
      my @para = ("cmd=relay_notify",
          "notify_type=$type",
          @aargs);
      print "Relaying events to $uri\n";
      print "notify_type = $type, param=[@para]\n";
      $|=1;
      eval {
        BSRPC::rpc($param, undef, @para);
      };
      if ($@) {
        warn($@);
      }
    }
  } else {
    my @aargs = map {"$_=$args->{$_}"} sort keys %$args;
    my @para = ("cmd=relay_notify",
        "notify_type=$type",
        @aargs);
    select STDOUT;
    print "Relaying events to $uri\n";
    print "notify_type = $type, param=[@para]\n";
    $|=1;
    eval {
      BSRPC::rpc($param, undef, @para);
    };
    if ($@) {
      warn($@);
    }
  }

}

sub notify() {
  my ($self, $type, $paramRef ) = @_;

  # you should add the statements below to BSConfig.pm
  #our $notification_plugin = "notify_buildmonitor";
  #our $build_monitor_db_conf = "/usr/lib/obs/server/build_monitor_db.conf";
  my $evhandler = $event_handlers{$type};
  if( defined $BSConfig::build_monitor_db_conf ) {

    my $g_dbh = BuildMonitorDB::connect_db($BSConfig::build_monitor_db_conf);
    if( ! $g_dbh ) {
      print "[", __FILE__, ":",__LINE__, "] BuildMonitorDB::connect_db() failed.\n";
      return ;
    }

    if( $evhandler ) {
      $evhandler->($paramRef);
    } else {
      print "[BuildMonitor] undefined event type: $type\n";
    }
  }

  if( $evhandler ) {
    print "[", __LINE__, "] relaying $type...\n";
    relay_src_server($type, $paramRef);
  }
}

1;
