package main

import (
	"fmt"
	"math"
	"sort"
	"strings"

	"../../"
)

func main() {
	part1 := aoc.ArgIsSet("-1")
	justSort := aoc.ArgIsSet("-sort")
	input := aoc.StdinToStringSlice()
	var blacklists []Blacklist
	for i := range input {
		pts := strings.Split(input[i], "-")
		st := aoc.Atoi(pts[0])
		end := aoc.Atoi(pts[1])
		blacklists = append(blacklists, *CreateBlacklist(st, end))
	}
	sort.Sort(ByStart(blacklists))

	// Just output the sorted blacklists
	if justSort {
		for i := range blacklists {
			fmt.Print(blacklists[i].start, "-", blacklists[i].end, "\n")
		}
		return
	}

	// Find the lowest non-blacklisted IP
	if part1 {
		fmt.Println(findLowest(blacklists))
		return
	}

	// Count how many IPs are allowed
	var numIps, blIdx, ip int
	highestIp := int(math.Pow(2, 32))
	for ip <= highestIp {
		if blIdx >= len(blacklists) {
			break
		}
		if ip >= blacklists[blIdx].start {
			if ip <= blacklists[blIdx].end {
				ip = blacklists[blIdx].end + 1
				continue
			}
			blIdx++
		} else {
			numIps++
			ip++
		}
	}

	fmt.Println(numIps)
}

func findLowest(blacklists []Blacklist) int {
	var lowestIp int
	for i := range blacklists {
		if blacklists[i].hasIp(lowestIp) {
			lowestIp = blacklists[i].end + 1
		}
	}
	return lowestIp
}

type Blacklist struct {
	start, end int
}

func CreateBlacklist(st, end int) *Blacklist {
	return &Blacklist{st, end}
}

func (b *Blacklist) hasIp(inp int) bool {
	return inp >= b.start && inp <= b.end
}

type ByStart []Blacklist

func (b ByStart) Len() int           { return len(b) }
func (b ByStart) Swap(i, j int)      { b[i], b[j] = b[j], b[i] }
func (b ByStart) Less(i, j int) bool { return b[i].start < b[j].start }
