use utf8;
use warnings; no warnings "redefine";
use strict;

use Dbase::Globals qw(get_ipkunde get_kunde name_kunde get_vrf get_gruppen unterkunden);
use Dbase::Help qw(DoFn DoSelect qquote);
use Loader qw(add_kunde_ipaddr edit_ipaddr line_in list_ipaddrs log_view
	valid_ip add_ipaddr_vrf list_vrfs select_suche);
use Fehler qw(problem report_fehler report_status warnung);
use Dbase::IP;

my %suche = (
	f  => sub {
		my ($grs, $grc) = get_gruppen( ipflags => $_[0], 1 ) or return;
		"(flags & $grs = $grs AND flags & $grc = 0)";
	},
	hg => sub {
		my($str,$key) = @_;
		$_ = $str;
		if ( $key eq '?' ) {
			$_ = "%$_" unless /^%/;
			$_ .= '%' unless /%$/;
		}
		"ipkunde.id in (select ip_hostgroup.host from ip_hostgroup,hostgroup
			where ip_hostgroup.gruppe=hostgroup.id
			  and hostgroup.name like ${\ qquote($_) } )"
	},
	n  => 'name',
	ni  => 'infotext',
);

# Flags: 1: Return mit Eintrag
#        2: nur Selektion von Hostadressen erlaubt
#        4: '-' erlaubt
sub edit_ipaddrs($;$$) {
	my($id,$flag,$kn) = @_;

	$kn = "Kunde $id:" .name_kunde($id) if $kn eq "";

	aloop: while(1) {
		my $act = line_in "$kn IP >", $flag&1 ? 0 : 4;
		return undef unless defined $act && length $act;
		( $act, my @select ) = split ' ', $act;

		for (@select) {
			if ( $_ eq '/' ) {
				$_ = 'bits > 0';
			}
			elsif (/^#(.*)/) {
				my $ip = get_ipkunde( $1, 2 );
				if ($ip) {
					my $bits;
					( $ip, $bits ) =
					  DoFn("select ip6,bits from ipkunde where id=$ip")
					  and $ip = Dbase::IP->new_db( $ip, $bits );
				}
				else {
					$ip = Dbase::IP->new($1);
				}

                                if ($ip) {
					$_ = 'ip6 >= '
					  . qquote( $ip->db_ip6 )
					  . ' AND ip6 < '
					  . qquote( ( $ip + 1 )->db_ip6 )
					  . ' AND bits <= '
					  . $ip->db_bits;
				}
				else {
					problem("IP-Adressobjekt $_ nicht gefunden.");
					next aloop;
				}
			}
			else {
				defined( $_ = select_suche( $_, ipkunde => %suche ) )
				  or next aloop;
			}
		}

		if($act eq "?") {
			print <<'END';

l       aktive IPv4-Objekte (mit VRFs) anzeigen       L   auch beendete ...
l4      aktive IPv4-Objekte (ohne VRFs) anzeigen      L4
l6      aktive IPv6-Objekte anzeigen                  L6
ll      alle aktiven Objekte anzeigen                 LL
*l, *L, etc.: auch mit Unterkunden

Ein bestimmtes VRF kann mit vorangestelltem "vrf!..." ausgewählt werden.
(Name oder Nummer)
Zusätzlich können beliebig viele mit Whitespace getrennte Suchargumente
übergeben werden:

#NETZ  zeigt nur Adressen innerhalb dieses Netz(objekt)s
/      zeigt nur Netzbereiche

f:...  nur Adressen mit diesen Flags anzeigen
       ll f:monitoring,!no_mx  zeige alle aktiven Adressen an, bei denen das
                               monitoring- aber nicht das no_mx-Flag an ist
n:...  nur Adressen anzeigen, deren Name zu SQL-Wildcard "..." passt
i:...  nur Adressen anzeigen, deren Infotext zu SQL-Wildcard "..." passt
hg:... nur Adressen in Hostgroups anzeigen, deren Name zu SQL-Wildcard "..."
       passt

n?...  nur Adressen anzeigen, in deren Name "..." vorkommt
i?...  nur Adressen anzeigen, in deren Infotext "..." vorkommt
hg?... nur Adressen in Hostgroups anzeigen, in deren Name "..." vorkommt

a      hinzufügen           v   neues VRF anlegen    lv  VRFs auflisten

END
			print <<'END' if $flag & 4;
-        disassoziieren
END
			if($flag & 1) {
				print <<'END';
####     Subnetz auswählen
!####    Subnetz editieren
END
			} else {
				print <<'END';
####     Subnetz editieren
END
			}
			print <<'END';
IPNR     dito (auch Netze)
NAME     dito (Rechner- bzw. Subnetz-Name)
END
			next;
		}

		if($act eq "a") {
			my $kunde_id = $id;
			until ($kunde_id) {
				length( my $kunde = line_in 'Kunde      > ' ) or return;
				$kunde_id = get_kunde $kunde and last;
				print
				  qq(Kunde "$kunde" ist mit nicht bekannt; bitte versuch's nochmal:\n);
			}
			my $ret = add_kunde_ipaddr($id,$kn);
			return $ret if $flag & 1 and $ret > 0;
			next;
		}
		if($act eq "v") {
			my $ret = add_ipaddr_vrf($id,$kn);
			return $ret if $flag & 1 and $ret > 0;
			next;
		}
		if($act eq "lv") {
			list_vrfs($id);
			next;
		}
		if ( $act =~ / ^ (\*)? (?:( \w* )\!)? ( [lL] ) ( [46lL] )? \z /x ) {
			my $vrf;
			if(defined $2 and $2 ne "") {
				$vrf = get_vrf($2);
				problem "Das VRF '$2' kenne ich nicht", next
					unless defined $vrf;
			}
			my $flags;
			$flags |= 8 if defined $2 and $2 eq "";
			$flags |= 1 if $3 eq 'L';
			$flags |= ($4 eq '6') ? 12 : ($4 eq '4') ? 8 : 4
				if defined $4;
			list_ipaddrs( ($1 && $id) ? [ unterkunden($id) ] : $id, $kn, $flags, $vrf, @select);
			next aloop;
		}
		if($act eq "H") { log_view($kn,"ipkunde"); next; }
		return $act if $act eq "-" and $flag & 4;
		my $force = ($act =~ s/^\?//);
		my $eip = Dbase::IP->new($act);

		if($act =~ s/^I?(\d+)$/$1/) {
			my($ip,$bits) = DoFn("select ip6,bits from ipkunde where id=$act");
			$eip = Dbase::IP->new_db($ip,$bits);

			if($flag & 1 and not $force) {
				return unless valid_ip($act);
				return $act;
			}
			edit_ipaddr($act,$id,$kn);
			next;
		} elsif(defined $eip) { # gültige Adresse eingegeben

			my $ipa = get_ipkunde( $eip, $flag&2 );
			if(not defined $ipa) {
				print "IP-Adresse '$act' nicht gefunden.\n";
				next;
			}

			my($ip,$bits) = DoFn("SELECT ip6,bits FROM ipkunde WHERE id = $ipa");

			if($flag & 2) {
				if($bits) {
					print STDERR "Nur Hostadressen sind hier erlaubt!\n";
					next aloop;
				}
			}
			$ip = Dbase::IP->new_db($ip,$bits);

			if ($ip->db_bits != $eip->db_bits) {
				my $ip = $ip->str(4);
				if ( $flag & 1 ) {
					problem("Ein solches Objekt gibt es nicht. (Nächstgrößerer Adressbereich: $ip)");
					next aloop;
				}
				else {
					warnung("Es wurde nur der übergeordnete IP-Adressbereich '$ip' gefunden.");
				}
				#report_status();
				#my $answer = line_in( 'Aufrufen? ' );
				#next aloop if $answer !~ /^[jy]/i;
			}

			if($flag & 1 and not $force) {
				return unless valid_ip($ipa);
				return $ipa;
			}
			edit_ipaddr($ipa,$id,$kn);
			next;
		} else {
			my $ipa;
			my $aktiv = '( ende IS NULL OR ende >= UNIX_TIMESTAMP(NOW()) )';

                        # Erstmal schauen, ob's ein _aktives_ Objekt mit passendem FQDN gibt,
                        # nur falls nicht, interessieren uns ggf. beendete Objekte:
			my @suchen = (
				[ " AND $aktiv", 'mehrere aktive' ],
				[ '',            'mehrere beendete' ]
			);

                        # Falls wir uns in einem bestimmten Kunden (und nicht unter "alle Kunden")
                        # befinden, suche erst speziell nach passenden Objekten bei diesem Kunden
                        # und nur, wenn es da keines gibt, auch bei anderen:
			@suchen =
			  map +(
				[ " AND kunde = $id$_->[0]", "bei diesem Kunden $_->[1]" ], $_
			  ),
			  @suchen
			  if defined $id;

                        for (@suchen) {
				my($sql, $descr) = @$_;
				DoSelect {
					if ($ipa) {
						warnung "Es gibt $descr IP-Adress-Objekte dieses Namens (#$ipa vs. #$_[0]).";
					}
					else {
						$ipa = shift;
						warnung('Dieses IP-Adressobjekt ist bereits beendet.') if shift;
					}
				} "SELECT id, ende IS NOT NULL AND ende <= UNIX_TIMESTAMP(NOW()) FROM ipkunde WHERE name = ${\qquote $act} $sql ORDER BY id";
				last if defined $ipa;
			}
			if(defined $ipa) {
				return $ipa if $flag & 1 and !$force;
				edit_ipaddr($ipa,$id,$kn);
				next;
			}
		} ## FALL THRU

		print "Aktion '$act' kenne ich nicht. Liste mit '?'.\n";
		next; fehler: report_fehler(4);
	}
	undef;
}

1;
