package main

import (
	"fmt"
	"github.com/dariubs/percent"
	"gonum.org/v1/plot"
	"gonum.org/v1/plot/plotter"
	"gonum.org/v1/plot/plotutil"
	"gonum.org/v1/plot/vg"
	"io/ioutil"
	"log"
	"sort"
	"strings"
)

type letter struct {
	upperCase string
	lowerCase string
	count     int
	frequency float64
}

type letterList []letter

func (l letterList) Len() int {
	return len(l)
}

func (l letterList) Less(i, j int) bool {
	return l[i].frequency > l[j].frequency
}

func (l letterList) Swap(i, j int) {
	l[i], l[j] = l[j], l[i]
}

const lettersInTheAlphabet = 'Z' - 'A' + 1

var letters = make([]letter, lettersInTheAlphabet)

func initLetterStruct() {
	for i := 0; i < lettersInTheAlphabet; i++ {
		letters[i].upperCase = string(rune('A' + i))
		letters[i].lowerCase = string(rune('A' + i + 32))
	}
}

func readFile(relativePath string) string {
	content, err := ioutil.ReadFile(relativePath)
	if err != nil {
		log.Fatalln(err)
	}
	return string(content)
}

func countLetters(inputText string) int {
	totalCount := 0
	for i := 0; i < lettersInTheAlphabet; i++ {
		letters[i].count +=
			strings.Count(inputText, letters[i].lowerCase) +
				strings.Count(inputText, letters[i].upperCase)
		totalCount += letters[i].count
	}
	return totalCount
}

func calculateFrequency(totalCount int) {
	for i := 0; i < lettersInTheAlphabet; i++ {
		letters[i].frequency = percent.PercentOf(letters[i].count, totalCount)
	}
}

func printResult() {
	for i := 0; i < lettersInTheAlphabet; i++ {
		l := letters[i]
		fmt.Printf(
			"The letter %s (%s) occurs %d times in the text and the frequencyArray in percent is %0.2f\n",
			l.upperCase, l.lowerCase, l.count, l.frequency,
		)
	}
}

func plotResult() {
	var count plotter.Values
	for i := 0; i < lettersInTheAlphabet; i++ {
		count = append(count, float64(letters[i].count))
	}
	p := plot.New()
	p.Title.Text = "Letter count"
	p.X.Label.Text = "letter"
	p.Y.Label.Text = "count"
	countBars, err := plotter.NewBarChart(count, vg.Points(lettersInTheAlphabet/2))
	countBars.Color = plotutil.Color(2)
	if err != nil {
		log.Fatalln(err)
	}
	p.Add(countBars)
	var xAxisNaming []string
	for index := range letters {
		xAxisNaming = append(xAxisNaming, letters[index].upperCase)
	}
	p.NominalX(xAxisNaming...)
	if err := p.Save(25*vg.Centimeter, 15*vg.Centimeter, "barChart.png"); err != nil {
		log.Fatalln(err)
	}
}

func main() {
	initLetterStruct()
	//totalCount := countLetters(readFile("plaintext.txt"))
	totalCount := countLetters(readFile("../encrypt/output.txt"))
	calculateFrequency(totalCount)
	plotResult()
	sort.Sort(letterList(letters))
	printResult()
}
