package main

import (
	"image/color"
	"math/rand"
	"time"

	"github.com/faiface/pixel"
	"github.com/faiface/pixel/imdraw"
	"github.com/faiface/pixel/pixelgl"
)

const w, h = float64(1024), float64(512)

var speed = float64(200)

var stars [1024]*star

func init() {
	rand.Seed(4)

	for i := 0; i < len(stars); i++ {
		stars[i] = newStar()
	}
}

type star struct {
	pixel.Vec
	Z float64
	P float64
	C color.RGBA
}

func newStar() *star {
	return &star{
		pixel.V(random(-w, w), random(-h, h)),
		random(0, w), 0, Colors[rand.Intn(len(Colors))],
	}
}

func (s *star) update(d float64) {
	s.P = s.Z
	s.Z -= d * speed

	if s.Z < 0 {
		s.X = random(-w, w)
		s.Y = random(-h, h)
		s.Z = w
		s.P = s.Z
	}
}

func (s *star) draw(imd *imdraw.IMDraw) {
	p := pixel.V(
		scale(s.X/s.Z, 0, 1, 0, w),
		scale(s.Y/s.Z, 0, 1, 0, h),
	)

	o := pixel.V(
		scale(s.X/s.P, 0, 1, 0, w),
		scale(s.Y/s.P, 0, 1, 0, h),
	)

	r := scale(s.Z, 0, w, 11, 0)

	imd.Color = s.C

	if p.Sub(o).Len() > 6 {
		imd.Push(p, o)
		imd.Line(r)
	}

	imd.Push(p)
	imd.Circle(r, 0)
}

func run() {
	win, err := pixelgl.NewWindow(pixelgl.WindowConfig{
		Bounds:      pixel.R(0, 0, w, h),
		VSync:       true,
		Undecorated: true,
	})
	if err != nil {
		panic(err)
	}

	imd := imdraw.New(nil)

	imd.Precision = 7

	imd.SetMatrix(pixel.IM.Moved(win.Bounds().Center()))

	last := time.Now()

	for !win.Closed() {
		win.SetClosed(win.JustPressed(pixelgl.KeyEscape) || win.JustPressed(pixelgl.KeyQ))

		if win.Pressed(pixelgl.KeyUp) {
			speed += 10
		}

		if win.Pressed(pixelgl.KeyDown) {
			if speed > 10 {
				speed -= 10
			}
		}

		if win.Pressed(pixelgl.KeySpace) {
			speed = 100
		}

		d := time.Since(last).Seconds()

		last = time.Now()

		imd.Clear()

		for _, s := range stars {
			s.update(d)
			s.draw(imd)
		}

		win.Clear(color.Black)
		imd.Draw(win)
		win.Update()
	}
}

func main() {
	pixelgl.Run(run)
}

func random(min, max float64) float64 {
	return rand.Float64()*(max-min) + min
}

func scale(unscaledNum, min, max, minAllowed, maxAllowed float64) float64 {
	return (maxAllowed-minAllowed)*(unscaledNum-min)/(max-min) + minAllowed
}

// Colors based on stellar types listed at
// http://www.vendian.org/mncharity/dir3/starcolor/
var Colors = []color.RGBA{
	color.RGBA{157, 180, 255, 255},
	color.RGBA{162, 185, 255, 255},
	color.RGBA{167, 188, 255, 255},
	color.RGBA{170, 191, 255, 255},
	color.RGBA{175, 195, 255, 255},
	color.RGBA{186, 204, 255, 255},
	color.RGBA{192, 209, 255, 255},
	color.RGBA{202, 216, 255, 255},
	color.RGBA{228, 232, 255, 255},
	color.RGBA{237, 238, 255, 255},
	color.RGBA{251, 248, 255, 255},
	color.RGBA{255, 249, 249, 255},
	color.RGBA{255, 245, 236, 255},
	color.RGBA{255, 244, 232, 255},
	color.RGBA{255, 241, 223, 255},
	color.RGBA{255, 235, 209, 255},
	color.RGBA{255, 215, 174, 255},
	color.RGBA{255, 198, 144, 255},
	color.RGBA{255, 190, 127, 255},
	color.RGBA{255, 187, 123, 255},
	color.RGBA{255, 187, 123, 255},
}