"""Source-grounded historical known answers, no K4 experiments.

Cipher transcription: https://www.elonka.com/kryptos/transcript.html
Plaintext and K2 key: Gillogly's first-person 1999 message, mirrored at
https://www.elonka.com/kryptos/mirrors/cypherpunks/1999/0930.html
K3 reproducible rotation recipe: https://kryptos.jsan.ch/k3/ (24,90;8,90),
corroborated by https://rumkin.com/tools/cipher/rotate/ (second width 8).
These document a working published recipe, not proof of Sanborn's exact
historical procedure. Gillogly calls K3 three columnar transpositions.
Dunin's independently published expected text:
https://elonka.com/kryptos/part3.html (use canonical transcript, because the
initial display on this explanatory page omits RI in one row).
K2 test stops after its first 31 letters, before question marks or the
2006 missing-X/end-message issue. It validates only that intact prefix.
"""
import unittest
from k4 import KA, crypt
from transposition import grid_route, inverse_perm, permute

K2_C = 'VFPJUDEEHZWETZYVGWHKKQETGFQJNCE'
K2_P = 'ITWASTOTALLYINVISIBLEHOWSTHATPO'
K3_C = ''.join(('ENDYAHROHNLSRHEOCPTEOIBIDYSHNAIA',
'CHTNREYULDSLLSLLNOHSNOSMRWXMNE',
'TPRNGATIHNRARPESLNNELEBLPIIACAE',
'WMTWNDITEENRAHCTENEUDRETNHAEOE',
'TFOLSEDTIWENHAEIOYTEYQHEENCTAYCR',
'EIFTBRSPAMHHEWENATAMATEGYEERLB',
'TEEFOASFIOTUETUAEOTOARMAEERTNRTI',
'BSEDDNIAAHTTMSTEWPIEROAGRIEWFEB',
'AECTDDHILCEIHSITEGOEAOSDDRYDLORIT',
'RKLMLEHAGTDHARDPNEOHMGFMFEUHE',
'ECDMRIPFEIMEHNLSSTTRTVDOHW'))
K3_P = ('SLOWLYDESPARATLYSLOWLYTHEREMAINSOFPASSAGEDEBRISTHATENCUMBEREDTHELOWERPARTOFTHEDOORWAY'
'WASREMOVEDWITHTREMBLINGHANDSIMADEATINYBREACHINTHEUPPERLEFTHANDCORNERANDTHENWIDENINGTHE'
'HOLEALITTLEIINSERTEDTHECANDLEANDPEEREDINTHEHOTAIRESCAPINGFROMTHECHAMBERCAUSEDTHEFLAMET'
'OFLICKERBUTPRESENTLYDETAILSOFTHEROOMWITHINEMERGEDFROMTHEMISTXCANYOUSEEANYTHINGQ')


def literal_clockwise(text, width):
    rows = [text[i:i+width] for i in range(0, len(text), width)]
    assert all(len(row) == width for row in rows)
    return ''.join(rows[r][c] for c in range(width) for r in range(len(rows)-1, -1, -1))


class HistoricalTests(unittest.TestCase):
    def test_k2_intact_prefix(self):
        self.assertEqual(len(K2_C), 31)
        self.assertEqual(crypt(K2_C, 'ABSCISSA', KA, decrypt=True), K2_P)
        self.assertEqual(crypt(K2_P, 'ABSCISSA', KA), K2_C)

    def test_k3_published_rotation_recipe(self):
        self.assertEqual(len(K3_C), 336)
        self.assertEqual(len(K3_P), 336)
        a = grid_route(336, 24, axis='column', reverse_minor=True)
        b = grid_route(336, 8, axis='column', reverse_minor=True)
        self.assertEqual(permute(permute(K3_C, a), b), K3_P)
        self.assertEqual(permute(permute(K3_P, inverse_perm(b)), inverse_perm(a)), K3_C)
        self.assertEqual(literal_clockwise(literal_clockwise(K3_C, 24), 8), K3_P)

if __name__ == '__main__':
    unittest.main()
