package main

import (
	"flag"
	"io/ioutil"
	"log"
	"os"
	"regexp"
	"strings"
	"unicode"
)

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

type keyLetter struct {
	upperCase string
	position  int32
}

func parseArguments() (string, string) {
	var inputKey string
	var inputFile string
	flag.StringVar(&inputKey, "k", "", "Specify key word.")
	flag.StringVar(&inputFile, "f", "", "Specify file to encrypt.")
	flag.Parse()
	return inputKey, inputFile
}

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

func writeFile(relativePath string, message string) {
	file, err := os.Create(relativePath)
	if err != nil {
		log.Fatalln(err)
	}
	defer file.Close()
	file.WriteString(message)
}

func validateKeyWord(inputKey string) string {
	reg, err := regexp.Compile("[^a-zA-Z]+")
	if err != nil {
		log.Fatalln(err)
	}
	processedString := reg.ReplaceAllString(inputKey, "")
	return strings.ToUpper(processedString)
}

func initKeyWord(key string) []keyLetter {
	var keyWord []keyLetter
	for _, letter := range key {
		keyWord = append(keyWord, keyLetter{
			upperCase: string(letter),
			position:  letter - 'A',
		})
	}
	return keyWord
}

func encryptMessage(keyWord []keyLetter, message string) string {
	encrypted := ""
	index := 0
	for _, letter := range message {
		if !unicode.IsLetter(letter) {
			encrypted += string(letter)
		} else {
			keyWordIndex := index % len(keyWord)
			newLetter := letter + keyWord[keyWordIndex].position
			if (unicode.IsLower(letter) && newLetter > 'z') ||
				(unicode.IsUpper(letter) && newLetter > 'Z') {
				newLetter -= lettersInTheAlphabet
			}
			encrypted += string(newLetter)
			index += 1
		}
	}
	return encrypted
}

func main() {
	inputKey, inputFile := parseArguments()
	message := readFile(inputFile)
	keyWord := initKeyWord(validateKeyWord(inputKey))
	writeFile("output.txt", encryptMessage(keyWord, message))
}
