# This code requires jquery.
# There should be a ciphertext input element and restable table element for results.
# please have the following elements already on the page:
# 	.results, .ciphertext, .goButton
window.englishFreqs = {'E': 12.49,
'T': 9.28,
'A': 8.04,
'O': 7.64,
'I': 7.57,
'N': 7.23,
'S': 6.51,
'R': 6.28,
'H': 5.05,
'L': 4.07,
'D': 3.82,
'C': 3.34,
'U': 2.73,
'M': 2.51,
'F': 2.40,
'P': 2.14,
'G': 1.87,
'W': 1.68,
'Y': 1.66,
'B': 1.48,
'V': 1.05,
'K': 0.54,
'X': 0.23,
'J': 0.16,
'Q': 0.12,
'Z': 0.09};

$->
	# inp and res are jquery elements.
	# res is a table of results.
	class DataEntry
		constructor: (@inp, @res) ->

		clear: ->
			@inp.clear

		getInp: ->
			return @inp

		# in the end we're going to be adding some html to the page under the @res parent.
		addRes: (elem) ->
			@res.appendChild(elem)


	class SubstitutionCipher
		constructor: (@data) ->
			@data = @data.toUpperCase()
			@curFreq = {} # Stores previously calculated letter freqs.

		# returns a character-number mapping.
		letterFreq: ->

			# frequency shouldn't include characters we don't care about, ideally.
			numCharacters = @data.replace(/\s+/g, '') # spaces
			numCharacters = numCharacters.replace(/\.+/g, '') # periods
			numCharacters = numCharacters.replace(/,/g, '') # commas
			numCharacters = numCharacters.length()

			occurrences = {};

			for charidx in @data
				actualChar = @data[charidx]
				if actualChar in @occurrences
					@occurrences[actualChar]++
				else 
					@occurrences[actualChar] = 1

			# calculate the actual frequency now
			for k,v of occurrences
				@curFreq[k] = (v/numCharacters)

			return @curFreq

		# we need to have curFreq populated before this.
		guessSubs: ->
			# normal english probabilities in @englishFreqs 
			someSubs = {};

			# for every idx in our data
			for charidx in @data
				char = @data[charidx]

				# if we already guessed a sub for this char, skip it
				#if char in someSubs
				#	continue

				# compare the character to the normal english frequency
				for engChar, engFeq of window.englishFreqs

					# how far off is this freq from the eng freq?
					diff = Math.abs(@curFreq[char] - engFreq)
					console.log "~diff~ #{char} vs #{engChar}: #{diff}"

					# if we've already guessed that a character in our cipher represents
					# this english letter, we should verify that the difference for that
					# re-sub is less than this companion.
					if (engChar in someSubs) and (someSubs[engChar].diff > diff)
						# this replacement is closer to normal english letter frequency..
						someSubs[engChar] = {cipherchar: char, diff: diff}
					# we hadn't guessed a substitution for this char already, let's 
					else if diff <= 0.01 
						someSubs[engChar] = {cipherchar: char, diff: diff}

			# attempt the substitutions, check dictionary word count


			# if dictionary word count is low, ??? ???? ????

			return someSubs					

	# produces pretty html for given letter freq
	generateFreqGraph: (freqs) ->
		tableElem = $("<table class='charfreqs'><thead><th>Letter</th><th>Frequency</th></thead><tbody></tbody></table>")

		body = tableElem.find("tbody")[0]

		for letter,val of freqs
			newRow = $("<tr><td>#{letter}</td><td class='progbar' data-val=\"#{val}\">#{val}</td></tr>")
			body.appendChild(newRow);

		return tableElem

	# main logic ##################

	curEntry = new DataEntry($('.ciphertext'), $('.results'))
	curEntry.clear()

	# handle running upon go click
	$('.goButton').on 'click', (e) ->
		goCipher = new SbustitutionCipher(curEntry.getInp())
		console.log goCipher.letterFreq	


		console.log 
		ourFreqGraph = generateFreqGraph(goCipher.letterFreq())

		curEntry.addRes(ourFreqGraph);


	# determining key length in vignere:
	# kasiski test, index of coincidence test.
		# words repeat, if you see a repeating sequence >=3 chars... calculate the distance between repetitions
		# run the gcd on each of these gcd(gcd(dist1,dist2),dist3) and so on
		# index of coincidence: normal english is 0.0676
			# memorize the formula for the exam and know how to apply it

	# solving
		# guess keyword length, take ever X indices to guess that they're shifted the same amount
		# if the guess was correct, each guess will have a high index of coincidence. if not, best of bins will have IoC near .04