package main

type Args struct {
	Version         verArgs         `command:"version" alias:"v" description:"Show version information." validate:"omitempty"`
	SplitCIDR       SplitCIDRArgs   `command:"split-cidr" alias:"se" description:"Split a network into as many equal subnets of prefix size N as possible." validate:"omitempty"`
	SplitHost       SplitHostArgs   `command:"split-hosts" alias:"sh" description:"Split a network into N total number of hosts *per subnet* as cleanly/evenly as possible. (VERY easy to run out of memory for IPv6 prefixes; be sure to specify very small network!)" validate:"omitempty"`
	SplitSubnets    SplitSubnetArgs `command:"split-nets" alias:"sn" description:"Split a network into N number of subnets as cleanly as possible." validate:"omitempty"`
	VLSM            VLSMArgs        `command:"split-vlsm" alias:"sv" alias:"vlsm" description:"Use VLSM (Variable-Length Subnet Masks) to split a network into differently sized subnets." validate:"omitempty"`
	ExplicitNetwork XNetArgs        `command:"net" alias:"xn" alias:"net" description:"Print information about an explicit network address." validate:"omitempty"`
	NumNets         NNetArgs        `command:"num-nets" alias:"nn" alias:"nets" description:"Return the number of subnets of a given size that can fit into a given network size. This is MUCH, MUCH FASTER than splitting (if you do not need addressing)." validate:"omitempty"`
	Parse           ParseArgs       `command:"parse" alias:"p" alias:"read" alias:"convert" description:"Parse/convert output from a previous subnetter run." validate:"omitempty"`
	Table           TableArgs       `command:"table" alias:"t" alias:"tab" alias:"tbl" description:"Show prefix summaries (by default both IPv4 and IPv6)." validate:"omitempty"`
	Check           CheckArgs       `command:"reserved" alias:"r" description:"Check if a subnet is reserved per IANA/RFC." validate:"omitempty"`
}

type verArgs struct {
	DetailVersion bool `short:"V" long:"detail" description:"Print detailed version info and exit."`
}

type commonBase struct {
	cacheArgs
	SuppressRemaining bool   `short:"r" long:"no-remaining" description:"Don't show leftover/unallocated/remaining space."`
	Plain             bool   `short:"p" long:"plain" description:"Show plain output instead of unicode (only used if -f/--format=pretty)."`
	Separator         string `short:"S" long:"separator" default:"\n" description:"Separator between addresses; only used for -f/--format=pretty with no verbosity."`
	Fmt               string `short:"f" long:"format" choice:"json" choice:"pretty" choice:"yml" choice:"xml" default:"pretty" description:"Output format. 'pretty' is not intended to be parseable, either by subnetter or by external tooling."`
	Verbose           []bool `short:"v" long:"verbose" description:"Show verbose information if -f/--format=pretty. May be specified multiple times to increase verbosity (up to 3 levels)."`
	AllowReserved     bool   `short:"R" long:"allow-reserved" description:"If specified, do not warn about reserved IP addresses/networks."`
	reservedArgs
	AllowHostNet bool `short:"H" long:"allow-host" description:"If specified, do not warn about host bits. Host bits are always removed for subnetting (as otherwise there would be errors); this is only used only for output."`
}

type common struct {
	commonBase
	Network Net `positional-args:"yes" required:"true" description:"The network/parent prefix to operate on." validate:"required"`
}

type reservedArgs struct {
	NoRecursive    bool `short:"u" long:"no-recursive" description:"Don't show reservations that are children subnets of the subnet(s). Only if -f/--format=pretty, always false for other formats."`
	NoRevRecursive bool `short:"U" long:"no-rev-recursive" description:"Don't show reservations that are parents of the subnet(s). Only if -f/--format=pretty, always false for other formats."`
	NoPrivate      bool `short:"e" long:"no-private" description:"Consider private subnets of the subnet(s) to be reserved. If you are subnetting private address space, you probably want to leave this disabled. Only if -f/--format=pretty, always true otherwise."`
}

type splitArgs struct {
	common
}

type cacheArgs struct {
	CacheDir   string `short:"C" long:"cache-dir" env:"SBNTR_RSVCACHE_DIR" description:"Cached reservation data directory. The default is platform/OS-specific."`
	DoResCache bool   `short:"c" long:"cache-reservations" env:"SBNTR_RSVCACHE" description:"Enable caching/cache lookup for reservation data."`
}

type NNetArgs struct {
	Verbose   bool `short:"v" long:"verbose" description:"Be verbose (more ideal for logging)."`
	NoV6Check bool `short:"6" long:"no-v6" description:"If specified, do not indicate if the subnetting is IPv6 only (true) or not (false; dual-stack/IPv4 supported)."`
	Sizes     struct {
		SubnetSize  uint8 `required:"1" validate:"required,le=128,gtefield=NetworkSize"`
		NetworkSize uint8 `required:"1" validate:"required,le=128,ltefield=SubnetSize"`
	} `positional-args:"yes" required:"2" validate:"required"`
}

type ParseArgs struct {
	commonBase
	InFile string `short:"i" long:"input" default:"-" description:"Input file to parse. Default is '-' (for STDIN)." required:"true" validate:"required,filepath|eq=-"`
}

type SplitCIDRArgs struct {
	Prefix uint8 `short:"s" long:"size" required:"true" description:"Prefix length/network size in bits (as CIDR number)." validate:"required"`
	splitArgs
}

type SplitHostArgs struct {
	Strict bool `short:"t" long:"strict" description:"If specified, an error will occur if the number of hosts/assignable addresses in a subnet is not exactly -n/--num-hosts."`
	Hosts  uint `short:"n" long:"num-hosts" required:"true" description:"Number of hosts (usable addresses) per subnet." validate:"required"`
	splitArgs
}

type SplitSubnetArgs struct {
	Strict  bool `short:"t" long:"strict" description:"If specified, an error will occur if the number of possible equally-sized subnets is not exactly -n/--num-nets."`
	NumNets uint `short:"n" long:"num-nets" required:"true" description:"Number of networks." validate:"required"`
	splitArgs
}

type TableArgs struct {
	Notes    bool `short:"n" long:"notes" description:"Include notes about prefixes (as a separate table)."`
	Legacy   bool `short:"l" long:"legacy" description:"Include legacy/obsolete/deprecated information (as separate table(s))."`
	Plain    bool `short:"p" long:"plain" description:"Show plain table output instead of unicode."`
	NoV4Mask bool `short:"M" long:"no-mask" description:"Do not include netmasks for IPv4."`
	NoIpv6   bool `short:"4" long:"ipv4" description:"Only show IPv4 table(s)."`
	NoIpv4   bool `short:"6" long:"ipv6" description:"Only show IPv6 table(s)."`
}

type CheckArgs struct {
	cacheArgs
	reservedArgs
	Plain   bool   `short:"p" long:"plain" description:"Show plain output instead of unicode (only used if -f/--format=pretty)."`
	Fmt     string `short:"f" long:"format" choice:"json" choice:"pretty" choice:"yml" choice:"xml" default:"pretty" description:"Output format. 'pretty' is not intended to be parseable, either by subnetter or by external tooling."`
	Network Net    `positional-args:"yes" required:"true" description:"The network/parent prefix to operate on." validate:"required"`
}

type XNetArgs struct {
	common
}

type VLSMArgs struct {
	Asc      bool `short:"A" long:"ascending" description:"If specified, place smaller networks (larger prefixes) at the beginning. You almost assuredly do not want to do this."`
	Explicit bool `short:"O" long:"explicit-order" description:"If specified, ignore -A/--ascending and do no reordering of prefix sizes whatsoever, instead using the order given. This is EXTREMELY suboptimal and can lead to drastic addressing waste."`
	// Custom type for now; see https://github.com/jessevdk/go-flags/issues/245
	// Sizes    []uint8 `short:"s" long:"size" required:"true" description:"Prefix lengths. May be specified multiple times." validate:"required"`
	Sizes []vlsmSize `short:"s" long:"size" required:"true" description:"Prefix lengths. May be specified multiple times or as a comma-delimited list." validate:"required"`
	splitArgs
}

type Net struct {
	Network string `positional-arg-name:"<network>/<prefix>" description:"Network address with prefix. Can be IPv4 or IPv6." validate:"required,cidr"`
}