// Week 4 – Solutions of the practice exercises
// Run: go run ./w04/exercises
package main

import (
	"fmt"
	"strconv"
	"strings"
	"unicode"
)

// E1. Palindrome (Unicode-safe: we work with runes)
func isPalindrome(s string) bool {
	var r []rune
	for _, c := range s {
		if unicode.IsLetter(c) || unicode.IsDigit(c) {
			r = append(r, unicode.ToLower(c))
		}
	}
	for i, j := 0, len(r)-1; i < j; i, j = i+1, j-1 {
		if r[i] != r[j] {
			return false
		}
	}
	return true
}

// E2. Number of words
func wordCount(s string) int {
	return len(strings.Fields(s))
}

// E3. Letter frequency with a 26-element array
func letterFrequency(s string) [26]int {
	var freq [26]int
	for _, c := range strings.ToLower(s) {
		if c >= 'a' && c <= 'z' {
			freq[c-'a']++
		}
	}
	return freq
}

// E4. Caesar cipher
func caesar(s string, k int) string {
	var sb strings.Builder
	for _, c := range s {
		switch {
		case c >= 'a' && c <= 'z':
			sb.WriteRune('a' + (c-'a'+rune(k)+26)%26)
		case c >= 'A' && c <= 'Z':
			sb.WriteRune('A' + (c-'A'+rune(k)+26)%26)
		default:
			sb.WriteRune(c)
		}
	}
	return sb.String()
}

// E5. Anagram: [26]int arrays can be compared with ==
func isAnagram(a, b string) bool {
	return letterFrequency(a) == letterFrequency(b)
}

// E6. Run-length compression
func compress(s string) string {
	var sb strings.Builder
	r := []rune(s)
	for i := 0; i < len(r); {
		j := i
		for j < len(r) && r[j] == r[i] {
			j++
		}
		sb.WriteRune(r[i])
		sb.WriteString(strconv.Itoa(j - i))
		i = j
	}
	return sb.String()
}

// E7. Reversing the order of the words
func reverseWords(s string) string {
	w := strings.Fields(s)
	for i, j := 0, len(w)-1; i < j; i, j = i+1, j-1 {
		w[i], w[j] = w[j], w[i]
	}
	return strings.Join(w, " ")
}

func main() {
	fmt.Println(`E1. isPalindrome("A man, a plan, a canal: Panama") =`, isPalindrome("A man, a plan, a canal: Panama"))
	fmt.Println(`    isPalindrome("上海自来水来自海上") =`, isPalindrome("上海自来水来自海上"))
	fmt.Println(`E2. wordCount("  data   structures are fun ") =`, wordCount("  data   structures are fun "))
	f := letterFrequency("Hello World")
	fmt.Print("E3. Hello World: ")
	for i, v := range f {
		if v > 0 {
			fmt.Printf("%c=%d ", 'a'+i, v)
		}
	}
	fmt.Println()
	enc := caesar("Hello, Wuhan!", 3)
	fmt.Println("E4. caesar(3) =", enc, ", decoded:", caesar(enc, -3))
	fmt.Println(`E5. isAnagram("listen", "silent") =`, isAnagram("listen", "silent"))
	fmt.Println(`E6. compress("aaabbcdddd") =`, compress("aaabbcdddd"))
	fmt.Println(`E7. reverseWords("I love data structures") =`, reverseWords("I love data structures"))
}
