import tkinter as tk
from tkinter import filedialog, messagebox, scrolledtext
from pathlib import Path
import random

def load_file_to_text(widget):
    p = filedialog.askopenfilename(filetypes=[("Text files","*.txt"),("All files","*.*")])
    if p:
        widget.delete('1.0', tk.END)
        widget.insert(tk.END, Path(p).read_text(encoding='utf-8'))

def save_text_to_file(text):
    p = filedialog.asksaveasfilename(defaultextension=".txt", filetypes=[("Text files","*.txt"),("All files","*.*")])
    if p:
        Path(p).write_text(text, encoding='utf-8')

def build_index_map(doc):
    idx = {}
    for i, ch in enumerate(doc, start=1):
        idx.setdefault(ch, []).append(i)
    return idx

def encrypt_action():
    doc = doc_text.get('1.0', tk.END)[:-1]  # remove trailing extra newline
    msg = input_text.get('1.0', tk.END)[:-1]
    if not doc:
        messagebox.showerror("Fehler", "Dokument ist leer.")
        return
    idx = build_index_map(doc)
    try:
        positions = [str(random.choice(idx[ch])) for ch in msg]
    except KeyError as e:
        messagebox.showerror("Fehler", f"Zeichen nicht im Dokument: {repr(e.args[0])}")
        return
    out = ','.join(positions)
    output_text.delete('1.0', tk.END)
    output_text.insert(tk.END, out)

def decrypt_action():
    doc = doc_text.get('1.0', tk.END)[:-1]
    nums = output_text.get('1.0', tk.END).strip()
    if not doc:
        messagebox.showerror("Fehler", "Dokument ist leer.")
        return
    if not nums:
        input_text.delete('1.0', tk.END)
        return
    parts = [p.strip() for p in nums.split(',') if p.strip()!='']
    doc_len = len(doc)
    chars = []
    try:
        for p in parts:
            if not p.isdigit():
                raise ValueError(f"Ungültige Zahl: {p}")
            idx = int(p)
            if idx < 1 or idx > doc_len:
                raise ValueError(f"Position außerhalb des Bereichs: {idx}")
            chars.append(doc[idx-1])
    except Exception as e:
        messagebox.showerror("Fehler", str(e))
        return
    input_text.delete('1.0', tk.END)
    input_text.insert(tk.END, ''.join(chars))

def load_doc_file():
    load_file_to_text(doc_text)

def load_message_file():
    load_file_to_text(input_text)

def save_numbers():
    save_text_to_file(output_text.get('1.0', tk.END).strip())

def save_message():
    save_text_to_file(input_text.get('1.0', tk.END))

root = tk.Tk()
root.title("Text-Position Cipher")

# Frames and widgets
left = tk.Frame(root)
left.pack(side=tk.LEFT, fill=tk.BOTH, expand=True, padx=6, pady=6)
right = tk.Frame(root)
right.pack(side=tk.RIGHT, fill=tk.BOTH, expand=True, padx=6, pady=6)

tk.Label(left, text="Gemeinsames Dokument (doc.txt)").pack(anchor='w')
doc_text = scrolledtext.ScrolledText(left, width=60, height=15)
doc_text.pack(fill=tk.BOTH, expand=True)
tk.Button(left, text="Dokument laden", command=load_doc_file).pack(anchor='w', pady=4)

tk.Label(left, text="Klartext Nachricht").pack(anchor='w')
input_text = scrolledtext.ScrolledText(left, width=60, height=8)
input_text.pack(fill=tk.BOTH, expand=True)
btn_frame = tk.Frame(left)
btn_frame.pack(fill='x', pady=4)
tk.Button(btn_frame, text="Nachricht laden", command=load_message_file).pack(side='left')
tk.Button(btn_frame, text="Nachricht speichern", command=save_message).pack(side='left', padx=6)

tk.Label(right, text="Zahlen (cipher)").pack(anchor='w')
output_text = scrolledtext.ScrolledText(right, width=40, height=30)
output_text.pack(fill=tk.BOTH, expand=True)
tk.Button(right, text="Zahlen speichern", command=save_numbers).pack(anchor='w', pady=4)

op_frame = tk.Frame(root)
op_frame.pack(fill='x', padx=6, pady=(0,6))
tk.Button(op_frame, text="Encrypt → Zahlen", command=encrypt_action).pack(side='left', padx=6)
tk.Button(op_frame, text="Decrypt → Nachricht", command=decrypt_action).pack(side='left', padx=6)
tk.Button(op_frame, text="Beenden", command=root.destroy).pack(side='right', padx=6)

root.mainloop()
