// package mod_stat_day -- статистика модуля за первые 24 часа
package mod_stat_day

import (
	"bytes"
	"fmt"
	"math"

	"sync"
	"time"

	svg "github.com/ajstarks/svgo"
)

// ModStatDay -- статистика модуля за первые 24 часа
type ModStatDay struct {
	sync.RWMutex
	lst    []int // Список значений за первые 24 часа
	bufSvg *bytes.Buffer
}

// NewModStatDay -- возвращает новую статистику модуля за первые 24 часа
func NewModStatDay() *ModStatDay {
	sf := &ModStatDay{
		lst:    []int{},
		bufSvg: bytes.NewBufferString(""),
	}
	return sf
}

// Sum -- возвращает сумму элементов по требованию
func (sf *ModStatDay) Sum() int {
	sf.RLock()
	defer sf.RUnlock()
	sum := 0
	for _, val := range sf.lst {
		sum += val
	}
	return sum
}

// Add -- добавляет значение в часовой срез
func (sf *ModStatDay) Add(val int) {
	sf.Lock()
	defer sf.Unlock()

	for len(sf.lst) < 72 {
		sf.lst = append(sf.lst, math.MinInt64)
	}

	sf.lst = append(sf.lst, val)
	if len(sf.lst) > 72 {
		sf.lst = sf.lst[1:]
	}
}

// Svg -- возвращает сгенерированный SVG по часовому срезу
func (sf *ModStatDay) Svg() string {
	sf.RLock()
	defer sf.RUnlock()
	sf.bufSvg.Reset()
	cnv := svg.New(sf.bufSvg)
	cnv.Start(480, 320)
	cnv.Title("Last 24 hours")
	cnv.Desc("Graphic of last 24 hours")
	cnv.Text(20, 20, "Last 24 hours", "")
	var (
		valMin = math.MaxInt64
		valMax = math.MinInt64
	)
	fnGetMinMax := func() { // Вычисляет максимальное и минимальное значение в графике
		for _, val := range sf.lst {
			if val < valMin {
				valMin = val
			}
			if val > valMax {
				valMax = val
			}
		}
	}
	fnGetMinMax()
	for i, val := range sf.lst {
		x1 := int(float32(i)*5) + 42
		y1 := int(240 * float32(valMax) / float32(val))
		cnv.Rect(x1, 280-y1, 4, y1, "fill:true;stroke:red;")
	}
	fnDrawNet := func() {
		// Метки величины
		if valMin == math.MaxInt64 || valMin == math.MinInt64 {
			valMin = 0
		}
		cnv.Text(25, 285, fmt.Sprint(valMin), "")
		if valMax == math.MinInt64 || valMax == math.MaxInt64 {
			valMax = 1
		}
		cnv.Text(25, 45, fmt.Sprint(valMax), "")
		// Метки времени
		timeNow := time.Now().Local()
		timeSub24 := timeNow.Add(-24 * time.Hour).Format("15")
		cnv.Text(40, 295, timeSub24, "")

		timeSub45 := timeNow.Add(-18 * time.Hour).Local().Format("15")
		cnv.Text(128, 295, timeSub45, "")

		timeSub30 := timeNow.Add(-12 * time.Hour).Local().Format("15")
		cnv.Text(216, 295, timeSub30, "")

		timeSub15 := timeNow.Add(-6 * time.Hour).Local().Format("15")
		cnv.Text(304, 295, timeSub15, "")

		timeSub0 := time.Now().Local().Format("15")
		cnv.Text(392, 295, timeSub0, "")

		cnv.Line(40, 280, 40, 38, "fill:true;stroke:black;stroke-width:4")
		cnv.Line(40, 280, 442, 280, "fill:true;stroke:black;stroke-width:4")
		count := 0
		for x := 40; x < 460; x += 20 {
			cnv.Line(x, 40, x, 280, "fill:true;stroke:gray")
			if count%5 == 0 {
				cnv.Text(x+3, 278, fmt.Sprint(x), "fill:white;stroke:gray")
			}
			count++
		}
		count = 0
		for y := 40; y < 300; y += 20 {
			cnv.Line(40, y, 440, y, "fill:true;stroke:gray")
			if count%5 == 0 {
				cnv.Text(43, y+12, fmt.Sprint(y), "fill:white;stroke:gray")
			}
			count++
		}
	}
	fnDrawNet()
	cnv.End()
	strOut := sf.bufSvg.String()
	return strOut
}
