#! /usr/bin/perl -w
# Copyright (C) 2020-2021 Arne Wichmann <aw@saar.de>
#
# This little thing is distributed under the GNU General Public License,
# version 2. If you need the license, ask your distributor for it.

use strict;

use TOML::Parser;

sub processitem($$);
sub searchname($$$);

my $parser = TOML::Parser->new();
my $data = $parser->parse(join("",<>));

our($domain,$defaultmonitoring,$searchdomain)=(".","ping",".");

processitem($data,".");

sub processitem($$) { # argument is a reference to a hash
  my($item)=shift;
  my($name)=shift;
  ref($item) eq "HASH" or die "no hash?";

  # this value will be overwritten by each recursion (dynamic scope)
  # explanation see lihordb
  local($defaultmonitoring)=$defaultmonitoring;
  local($domain)="$domain";

  if (exists($item->{"name"})) {$name=$item->{"name"}}
  if (exists($item->{"isdomain"}) and $item->{"isdomain"}) {
    $domain="$name.$domain";
    if (exists($item->{"domain"})) { $domain=$item->{"domain"} }
    if (exists($item->{"monitoring"}))
      { $defaultmonitoring=$item->{"monitoring"} }

  } else {
    if (exists($item->{"domain"})) { # should this be supported?
      warn "domain only supported in domain definitions. skipping $name";
      return;
    }
    my ($monitoring)=$defaultmonitoring;
    if (exists($item->{"monitoring"})) { $monitoring=$item->{"monitoring"}; }

    return if $monitoring eq "none";
    if (exists($item->{"ip"})) {
      my(@ip);
      if (ref($item->{"ip"}) eq "ARRAY") { @ip=@{$item->{"ip"}} } 
      else {
	ref($item->{"ip"}) eq "" or warn "ip not scalar but "
	  .ref($item->{"ip"}).", things might break - please report this!";
        @ip=($item->{"ip"});
      }

      for (@ip) {
        if (/[0-9]+(\.[0-9]+){3}/) {
	  print "object Host \"$name.$domain\" {\n";
	  print "  import \"liho-host\"\n";
	  print "  address = \"$_\"\n";
	  # TODO smart & mem??
	  if (exists($item->{"smart"})) { # implies linux
	    print "  vars.os = \"Linux\"\n";
	    my(@smart);
	    if (ref($item->{"smart"}) eq "ARRAY") { @smart=@{$item->{"smart"}} }
	    else {
	      ref($item->{"smart"}) eq "" or warn "smart not scalar but "
		.ref($item->{"smart"})
		.", things might break - please report this!";
	      @smart=($item->{"smart"});
	    }
	    for (@smart) { print "vars.$_ = \"smart\"\n" }
	  } elsif ($monitoring eq "mem") { # implies linux
	    print "  vars.os = \"Linux\"\n";
	    print "  vars.mem_warn = 40\n";
	  } elsif ($monitoring eq "linux") {
	    print "  vars.os = \"Linux\"\n";
	  } elsif ($monitoring eq "openwrt") {
	    print "  vars.os = \"OpenWRT\"\n";
	  }
	  if (exists($item->{"https"})) {
	    print "  vars.https = \"true\"\n";
	  }
	  print "}\n\n";
	} elsif (/[0-9a-fA-F]*:[0-9a-fA-F:]*:[0-9a-fA-F]*/) {
	  $#ip>0 or warn "monitoring hosts without ipv4 not supported yet";
	  next;
	} else { # CNAME - if https is set this is a virtual host
	  next unless exists($item->{"https"});

	  if (not searchname($data,".",$_)) {
	    warn "https host but ip value is no valid icinga host: $_ ".
	      "- ignoring";
	    next;
	  }

	  my($ndd)=$domain;
	  chop($ndd) if substr($ndd,-1) eq '.';
	  print "object Service \"cert-$name.$ndd\" {\n";
	  print "  import \"generic-service\"\n";
	  print "  host_name = \"$_\"\n";
	  print "  vars.vhost = \"$name.$ndd\"\n";
	  print "  check_command = \"vhttps\"\n";
	  print "}\n\n";
	}
      }
    }
    # ignored: eip, ettl, emx, smart
  }

  for (sort(keys(%$item))) {
    if (ref($item->{$_}) eq "HASH") { # name
      next if $item->{$_}->{"isdomain"};
      processitem($item->{$_},$_);
    }
  }

  for (sort(keys(%$item))) {
    if (ref($item->{$_}) eq "HASH") { # subdomain
      next unless $item->{$_}->{"isdomain"};
      processitem($item->{$_},$_);
    }
  }
}

# search in TOML-datastructure (recursively) for name. recursion-anchor
# should usually be "." at start.
# arguments: TOML-datastructure-hash recursion-anchor name 
sub searchname($$$) {
  my($item)=shift;
  my($name)=shift;
  my($search)=shift;
  ref($item) eq "HASH" or die "no hash?";

  # my($domain)=$domain;
  # this creates a new dynamic scope for this variable which will last
  # until the end of the enclosing block - which means we can set this to
  # the domain we are searching at the moment, persisting throuch
  # recursions, and it will be reset when we leave the function
  local($searchdomain)="$searchdomain";

  if (exists($item->{"name"})) {$name=$item->{"name"}}
  if (exists($item->{"isdomain"}) and $item->{"isdomain"}) {
    $searchdomain="$name.$searchdomain";
    if (exists($item->{"domain"})) { $searchdomain=$item->{"domain"} }
  } elsif ($search eq "$name.$searchdomain") { return 1; }

  for (sort(keys(%$item))) {
    if (ref($item->{$_}) eq "HASH") { # name
      if (searchname($item->{$_},$_,$search)) { return 1;}
    }
  }

  return 0;
}
