#                       Copyright 2021 Saad Mairaj
#
#    Licensed under the Apache License, Version 2.0 (the "License");
#    you may not use this file except in compliance with the License.
#    You may obtain a copy of the License at
#
#        http://www.apache.org/licenses/LICENSE-2.0
#
#    Unless required by applicable law or agreed to in writing, software
#    distributed under the License is distributed on an "AS IS" BASIS,
#    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#    See the License for the specific language governing permissions and
#    limitations under the License.

import random
import tkinter as tk

from tkinter import font
from tkinter import ttk
from tkinter.colorchooser import askcolor

from tkmacosx import SFrame, Button, Colorscale, ColorVar
from tkmacosx.utils import check_light_dark


def grid(root, row, column):
    "Defines rows and columns if grid method is used"
    for y in range(column):
        tk.Grid.columnconfigure(root, y, weight=1)
    for x in range(row):
        tk.Grid.rowconfigure(root, x, weight=1)


def sort_random_values(fn):
    def wrapper(*args, **kwargs):
        value = fn(*args, **kwargs)
        if isinstance(value, (list, tuple)) and len(value) == 1:
            return value[0]
        return value
    return wrapper


def choices(seq, k):
    "Random choices."
    return tuple(random.choice(seq) for i in range(k))


@sort_random_values
def get_random_colors(k=1):
    return ["#%06x" % random.randint(0, 0xFFFFFF) for n in range(k)]


@sort_random_values
def get_random_font(k=1):
    def family():
        return random.choice(font.families())

    def weight():
        return random.choice(('bold', 'normal'))

    def slant():
        return random.choice(('italic', 'roman'))

    def underline():
        return random.choice((True, False))

    overstrike = underline
    return tuple(font.Font(family=family(), weight=weight(),
                           slant=slant(), underline=underline(),
                           overstrike=overstrike(), size=30,) for i in range(k))


@sort_random_values
def get_random_size(k=1, start=10, end=200):
    return tuple(choices([i for i in range(start, end)], k=k))


@sort_random_values
def get_random_relief(k=1):
    return choices(('flat', 'groove', 'raised',
                    'ridge', 'solid', 'sunken'), k=k)


class Sample(tk.Tk):
    def __init__(self):
        tk.Tk.__init__(self)
        self.resizable(0, 0)
        self.geometry('420x700+300+100')
        self.title('Mac OSX Button Testing')
        self.wm_attributes('-modified', 1)
        self.main_color = ColorVar(value='#ffe6f4')
        self['bg'] = self.main_color
        grid(self, 25, 5)
        self.L1 = tk.Label(self, text='Comparison',
                           bg=self.main_color, font=('', 18, 'bold'))
        self.L1.grid(row=0, column=0, columnspan=5, sticky='nsew')
        Button(self, text='Hello').grid(row=1, column=1, sticky='s')
        ttk.Button(self, text='Hello').grid(row=1, column=3, sticky='s')
        tk.Button(self, text='Hello').grid(row=1, column=2, sticky='s')
        tk.Label(self, bg=self.main_color, font=('', 10),
                 text='(Mac OSX)').grid(row=2, column=1, sticky='n',)
        tk.Label(self, bg=self.main_color, font=('', 10),
                 text='(ttk themed)').grid(row=2, column=3, sticky='n')
        tk.Label(self, bg=self.main_color, font=('', 10),
                 text='(Default)').grid(row=2, column=2, sticky='n')
        ttk.Separator(self, orient='vertical').grid(
            row=3, column=0, columnspan=5, sticky='ew')

        # ------------ Seperator -------------

        # ------------ Demonstration ------------

        self.sfr = SFrame(self, bg=self.main_color)
        self.sfr.grid(rowspan=27, columnspan=5, sticky='nsew')
        for i in range(5):
            self.sfr.grid_columnconfigure(i, weight=1)
        self.L2 = tk.Label(self.sfr, text='Demonstration',
                           bg=self.main_color, font=('', 20, 'bold'))
        self.L2.grid(row=1, column=0, columnspan=5,
                     sticky='new', pady=(20, 10))

        # ------------ Active Color ------------

        self.L3 = tk.Label(self.sfr, text='1. Change Active color', bg=self.main_color,
                           font=('', 15, 'bold'))
        self.L3.grid(row=2, column=0, columnspan=5, sticky='nsew', pady=10)
        self.L4 = tk.Label(self.sfr, text='The active color can be changed to any gradient color.',
                           bg=self.main_color, font=('', 10))
        self.L4.grid(row=3, column=0, columnspan=5, sticky='new')
        self.B1 = Button(self.sfr, text='Press Me', pady=20)
        self.B1.grid(row=4, column=0, columnspan=5, pady=20)
        self.C1 = tk.StringVar(value='Select')
        self.L5 = tk.Label(self.sfr, text='From',
                           bg=self.main_color, font=('', 12))
        self.L5.grid(row=5, column=1, sticky='ew')

        self.L6 = tk.Label(self.sfr, text='To',
                           bg=self.main_color, font=('', 12))
        self.L6.grid(row=5, column=3, sticky='ew')
        
        button_container1 = tk.Frame(self.sfr, bg=self.main_color)
        button_container1.grid(row=6, column=0, columnspan=5,
                              sticky='ew', pady=10, padx=10)
        button_container1.columnconfigure(0, weight=1)
        button_container1.columnconfigure(1, weight=1)
        self.Om1_b = Button(button_container1, text='Change Color',
                         bg='#d0c0ea', borderless=1)
        self.Om1_b.grid(row=0, column=0, padx=(0, 2), sticky='ew')
        self.Om2_b = Button(button_container1, text='Change Color',
                         bg="#d0c0ea", borderless=1)
        self.Om2_b.grid(row=0, column=1, sticky='ew')
        self.Om1_b['command'] = lambda: self.change_active_color(1)
        self.Om2_b['command'] = lambda: self.change_active_color(2)

        # ------------ Background Color ------------

        self.L7 = tk.Label(self.sfr, text='2. Change Background color', bg=self.main_color,
                           font=('', 15, 'bold'))
        self.L7.grid(row=7, column=0, columnspan=5,
                     sticky='nsew', pady=(50, 0))
        self.L8 = tk.Label(self.sfr, text='Click on the button to choose the color.',
                           bg=self.main_color, font=('', 10))
        self.L8.grid(row=8, column=0, columnspan=5, sticky='new', pady=10)

        self.B2 = Button(self.sfr, text='Color me',
                         font=('', 30,), pady=10)
        self.B2.grid(row=9, column=0, columnspan=5, sticky='', pady=20)

        button_container2 = tk.Frame(self.sfr, bg=self.main_color)
        button_container2.grid(row=10, column=0, columnspan=5,
                              sticky='ew', pady=10, padx=10)
        button_container2.columnconfigure(0, weight=1)
        button_container2.columnconfigure(1, weight=1)
        self.B3 = Button(button_container2, text='Change Background Color',
                         bg='#d0c0ea', borderless=1)
        self.B3['command'] = lambda: self.B2.config(bg=askcolor()[1])
        self.B3.grid(row=0, column=0, padx=(0, 2))
        self.B4 = Button(button_container2, text='Change Foreground Color',
                         bg="#d0c0ea", borderless=1)
        self.B4['command'] = lambda: self.B2.config(fg=askcolor()[1])
        self.B4.grid(row=0, column=1)

        # ------------ Borderless ------------

        self.L9 = tk.Label(self.sfr, text='3. Switch Between Borderless', bg=self.main_color,
                           font=('', 15, 'bold'))
        self.L9.grid(row=11, column=0, columnspan=5,
                     sticky='sew', pady=(50, 0))
        self.L10 = tk.Label(self.sfr, text="""
    In borderless it will blend with its parent widget background color.
    Give parameter `borderless = True / False` to use it.""", bg=self.main_color, font=('', 10))
        self.L10.grid(row=12, column=0, columnspan=5, sticky='new')

        self.B5 = Button(self.sfr, text='No Borders', borderless=1, height=40,
                         bg='#212F3D', fg='white', activebackground=("#EAECEE", "#212F3D"))
        self.B5.grid(row=13, columnspan=5, pady=(20, 5))

        self.B6 = Button(self.sfr, text='No Borders', borderless=1, height=40,
                         bg='#F7DC6F', fg='#21618C', activebackground=('#B3B6B7', '#58D68D'))
        self.B6.grid(row=14, columnspan=5, pady=(0, 20))
        self.var1 = tk.BooleanVar(value=True)
        self.CB1 = tk.Checkbutton(self.sfr, text='Toggle Borderless', variable=self.var1,
                                  bg=self.main_color, command=self.change_borderless_state)
        self.CB1.grid(row=15, columnspan=5, pady=(0, 10))

        # ------------ Bordercolor ------------

        self.L11 = tk.Label(self.sfr, text='4. Change Bordercolor', bg=self.main_color,
                            font=('', 15, 'bold'))
        self.L11.grid(row=16, column=0, columnspan=5,
                      sticky='sew', pady=(50, 0))
        self.L12 = tk.Label(self.sfr, text="Change Bordercolor of the button\nNote: if borderless=True, then the bordercolor won't work.",
                            bg=self.main_color, font=('', 10))
        self.L12.grid(row=17, column=0, columnspan=5, sticky='new')

        self.B7 = Button(self.sfr, text='Button', pady=10,
                         padx=5, font=('Zapfino', 12, 'bold'))
        self.B7.grid(row=18, columnspan=5, pady=30)

        self.CS1 = Colorscale(self.sfr, value='hex', mousewheel=1,
                              command=lambda e: self.B7.config(bordercolor=e))
        self.CS1.grid(row=19, columnspan=5, sticky='ew', padx=10)

        self.CS2 = Colorscale(self.sfr, value='hex', mousewheel=1,
                              gradient=('#FCF6F5', '#990011'),
                              command=lambda e: self.B7.config(bg=e))
        self.CS2.grid(row=20, columnspan=5, sticky='ew', padx=10, pady=5)

        self.CS3 = Colorscale(self.sfr, value='hex', mousewheel=1,
                              gradient=('green', 'yellow'),
                              command=lambda e: self.B7.config(fg=e))
        self.CS3.grid(row=21, columnspan=5, sticky='ew', padx=10)

        self.CS4 = Colorscale(self.sfr, value='hex', mousewheel=1,
                              gradient=('pink', 'purple'),
                              command=lambda e: self.B7.config(overforeground=e))
        self.CS4.grid(row=22, columnspan=5, sticky='ew', padx=10, pady=5)

        # ------------ Random button styling ------------
        self.L11 = tk.Label(self.sfr, text='5. Button Styling', bg=self.main_color,
                            font=('', 15, 'bold'))
        self.L11.grid(row=23, column=0, columnspan=5,
                      sticky='sew', pady=(50, 0))
        self.L12 = tk.Label(self.sfr, text="Press the button to ramdomise the style of the button.",
                            bg=self.main_color, font=('', 10))
        self.L12.grid(row=24, column=0, columnspan=5, sticky='new')

        self.B10 = Button(self.sfr, text='Button', borderless=1)
        self.B10.grid(row=25, columnspan=5, pady=20)

        self.B11 = Button(self.sfr, text='Change Style', borderless=1, fg='#21618C',
                          activebackground=('#B3B6B7', '#58D68D'), command=self.change_button_style)
        self.B11.grid(row=26, columnspan=5, ipady=5)

        self.button_clicks = 1
        self.Text1 = tk.Text(self.sfr, background=self.main_color, highlightthickness=0,
                             relief='sunken', height=20, bd=2, padx=10)
        self.Text1.grid(row=27, columnspan=5, pady=20, padx=20)
        self.sfr._avoid_mousewheel(
            (self.Text1, self.CS1, self.CS2, self.CS3, self.CS4))
        self.change_button_style()
        self.update_idletasks()

    def change_active_color(self, num):
        hexcode = askcolor()[1]
        if num == 1:
            self.Om1_b['bg'] = self.Om1_b['text'] = hexcode
            self.Om1_b['fg'] = check_light_dark(hexcode)
        else:
            self.Om2_b['bg'] = self.Om2_b['text'] = hexcode
            self.Om2_b['fg'] = check_light_dark(hexcode)
        self.B1['activebackground'] = (self.Om1_b['bg'], self.Om2_b['bg'])

    def change_borderless_state(self):
        if self.var1.get():
            self.B5['borderless'] = 1
            self.B6['borderless'] = 1
        else:
            self.B5['borderless'] = 0
            self.B6['borderless'] = 0

    def change_button_style(self):
        cnf = dict(
            foreground=get_random_colors(),
            background=get_random_colors(),
            activebackground=get_random_colors(2),
            activeforeground=get_random_colors(),
            overrelief=get_random_relief(),
            relief=get_random_relief(),
            highlightthickness=get_random_size(1, 1, 5),
            borderwidth=get_random_size(1, 1, 5),
            font=get_random_font(),
            highlightbackground=get_random_colors(),
            focuscolor=get_random_colors(),
            overbackground=get_random_colors(),
            overforeground=get_random_colors(),
        )
        self.B10.config(**cnf)

        self.Text1.insert('end', '\n\nBUTTON STYLE %s\n\n' %
                          self.button_clicks)
        for k, v in cnf.items():
            if k == 'font':
                self.Text1.insert('end', 'font:\n')
                for i, j in v.config().items():
                    self.Text1.insert('end', '\t%s\t\t= %s\n' % (i, j))
            else:
                self.Text1.insert('end', '%s\t\t\t= %s\n' % (k, v))
        self.Text1.see('end')
        self.Text1.insert('end', '\n\n'+'-'*40)
        self.button_clicks += 1
        self.sfr['canvas'].yview_moveto('1.0')
        self.update_idletasks()


def main():
    "Demonstration of tkmacosx."
    Sample().mainloop()


#  Testing Demo
if __name__ == "__main__":
    main()
