#!/usr/bin/env python3
from RuneText import rune_map, RuneText
from NGrams import NGrams


#########################################
#  NGramShifter  :  Shift rune-pairs in a fixed-width running window
#########################################

class NGramShifter(object):
    def __init__(self, gramsize=3):  # 3 is the only reasonable value though
        self.gramsize = gramsize
        self.prob = NGrams.load(gramsize)

    def ngram_probability_heatmap(self, data):
        gram_count = len(data) // self.gramsize
        ret = [[] for _ in range(gram_count)]  # ret[x][y] x: parts, y: shifts
        for y in range(29):
            variant = data - y
            for x in range(gram_count):
                i = x * self.gramsize
                gram = ''.join(r.rune for r in variant[i:i + self.gramsize])
                ret[x].append((y, self.prob.get(gram, 0), gram))
        # sort most probable first
        for arr in ret:
            arr.sort(key=lambda x: -x[1])  # (shift, probability)
        return ret

    def guess_single(self, data, interrupt_chr=None):
        data = RuneText(data)
        res = self.ngram_probability_heatmap(data)
        fillup = ' ' * (2 * self.gramsize + 1)
        all_interrupts = []
        if interrupt_chr:
            for i, x in enumerate(data):
                if x.rune == interrupt_chr:
                    all_interrupts.append(i)
        for y in range(29):  # each row in output
            line = ''
            for i, obj in enumerate(res):  # each column per row
                txt = ''
                if obj[y][1] > 0:
                    for u in range(self.gramsize):
                        if (i * self.gramsize + u) in all_interrupts:
                            txt += '|'  # mark with preceding
                        txt += rune_map[obj[y][2][u]]
                line += txt + fillup[len(txt):]
            line = line.rstrip()
            if line:
                print(line)

    def guess(self, data, interrupt_chr=None):
        data = RuneText(data)  # create RuneText once and reuse
        for i in range(self.gramsize):
            print('offset:', i)
            self.guess_single(data[i:], interrupt_chr)
            print()


# NGramShifter().guess('ᛈᚢᛟᚫᛈᚠᛖᚱᛋᛈᛈᚦᛗᚾᚪᚱᛚᚹᛈᛖᚩᛈᚢᛠᛁᛁᚻᛞᛚᛟᛠ', 'ᛟ')
# NGramShifter().guess([1, 2, 4, 5, 7, 9, 0, 12], 'ᛟ')
