package main

import (
	"bufio"
	"encoding/hex"
	"fmt"
	"log"
	"os"
	"strings"
)

func main() {
	file, err := os.Open("save.txt")
	if err != nil {
		log.Fatalf("Failed to open file: %s", err)
	}
	defer file.Close()

	scanner := bufio.NewScanner(file)
	for scanner.Scan() {
		line := scanner.Text()
		decodeBeacon(line)
	}
}

func decodeBeacon(beacon string) {
	beacon = strings.TrimSpace(beacon)
	if beacon == "" {
		return
	}

	// convert to bytes for faster operations
	b, err := hex.DecodeString(beacon)
	if err != nil {
		fmt.Println("invalid line: ", beacon)
		return
	}

	// remove flag bytes - they hold no structural information
	if len(b) > 1 && b[1] == 0x01 {
		l := int(b[0])
		if 1+l <= len(b) {
			b = b[1+l:]
		}
	}

	adBlockIndeces := parseADFast(b)
	for _, r := range adBlockIndeces {
		ad := b[r[0]:r[1]]
		if len(ad) >= 4 &&
			ad[1] == 0x16 &&
			ad[2] == 0xAA &&
			ad[3] == 0xFE {
			// fmt.Println("Eddystone:", hex.EncodeToString(b))
			return
		}
		if len(ad) >= 7 &&
			ad[1] == 0xFF &&
			ad[2] == 0x4C && ad[3] == 0x00 &&
			ad[4] == 0x02 && ad[5] == 0x15 {
			// fmt.Println("iBeacon:", hex.EncodeToString(b))
			return
		}

	}

	fmt.Println(hex.EncodeToString(b))
}

func parseADFast(b []byte) [][2]int {
	var res [][2]int
	i := 0

	for i < len(b) {
		l := int(b[i])
		if l == 0 || i+1+l > len(b) {
			break
		}

		res = append(res, [2]int{i, i + 1 + l})

		i += 1 + l
	}

	return res
}
