package main

import (
	"bytes"
	"fmt"
	"os"

	helpers "git.bullercodeworks.com/brian/adventofcode/helpers"
)

func main() {
	args := make([]string, len(os.Args)-1)
	copy(args, os.Args[1:])
	progFileName := "input"
	if len(args) == 0 {
		progFileName, args = "input", []string{"25", "6"}
	} else {
		if len(args) == 3 {
			progFileName, args = args[0], args[1:]
		}
		if len(args) != 2 {
			panic("Image Dimensions Required")
		}
	}
	w, h := helpers.Atoi(args[0]), helpers.Atoi(args[1])
	inp := bytes.TrimSpace(helpers.FileToBytes(progFileName))
	i := NewImage(inp, w, h)
	//part1(i)
	part2(i)
}

func part1(i *Image) {
	lowestZero, lowestZeroLayer := -1, -1
	for l := range i.Layers {
		countZeroes := i.Layers[l].CountByte('0')
		if lowestZeroLayer == -1 || lowestZero > countZeroes {
			lowestZero, lowestZeroLayer = countZeroes, l
		}
	}
	layer := i.Layers[lowestZeroLayer]
	fmt.Println(layer.CountByte('1') * layer.CountByte('2'))
}

func part2(i *Image) {
	wrk := i.Flatten()
	fmt.Println(wrk)
}

type Image struct {
	w, h   int
	Layers []Layer
}

func NewImage(bts []byte, w, h int) *Image {
	ret := Image{w: w, h: h}
	for len(bts) > 0 {
		var lyr *Layer
		lyr, bts = NewLayer(bts, w, h)
		ret.Layers = append(ret.Layers, *lyr)
	}
	return &ret
}

func (i Image) String() string {
	var ret string
	for l := range i.Layers {
		ret = ret + fmt.Sprintf("Layer %d\n", l+1)
		ret = ret + i.Layers[l].String() + "\n"
		ret = ret + "\n"
	}
	return ret
}

func (i Image) Flatten() *Image {
	ret := make([]byte, i.w*i.h)
	for l := range i.Layers {
		for v := range i.Layers[l].bytes {
			if ret[v] == '0' || ret[v] == '1' {
				continue
			}
			ret[v] = i.Layers[l].bytes[v]
		}
	}
	return NewImage(ret, i.w, i.h)
}

type Layer struct {
	w, h  int
	bytes []byte
}

func NewLayer(bts []byte, w, h int) (*Layer, []byte) {
	ret := Layer{w: w, h: h, bytes: bts[:w*h]}
	if len(bts) > w*h {
		return &ret, bts[w*h:]
	}
	return &ret, nil
}

func (l Layer) CountByte(bt byte) int {
	return bytes.Count(l.bytes, []byte{bt})
}

func (l Layer) GetPos(x, y int) byte {
	pos := (y * l.w) + x
	return l.bytes[pos]
}

func (l Layer) String() string {
	var ret string
	for i := range l.bytes {
		if i > 0 && i%l.w == 0 {
			ret = ret + "\n"
		}
		ret = ret + fmt.Sprintf("%d", l.bytes[i]-48)
	}
	return ret
}