#!/usr/bin/env python3
# Copyright © 2012-13 Qtrac Ltd. All rights reserved.
# This program or module is free software: you can redistribute it
# and/or modify it under the terms of the GNU General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version. It is provided for
# educational purposes and is distributed in the hope that it will be
# useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.

import os
import sys
import tkinter as tk
import tkinter.ttk as ttk
import tkinter.messagebox as messagebox
Spinbox = ttk.Spinbox if hasattr(ttk, "Spinbox") else tk.Spinbox
if __name__ == "__main__": # For stand-alone testing with parallel TkUtil
    sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__),
        "..")))
import About
import Board
import Help
import Options
import Preferences
import Shapes
import TkUtil
import TkUtil.Settings
import TkUtil.Tooltip
from Globals import *


class Window(ttk.Frame):

    def __init__(self, master):
        super().__init__(master, padding=PAD)
        self.create_variables()
        self.create_images()
        self.create_ui()


    def create_variables(self):
        self.helpDialog = None
        settings = TkUtil.Settings.Data
        self.toolbar = None
        self.showToolbar = tk.BooleanVar()
        self.showToolbar.set(settings.get_bool(GENERAL, SHOWTOOLBAR, True))
        self.shapeName = tk.StringVar()
        self.shapeName.set(settings.get_str(GENERAL, SHAPENAME,
                Shapes.Shapes[0].name))
        self.images = {}
        self.statusText = tk.StringVar()
        self.scoreText = tk.StringVar()
        self.zoom = tk.StringVar()
        self.zoom.set(settings.get_int(GENERAL, ZOOM, 100))
        self.restore = settings.get_bool(GENERAL, RESTORE, True)


    def create_ui(self):
        self.create_board() # Must come before (hideable) toolbar and menu
        self.create_menubar()
        if self.showToolbar.get():
            self.toggle_toolbar()
        self.create_statusbar()
        self.create_bindings()
        settings = TkUtil.Settings.Data
        if self.restore:
            position = settings.get_str(GENERAL, POSITION)
            if position is not None:
                self.master.geometry(position)
        self.master.resizable(False, False)


    def create_images(self):
        imagePath = os.path.join(os.path.dirname(
                os.path.realpath(__file__)), "images")
        for name in ([NEW, CLOSE, PREFERENCES, SHAPE, HELP, ABOUT] +
                sorted(Shapes.ShapeForName.keys())):
            self.images[name] = tk.PhotoImage(
                    file=os.path.join(imagePath, name + "_16x16.gif"))


    def create_menubar(self):
        self.menubar = tk.Menu(self.master)
        self.master.config(menu=self.menubar)
        self.create_file_menu()
        self.create_edit_menu()
        self.create_help_menu()


    def create_file_menu(self):
        # Ctrl is nicer than Control for menus
        modifier = TkUtil.menu_modifier()
        fileMenu = tk.Menu(self.menubar, name="apple")
        fileMenu.add_command(label=NEW, underline=0,
                command=self.board.new_game, compound=tk.LEFT,
                image=self.images[NEW], accelerator=modifier + "+N")
        if TkUtil.mac():
            self.master.createcommand("exit", self.close)
        else:
            fileMenu.add_separator()
            fileMenu.add_command(label="Quit", underline=0,
                    command=self.close, compound=tk.LEFT,
                    image=self.images[CLOSE],
                    accelerator=modifier + "+Q")
        self.menubar.add_cascade(label="File", underline=0,
                menu=fileMenu)


    def create_edit_menu(self):
        editMenu = tk.Menu(self.menubar)
        shapeMenu = tk.Menu(editMenu)
        editMenu.add_cascade(label=SHAPE, underline=0,
                menu=shapeMenu, image=self.images[SHAPE],
                compound=tk.LEFT)
        for name in sorted(Shapes.ShapeForName.keys()):
            shape = Shapes.ShapeForName[name]
            shapeMenu.add_radiobutton(label=shape.name,
                    underline=shape.underline, value=shape.name,
                    variable=self.shapeName, compound=tk.LEFT,
                    image=self.images[shape.name])
        if TkUtil.mac():
            self.master.createcommand("::tk::mac::ShowPreferences",
                    self.preferences)
        else:
            editMenu.add_command(label=PREFERENCES + ELLIPSIS, underline=0,
                    command=self.preferences,
                    image=self.images[PREFERENCES], compound=tk.LEFT)
        editMenu.add_checkbutton(label="Show Toolbar", underline=5,
                onvalue=True, offvalue=False, variable=self.showToolbar,
                command=self.toggle_toolbar)
        self.menubar.add_cascade(label="Edit", underline=0,
                menu=editMenu)


    def create_help_menu(self):
        helpMenu = tk.Menu(self.menubar, name="help")
        if TkUtil.mac():
            self.master.createcommand("tkAboutDialog", self.about)
            self.master.createcommand("::tk::mac::ShowHelp", self.help)
        else:
            helpMenu.add_command(label=HELP, underline=0,
                    command=self.help, image=self.images[HELP],
                    compound=tk.LEFT, accelerator="F1")
            helpMenu.add_command(label=ABOUT, underline=0,
                    command=self.about, image=self.images[ABOUT],
                    compound=tk.LEFT)
        self.menubar.add_cascade(label=HELP, underline=0,
                menu=helpMenu)


    def create_board(self):
        settings = TkUtil.Settings.Data
        columns = settings.get_int(BOARD, COLUMNS, Board.DEF_COLUMNS)
        rows = settings.get_int(BOARD, ROWS, Board.DEF_ROWS)
        maxColors = settings.get_int(BOARD, MAXCOLORS,
                Board.DEF_MAX_COLORS)
        delay = settings.get_int(BOARD, DELAY, Board.DEF_DELAY)
        self.board = Board.Board(self.master, self.zoom,
                self.shapeName, self.set_status_text, self.scoreText,
                columns, rows, maxColors, delay)
        self.board.highScore = settings.get_int(BOARD, HIGHSCORE, 0)
        self.board.update_score()
        self.board.pack(fill=tk.BOTH, expand=True)


    def create_toolbar(self):
        self.toolbar = ttk.Frame(self.master)
        newButton = ttk.Button(self.toolbar, text=NEW, takefocus=False,
                image=self.images[NEW], command=self.board.new_game)
        TkUtil.Tooltip.Tooltip(newButton, text="New Game")
        zoomLabel = ttk.Label(self.toolbar, text="Zoom:")
        self.zoomSpinbox = Spinbox(self.toolbar,
                textvariable=self.zoom, from_=Board.MIN_ZOOM,
                to=Board.MAX_ZOOM, increment=Board.ZOOM_INC, width=3,
                justify=tk.RIGHT, validate="all")
        self.zoomSpinbox.config(validatecommand=(
                self.zoomSpinbox.register(self.validate_int), "%P"))
        TkUtil.Tooltip.Tooltip(self.zoomSpinbox, text="Zoom level (%)")
        self.shapeCombobox = ttk.Combobox(self.toolbar, width=8,
                textvariable=self.shapeName, state="readonly",
                values=sorted(Shapes.ShapeForName.keys()))
        TkUtil.Tooltip.Tooltip(self.shapeCombobox, text="Tile Shape")
        TkUtil.add_toolbar_buttons(self.toolbar, (newButton, None,
                zoomLabel, self.zoomSpinbox, self.shapeCombobox))
        self.toolbar.pack(side=tk.TOP, fill=tk.X, before=self.board)


    def validate_int(self, number):
        return TkUtil.validate_spinbox_int(self.zoomSpinbox, number)


    def create_statusbar(self):
        statusBar = ttk.Frame(self.master)
        statusLabel = ttk.Label(statusBar, textvariable=self.statusText)
        statusLabel.grid(column=0, row=0, sticky=(tk.W, tk.E))
        scoreLabel = ttk.Label(statusBar, textvariable=self.scoreText,
                relief=tk.SUNKEN)
        scoreLabel.grid(column=1, row=0)
        TkUtil.Tooltip.Tooltip(scoreLabel,
                text="Current score (High score)")
        statusBar.columnconfigure(0, weight=1)
        statusBar.pack(side=tk.BOTTOM, fill=tk.X)
        self.set_status_text("Click a tile or click File→New for a new "
                "game")


    def set_status_text(self, text):
        self.statusText.set(text)
        self.master.after(SHOW_TIME, lambda: self.statusText.set(""))


    def create_bindings(self):
        # Can't use Ctrl for key bindings
        modifier = TkUtil.key_modifier()
        self.master.bind("<{}-n>".format(modifier), self.board.new_game)
        self.master.bind("<{}-q>".format(modifier), self.close)
        self.master.bind("<F1>", self.help)


    def close(self, event=None):
        settings = TkUtil.Settings.Data
        settings.put(BOARD, COLUMNS, self.board.columns)
        settings.put(BOARD, ROWS, self.board.rows)
        settings.put(BOARD, MAXCOLORS, self.board.maxColors)
        settings.put(BOARD, DELAY, self.board.delay)
        settings.put(BOARD, HIGHSCORE, self.board.highScore)
        settings.put(GENERAL, SHAPENAME, self.shapeName.get())
        settings.put(GENERAL, ZOOM, int(self.zoom.get()))
        settings.put(GENERAL, SHOWTOOLBAR, bool(self.showToolbar.get()))
        settings.put(GENERAL, RESTORE, self.restore)
        if self.restore:
            geometry = TkUtil.geometry_for_str(self.master.geometry())
            position = TkUtil.str_for_geometry(x=geometry.x, y= geometry.y)
            settings.put(GENERAL, POSITION, position)
        TkUtil.Settings.save()
        self.quit()


    def toggle_toolbar(self):
        if self.toolbar is None:
            self.create_toolbar()
        else:
            self.toolbar.pack_forget()
            self.toolbar = None


    def preferences(self):
        oldShapeName = self.shapeName.get()
        oldZoom = self.zoom.get()
        showToolbar = bool(self.showToolbar.get())
        options = Options.Options(False, showToolbar, self.restore,
                self.shapeName, self.zoom, self.board)
        Preferences.Window(self, options)
        if options.ok:
            if options.showToolbar != showToolbar:
                self.showToolbar.set(not showToolbar)
                self.toggle_toolbar()
            self.restore = options.restore
        else:
            self.shapeName.set(oldShapeName)
            self.zoom.set(oldZoom)
        self.focus()


    def help(self, event=None):
        if self.helpDialog is None:
            self.helpDialog = Help.Window(self)
        else:
            self.helpDialog.deiconify()


    def about(self):
        About.Window(self)


if __name__ == "__main__":
    if sys.stdout.isatty():
        application = tk.Tk()
        application.title("Window")
        TkUtil.Settings.DOMAIN = "Qtrac"
        TkUtil.Settings.APPNAME = APPNAME
        TkUtil.Settings.load()
        window = Window(application)
        application.protocol("WM_DELETE_WINDOW", window.close)
        application.mainloop()
    else:
        print("Loaded OK")