#!/usr/bin/python2
# -*- coding: utf-8 -*-

from animations import *
from forms import *
from protocol import JurassicProtocol

from Tkinter import *
from ttk import *
from PIL import Image, ImageTk
import time
import shelve


SERVER_1 = "10.13.37.171:9090"
SERVER_2 = "10.13.37.172:9090"


class JurassicSparcSystemSecurityInterface(Frame):

    def __init__(self, parent):

        """
        Init the GUI and launches the Magic Word animation.
        Connects to the first available server.
        """

        Frame.__init__(self, parent, padding=(0, 10, 0, 0))

        self.parent = parent

        self.initSettings()
        self.initUI()
        self.initNetwork()

        self.animation = AnimationAccessSecurityGrid(self)

    def initSettings(self):

        """
        Set default settings (view in the settings popup).
        Saves data on disk in settings.dat.
        """

        self.settings = shelve.open("settings.dat")

        if not self.settings.has_key('login'):
            self.settings['login'] = "RayArnold"
            self.settings['password'] = "better_be_mace_windu_amiright"
            self.settings['magic'] = "0x31337"
            self.settings['server1'] = SERVER_1
            self.settings['server2'] = SERVER_2

    def initNetwork(self):

        """
        Connects to the first available server.
        """

        for server in ['server1', 'server2']:
            try:
                host, port = self.settings[server].split(':')
                magic = self.settings['magic']
                self.protocol = JurassicProtocol(host, int(port), int(magic, 16))
                break
            except:
                continue
        else:
            print "[-] Cannot connect to any server :("

    def initUI(self):
        self.parent.title("Jurassic Sparc Control Center")
        self.style = Style()
        self.style.theme_use("default")
        self.pack(fill=BOTH, expand=True)

        self.columnconfigure(0, weight=1)
        self.columnconfigure(1, weight=0)
        self.rowconfigure(0, weight=0, pad=10)

        for i in range(1, 6):
            self.rowconfigure(i, weight=0)

        self.rowconfigure(6, weight=1)

        # Tabs

        noteBook = Notebook(self)
        console = Frame(noteBook, padding=(5, 5, 5, 5));
        lab = Frame(noteBook, padding=(5, 5, 5, 5));
        noteBook.add(console, text='Central Park Console')
        noteBook.add(lab, text='Laboratory Manager', state=DISABLED)

        noteBook.grid(row=0, column=0, rowspan=7, sticky=(N, S, E, W))

        # Logo on the top right

        logo = Image.open("logo.png").resize((64, 64), Image.ANTIALIAS)
        img = ImageTk.PhotoImage(logo)
        panel = Label(self, image=img)
        panel.image = img
        panel.grid(row=0, column=1)

        # Buttons on the right

        self.settingsButton =  Button(self, text="Settings", command=self.settingsAction)
        self.settingsButton.grid(row=1, column=1, sticky=W, padx=15, pady=5)

        self.aboutButton =  Button(self, text="About", command=self.aboutAction)
        self.aboutButton.grid(row=2, column=1, sticky=W, padx=15, pady=5)

        self.rebootButton =  Button(self, text="Reboot", command=self.rebootAction)
        self.rebootButton.grid(row=3, column=1, sticky=W, padx=15, pady=5)

        self.replayButton =  Button(self, text="Replay", command=replay)
        self.replayButton.grid(row=4, column=1, sticky=W, padx=15, pady=5)

        self.closeButton =  Button(self, text="Close", command=self.parent.destroy)
        self.closeButton.grid(row=5, column=1, sticky=W, padx=15, pady=5)

        # "Central Park Console" Tab

        self.consoleText = Text(console, bg="#2b34f1", fg="white")
        self.consoleText.pack(fill=BOTH, expand=True)
        self.consoleText.config(state=DISABLED)

        # "Laboratory Manager" Tab -- removed

    def rebootAction(self):

        """
        Popup for Jurassic Sparc security system reboot.
        Prints a timer that goes down to zero.
        If the window is closed before the timer is at zero, no reboot is performed.
        """

        t = Toplevel(self, pady=10, padx=10)
        t.geometry("400x130+300+300")
        t.resizable(0,0)
        t.wm_title("Rebooting the system...")

        self.rebootWindow = t

        self.rebootLabel = StringVar()
        rebootLabel = Label(t, text="Reboot in 300 seconds...",
                            font="TkDefaultFont 10 bold", textvariable=self.rebootLabel)
        rebootLabel.grid(row=0, column=0)

        messageLabel = Label(t, text="The system is going to reboot.\n" + \
                             "This may close your connection to the security interface...")
        messageLabel.grid(row=1, column=0, sticky="W", pady=10)

        messageLabel = Label(t, text="Leave a reboot message:", font="TkDefaultFont 10 bold")
        messageLabel.grid(row=2, column=0, sticky="W")

        self.rebootEntry = MaxLengthEntry(t, maxlength=50, width=40)
        self.rebootEntry.delete(0, END)
        self.rebootEntry.insert(0, "Trying to fix everything.")
        self.rebootEntry.grid(row=3, column=0, padx=15, pady=5)

        AnimationReboot(10, self)

    def doRebootAction(self):

        """
        Action triggered when the reboot timer is down to zero.
        Stops the magic word animation.
        Replay after 5seconds.
        """

        try:
            self.animation.cont = False
            self.animation.t.destroy()
        except:
            pass

        msg = self.protocol.reboot(self.rebootEntry.get())

        self.rebootButton.config(state=DISABLED)

        self.consoleText.config(state=NORMAL)
        self.consoleText.delete("@0,0", END)

        self.consoleText.mark_set("insert", "0.0")

        for i in range(500):
            self.consoleText.insert(END, "\n")

        lastline = self.consoleText.index("@0,%d" % self.consoleText.winfo_height())
        lastline = "%d.0" % (int(lastline.split('.')[0]) - 1)
        self.consoleText.delete(lastline, END)
        self.consoleText.insert(END, "\n" + msg)

        self.consoleText.config(state=DISABLED)

        self.after(5000, replay)

    def settingsAction(self):

        """ The settings popup """

        t = Toplevel(self, pady=10, padx=10)
        t.geometry("380x340+300+300")
        t.resizable(0,0)
        t.wm_title("Settings")

        self.settingsWindow = t

        settingsLabel = Label(t, text="Settings", font="TkDefaultFont 10 bold")
        settingsLabel.grid(row=0, column=0)

        self.loginEntry    = MaxLengthEntry(t, maxlength=50,  width=40)
        self.passwordEntry = MaxLengthEntry(t, maxlength=150, width=40)
        self.magicEntry    = MaxLengthEntry(t, maxlength=16,  width=40)
        self.server1Entry  = MaxLengthEntry(t, maxlength=200, width=40)
        self.server2Entry  = MaxLengthEntry(t, maxlength=200, width=40)

        fields = [
            ('Login', 'login', self.loginEntry),
            ('Password', 'password', self.passwordEntry),
            ('Magic Word', 'magic', self.magicEntry),
            ('Primary Server', 'server1', self.server1Entry),
            ('Secondary Server', 'server2', self.server2Entry)
        ]
        row = 1

        for label, setting, entry in fields:
            Label(t, text=label + ":", font="TkDefaultFont 10 bold").grid(row=row, column=0, sticky="W")
            row += 1
            entry.delete(0, END)
            entry.insert(0, self.settings[setting])
            entry.grid(row=row, column=0)
            row += 1

        buttons = Frame(t)
        buttons.grid(row=11, column=0)

        saveButton = Button(buttons, text="Save", command=self.saveSettings)
        saveButton.pack(side=LEFT)

        cancelButton = Button(buttons, text="Cancel", command=t.destroy)
        cancelButton.pack(side=RIGHT, padx=10)

        for i in range(11):
            if not i % 2:
                t.rowconfigure(i, weight=0)
            else:
                t.rowconfigure(i, weight=0, pad=15)

        t.rowconfigure(11, weight=0, pad=20)
        t.columnconfigure(0, weight=0, pad=30)
        t.columnconfigure(1, weight=0)

    def saveSettings(self):

        """ Action triggered when saving from the settings popup """

        self.settings['login'] = self.loginEntry.get()
        self.settings['password'] = self.passwordEntry.get()
        self.settings['magic'] = self.magicEntry.get()
        self.settings['server1'] = self.server1Entry.get()
        self.settings['server2'] = self.server2Entry.get()
        self.settings.sync()
        self.settingsWindow.destroy()

    def networkIssueAction(self):

        """ Network issue popup, whenever one is detected """

        t = Toplevel()
        t.geometry("480x120+300+300")
        t.resizable(0, 0)
        t.wm_title("Network issue")

        text  = "The client wasn't able to contact any server.\n"
        text += "Make sure your server settings are up to date, "
        text += "and restart the client.\n"
        text += "If the error persists, contact an admin!"

        Label(t, text="Cannot connect to server", font="TkDefaultFont 10 bold").grid(row=0, column=0)
        Label(t, text=text, anchor=W, justify=LEFT, wraplength=450).grid(row=1, column=0)

        t.columnconfigure(0,weight=1, pad=15)
        t.rowconfigure(0, weight=0, pad=15)
        t.rowconfigure(1, weight=1, pad=15)

    def aboutAction(self):

        """ About popup """

        t = Toplevel()
        t.geometry("480x190+300+300")
        t.resizable(0,0)
        t.wm_title("About")

        text  = "This challenge was splitted in two parts.\n\n"
        text += "In the first part your goal is to connect to the "
        text += "System Security Interface. "
        text += "You'll need to find the magic word and valid identifiers.\n"
        text += "You should know that the password policy in Jurassic Sparc "
        text += "is quite good, passwords are safe!\n\n"
        text += "The second part... was cancelled last minute :((( Sparc issues...\n"
        text += "All code related to that part was removed."

        Label(t, text="About", font="TkDefaultFont 10 bold").grid(row=0, column=0)
        Label(t, text=text, anchor=W, justify=LEFT, wraplength=450).grid(row=1, column=0)

        t.columnconfigure(0,weight=1, pad=15)
        t.rowconfigure(0, weight=0, pad=15)
        t.rowconfigure(1, weight=1, pad=15)


def gui():
    global root

    root = Tk()
    root.geometry("950x710+300+300")

    app = JurassicSparcSystemSecurityInterface(root)
    root.mainloop()

def replay():

    """
    Disconnects from the server, re-connect and play the console animation
    once more
    """

    global root

    root.destroy()
    gui()

if __name__ == '__main__':
    gui()
