package main

import (
	"fmt"
	"time"
)

// barrier represents a multi-position light barrier attached to a motor.
type barrier struct {
	// npos is the number of the positions of the light barrier.
	npos uint
	// cur is the current position of the motor.
	cur float64
}

// pins returns an npos-length array representing the interruption state of the
// barrier given cur. An interrupted light barrier is represented by a true
// value, an uninterrupted one with a false value.
//
// Every light barrier position is half a unit away from eachother, with the
// first light barrier at unit 1.
func (b *barrier) pins() []bool {
	res := make([]bool, b.npos)
	for i := uint(0); i < b.npos; i++ {
		pos := float64(i) * float64(1.0)
		pos += 1.0
		if b.cur*2.0 >= pos {
			res[i] = true
		}
	}
	return res
}

// status returns a human-readable status of the barrier like '||..' for a
// 4-position light barrier with the first two barrier interrupted.
func (b *barrier) status() string {
	res := ""
	for _, v := range b.pins() {
		if v {
			res += "|"
		} else {
			res += "."
		}
	}
	return res
}

// motor represents an electrical motor which drives a linear actuator at 1 unit per second.
type motor struct {
	// en is true if the motor is enabled.
	en bool
	// dir is used to select the direction of the motor. If true, the motor
	// actuator moves towards positive values.
	dir bool
	// pos is the current position of the motor actuator.
	pos float64

	// barrier attached to this motor, will be automatically updated when the
	// motor simulation runs.
	barrier *barrier
}

// status returns a human-readable staus of the motor like '<-ID  ' indicating
// whether the motor is moving, and if so, in which direction.
func (s *motor) status(id string) string {
	res := ""
	if s.en {
		if s.dir {
			res += fmt.Sprintf("  %s->", id)
		} else {
			res += fmt.Sprintf("<-%s  ", id)
		}
	} else {
		res += fmt.Sprintf("  %s  ", id)
	}
	return res
}

// sim runs a simulation step of the motor given a delta time.
func (s *motor) sim(dt time.Duration) {
	if !s.en {
		return
	}
	d := dt.Seconds()
	if s.dir {
		s.pos += d
	} else {
		s.pos -= d
	}
	s.barrier.cur = s.pos
}

type indicators struct {
	indEvac     bool
	indHTReadyN bool
	indPumpDown bool
}

func (i indicators) String() string {
	res := ""
	if i.indEvac {
		res += "EVAC "
	} else {
		res += "---- "
	}
	if !i.indHTReadyN {
		res += "HT READY "
	} else {
		res += "-------- "
	}
	if i.indPumpDown {
		res += "PUMP DOWN "
	} else {
		res += "VENT      "
	}

	return res
}
