#!/usr/bin/perl

use warnings;
use strict;

use lib "/opt/vyatta/share/perl5";
use Try::Tiny;
use Getopt::Long;
use Vyatta::Configd;
use Readonly;
use File::Basename;

Readonly my $SCRIPT_NAME => basename($0);

my $client = Vyatta::Configd::Client->new();

sub list_interfaces {

    sub process_tree {
        my ($tree) = @_;
        return
          map { $_->{"name"} }
          @{ $tree->{"dynamic"}->{"status"}->{"interfaces"} };
    }

    my $tree = try { $client->tree_get_full_hash("service dns dynamic") };
    my @interfaces = process_tree($tree)
      if defined $tree;

    my $ris = try { $client->tree_get_full_hash("routing routing-instance") };
    push @interfaces,
      map { process_tree( $_->{"service"}->{"dns"} ) }
      @{ $ris->{"routing-instance"} }
      if defined $ris;
    printf "%s\n", join( " ", @interfaces );
}

sub list_services {
    my @services = (
        "dnspark",   "dslreports",  "dyndns", "easydns",
        "namecheap", "sitelutions", "zoneedit"
    );
    printf "%s\n", join( " ", @services );
}

sub update_interface {
    my $usage = sub {
        printf( "Usage for %s --action=update-interface\n", $SCRIPT_NAME );
        printf( "    %s --action=update-interface --dev=<ifname>\n",
            $SCRIPT_NAME );
        exit(1);
    };
    my ($dev);
    GetOptions( "dev=s" => \$dev, )
      or $usage->();
    $usage->() unless defined $dev;

    try {
        $client->call_rpc_hash(
            "vyatta-service-dns-v1",
            "update-dynamic-dns-interface",
            { "interface" => $dev }
        );
    }
    catch {
        my $msg = $_;
        $msg =~ s/at.*$//;
        die $msg;
    }
}

sub show_status {
    my $usage = sub {
        printf( "Usage for %s --action=show\n",         $SCRIPT_NAME );
        printf( "    %s --action=show [--vrf=<vrf>]\n", $SCRIPT_NAME );
        exit(1);
    };
    my ($vrf);
    GetOptions( "vrf=s" => \$vrf, )
      or $usage->();

    $vrf = "default"
      unless defined $vrf;

    my $path = "service dns dynamic";
    $path = "routing routing-instance $vrf service dns dynamic"
      unless $vrf eq "default";

    my $tree = try { $client->tree_get_full_hash($path); };

    die "No dynamic DNS instances are running\n"
      unless defined $tree;

    for my $intf ( @{ $tree->{"dynamic"}->{"status"}->{"interfaces"} } ) {
        for my $host ( @{ $intf->{"hosts"} } ) {
            printf "interface    : %s\n", $intf->{"name"};
            printf "ip address   : %s\n", $host->{"address"}
              if defined $host->{"address"};
            printf "host-name    : %s\n", $host->{"hostname"};
            printf "last update  : %s\n", $host->{"last-update"}
              if defined $host->{"last-update"};
            printf "update status: %s\n", $host->{"status"};
            print "\n";
        }
    }
}

sub call_action_by_name {
    my ( $actions, $script_name, $opt_name, $usage ) = @_;

    my $usagefn = sub {
        printf( "Usage for %s %s:\n", $script_name, $usage );
        printf( "    %s %s --%s=[%s]\n",
            $script_name, $usage, $opt_name, join( "|", keys( %{$actions} ) ) );
        exit(1);
    };

    my ($name);
    GetOptions( "$opt_name=s" => \$name, ) or $usagefn->();
    $usagefn->() unless ( defined($name) );

    my $action = $actions->{$name};
    $usagefn->() unless ( defined($action) );

    return $action->();
}

my %actions = (
    "list-interfaces"  => \&list_interfaces,
    "list-services"    => \&list_services,
    "update-interface" => \&update_interface,
    "show"             => \&show_status,
);
call_action_by_name( \%actions, $SCRIPT_NAME, "action", "" );
