// Copyright 2023 wanderer <a_mirre at utb dot cz>
// SPDX-License-Identifier: GPL-3.0-or-later

package cec2020

import (
	"bufio"
	"embed"
	"fmt"
	"io/fs"
	"log"
	"strconv"
	"strings"
)

//go:embed input_data/*
var inputData embed.FS

// LoadInputData loads matrices and shift/rotation/shuffle input data and
// returns them as maps.
func LoadInputData(nx int) (map[int][][]float64, map[int][][]float64) {
	matrices := make(map[int][][]float64)
	shiftData := make(map[int][][]float64)

	prefix := "input_data"

	// filenames indices.
	funcNums := []int{1, 2, 3, 7, 4, 16, 6, 22, 24, 25}

	for _, v := range funcNums {
		fnameMatrix := fmt.Sprintf("%s/M_%d_D%d.txt", prefix, v, nx)
		fnameShift := fmt.Sprintf("%s/shift_data_%d.txt", prefix, v)

		{
			matrix, err := inputData.Open(fnameMatrix)
			if err != nil {
				log.Printf("matrix: could not read %s, err: %q\n", fnameMatrix, err)
				continue
			}

			defer matrix.Close()

			m := parseMatrix(matrix, nx)

			matrices[v] = m
		}

		{
			shift, err := inputData.Open(fnameShift)
			if err != nil {
				log.Printf("shift: could not read %s, err: %q\n", fnameShift, err)
				continue
			}

			defer shift.Close()

			s := parseShiftData(shift, nx)

			shiftData[v] = s
		}
	}

	return matrices, shiftData
}

func parseMatrix(f fs.File, dim int) [][]float64 {
	if f == nil {
		log.Fatalln("matrix file is nil, exiting...")
	}

	var mrows []string

	fMatrix := make([][]float64, 0, dim)
	scanner := bufio.NewScanner(f)

	for scanner.Scan() {
		mrows = append(mrows, scanner.Text())
	}

	for _, r := range mrows {
		row := strings.Fields(r)
		flrow := make([]float64, 0, len(row))

		for _, val := range row {
			fl, err := strconv.ParseFloat(val, 64)
			if err != nil {
				log.Fatalf("parseMatrix: could not parse value to float64, val: %s, error: %q, bailing...", val, err)
			}

			flrow = append(flrow, fl)
		}

		fMatrix = append(fMatrix, flrow)
	}

	return fMatrix
}

func parseShiftData(f fs.File, dim int) [][]float64 {
	if f == nil {
		log.Fatalln("shift file is nil, exiting...")
	}

	shrows := make([]string, 0, dim)
	fSh := make([][]float64, 0, dim)
	scanner := bufio.NewScanner(f)

	for scanner.Scan() {
		shrows = append(shrows, scanner.Text())
	}

	for _, r := range shrows {
		row := strings.Fields(r)
		flrow := make([]float64, 0, len(row))

		for _, col := range row {
			fl, err := strconv.ParseFloat(col, 64)
			if err != nil {
				log.Fatalf("parseShiftData: could not parse value to float64, col: %s, error: %q, bailing...", col, err)
			}

			flrow = append(flrow, fl)
		}

		fSh = append(fSh, flrow)
	}

	return fSh
}
