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

# Copyright (C) 2019 Rod Engerstad


import Tkinter as tk
import tkMessageBox
import os
import shutil
import sys
import logging
import logging.config
import glob
from datetime import datetime
import string


class MyLogger(object):
    """
    Log events and exceptions.
    For exception logging need to initialise MyLogger to a global
    and wrap the main program in a try block:

    ----------------------------------------------------------
    def main():
       my_logger.logger.info("Program started")
       do stuff
       my_logger.logger.info("Success!")

    my_logger = MyLogger("log.txt", "INFO", "Main")
    try:
       main()
    except:
       my_logger.logger.exception("Unhandled exception during main")
    ----------------------------------------------------------

    See http://www.blog.pythonlibrary.org/2012/08/02/python-101-an-intro-to-logging/
    file_name - log file
    level - what to report: DEBUG, INFO, WARNING, ERROR, CRITICAL
    app_name - program name for messages
    """

    def __init__(self, file_name, level, app_name):
        dict_config = {
            "version":1,
            "handlers":{
                        "fileHandler":{
                            "class":"logging.FileHandler",
                            "formatter":"myFormatter",
                            "filename":file_name
                            }
                        },
            "loggers":{
                app_name:{
                    "handlers":["fileHandler"],
                    "level":level,
                    }
                },
            "formatters":{
                "myFormatter":{
                    "format":\
                        "%(asctime)s - %(name)s - %(levelname)s - %(message)s"
                    }
                }
            }
        logging.config.dictConfig(dict_config)
        self.logger = logging.getLogger(app_name)
        #start debug
        #ch = logging.StreamHandler(sys.stdout)
        #self.logger.addHandler(ch)
        #end debug


class Sgg(object):
    """
    Globals
    """
    version = 'v1.01'
    app_name = ''
    os = 'linux'
    logger = None
    program = ''
    """
    Get os.
    Set paths.
    Init Logger.
    """

    def __init__(self):
        operating_system = 'linux'
        if sys.platform.startswith('win'):
            operating_system = 'windows'
        elif sys.platform.startswith('dar'):
            operating_system = 'mac'
        else:
            if sys.version_info > (3,):
                Sgg.program = "python3"
            else:
                Sgg.program = "python"
           
        Sgg.os = operating_system
        path_name = sys.argv[0]
        app_name = os.path.split(path_name)[1]
        dot = app_name.find('.')
        if -1 == dot:
            dot = len(app_name)
        Sgg.app_name = app_name[:dot]
        package_name = '.pzl'
        path_name = os.path.expanduser('~') + os.sep + package_name + os.sep
        try:
            os.mkdir(path_name)
        except OSError:
            pass
        Sgg.app_data_path = path_name + 'PROGRAMS'

        try:
            os.mkdir(Sgg.app_data_path)
        except OSError:
            pass

        log_file_name = Sgg.app_data_path + os.sep + 'log.txt'
        Sgg.logger = MyLogger(log_file_name, "WARNING", "Main")


class SGImage(object):
    """
    Images
    """

    def __init__(self):
# get image files

        image = \
            tk.PhotoImage(data="""
R0lGODlhIAAgAPf/AGqzAG62A2+2BXC3B3G3CXK5Cni7FXi8FX2+Hn+/IH/AIoLAJorENIzENpDH
QJDIQJTJRZfKS5jLTZ/PWaDPWqTRYa3Wcb3djc7mrc/ortDmrNjrvN3uxP/+/wAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/ACH5BAEKAP8ALAAAAAAgACAA
AAj/AP/942ChgsGDCBMqPGiBg8B/FhZInEixosWLFgZe3MjRIsGOIDkWDFkxQQKQBklKTBDAgYMA
JzemJJlAQYebHRTEtDgzZACcOAPIrEATAtCbEBBc7NkRgYOjHRwo5Um0JIKrWBH8PBoAwc6JTBcU
YCAhgtmzECIAjQBBAoMCFZkW2AC17tENcMFWXZCAgd2/OBko0DsRgQTAgCVMXdATgVrEdiMsbnz4
woABFyDjlExYIoIJGoQuCJBZM2eJTBEcoDhAc4fTjPcuUM3aNezGEzCIJn3UMuajt/ca7nChwG+g
F3aXvhm88OG/A2rjVNx59nO70Se2nj55b1/AySXyPw48GLXsuYAxHDiQASheimHHlj17VgKFqxTK
us1bfWKCrABOldVXqEWk0oENHXigQwYq2FFGAhG00IQUNiRQQAA7
""")
        self.file = image

        image = \
            tk.PhotoImage(data="""
R0lGODdhlAAhAOfKAIG/JoK/J4LAJoLAKIPAKIPAKYTAKYXALYTBK4XBLIbBLobBL4bCLofCLojC
MYjCMorCM4fDMonDM4rDN4nENIzDN4vENYvEOIzEOY3EOozFOI3FPI7FPI7FPY/FPo/GPpDGP5DG
QJHGQZHGQ5HHQpLHQ5PHRJPHR5LIRJTIRZXISJXISZbISpfJTZjJTpjKTpnKUJnKUpjLT5rLUprL
U5vLVJzMVZzMVpzMV53MWJ3NWZ7NWZ/NWp/NW6HNXqDOXaHOX6POYKLPX6TPY6TPZKXPZKPQY6XQ
ZqbQaKfRaajRaqjRa6nRbKvRb6nSbarSbqvTcKzTca7Tda/Tdq3UdK/Ud6/Ueq/VebDVe7HVe7DW
erLWfrPWf7TXgbXXg7bYhbfYhbfYhrjZh7jZibjZirrZjbnai7rajLzaj73aj73akLzbjr7bkb7b
kr7blL/clL/clcLdmcLdmsPem8TenMTencbeoMXfnsXfn8bfoMffo8fgocfgosjgpMngpsjhpcrh
qMvhqsziq83irc3jrs7jr87jsM/jsdDkstDks9HktNHktdPkuNLlttPlt9TlutTlu9XlvNTmudXm
vNbmvdbmvtbmv9fnwNjnwtnowtnoxNvpxtzpyN3qyt7qy+Dqz+Dr0OHr0eHr0uLr0uLs0+Ls1ePs
1uPt1+Xt2eXu2ubu2ubu2+fu3Ofv3Ojv3ejv3unv3+nw4Orw4erw4uvw4uzw5evx4+zx5O3x5u3x
5+7x6O/x6e/y6u/y6+/y7PDy7fDz7fHz7vHz7/Lz8PL08fP08vT08/T19PX19fb29tbW1tbW1tbW
1tbW1tbW1tbW1tbW1tbW1tbW1tbW1tbW1tbW1tbW1tbW1tbW1tbW1tbW1tbW1tbW1tbW1tbW1tbW
1tbW1tbW1tbW1tbW1tbW1tbW1tbW1tbW1tbW1tbW1tbW1tbW1tbW1tbW1tbW1tbW1tbW1tbW1tbW
1tbW1tbW1tbW1tbW1tbW1tbW1tbW1tbW1tbW1tbW1tbW1tbW1tbW1iwAAAAAlAAhAAAI/gCTCRxI
sKDBgwgTKlzIsKHDhxAjSpxIsaLFixgzatzIsaPHjyBDihyZ7JWAkyhJqlzpEdggLCgFsJxJ8+Ku
mDVz6nRoDOfOn0AL+gxKdOdQichmFSvKdOLRh8j8ZBDQYFLTkANiymyUw8GDHWd+EaSjVesUgk8P
jtICYwIBCiJGaGhzktDAVmpiZDCwgYaZWwSFlU3WyEUCFYYEDoqhgMOSUweRWZJSQ8KFHWR2FfT1
JsYDBSKoUBFgKeIoPDHTnASAEgSngWsEFODiZ9GVmHnQpkyIjMtJCm3gQDgpRNcMF70EZnJwUomd
GycZhBp4TFScmIRYo4wERmuC6QR9/iE5uaFNmwgCKlgVeEuEABhq5iDRDkliMK1gXAUThOCkB14C
+XaHQK1IgJIRyOh2kkJwoOSIQImghEZBL6BkSjKnoLRDQb/ElEEYQKBEgQBJtNECSj4UJMVJBqwi
kCEnWUCLQE4IIMFSAlHSgACNSHRMTFEQZAZKYggUhQPCJFMMdCdhUItQuyG0AkoAJpMLSiIUNOJJ
gCiJUgUF/YjSH8l8EpMZyqHUAEGNoJTEQLiglIVAFpzUxisDISLAIU6htAlBoKB0g0B87CFQGSgB
cIlBaRGE3kmwCOQLShEUVIgFCyyhi5dRDhQTYPehhGcywBwVBUpTlKIqJSjBIFAJ/jF94EQfrsgC
TJ8nPTmQLigtUJAmAaBExkGNDpQESogIhAlKShiEjDGw6EEEA2nFlGAy1nraqQllaXWAQHZ0C0AV
OEYU060D9YKSCQTl0gFKNJSroEwJwcLCSSpQUokKJ5EwKkGSyHASDoBUG+VRR3mA0hgKIXPHjmWh
KVFMFw40CkpODITMeCc5oIpAS6gx70K6QIESARbUAIdYBfmBUh3PGrygQAh3OgRKTRgkCimHuvLL
I1/wQO1JJ+AqQBsEIXqSIgPxgZ1ApQjwxcgJMTLBSY0kqRAIKCXHSkzyYntwp0cRgpIDmw70Cwo/
0NyDMQP5csZJLBgdQWnJXLLA/klLDETKAagKVEwPAogsONgJYVAWAA10QMQjBe19EiXJeBETLMMM
VAzixMSUeTLDxAS3QMfkgBILqAiUyg0GiEIziegmA8tJYRh9hAAehOBm2sNMGR0hiOBhw0lyJGPM
H7ehtEUhCOneLbIEHXvSACUY0AVKGmBwzPFWxCTGKmLEtMUmm2whvh/HCKRLETGBkEIAClD+ugAT
eJGHGCgIYIPW5qKEjB06cAAJlMCngZjkeSchk2DKcgGEdKIGCBRACwiiiyts4AAsiAIokJEHGSjg
Bn9aoFYCURYrdK8s8tpEE17ggAiwID/zalIO/BC2hxRLJL84g+S6pYCrkOSGcCG5nQDqoDldsOEk
rvJhSJARk/TNRHK6GkgsTlIGJYJkF5KISSFmcS2VMOEkRPCEL4ZBC0jgQABB4J8VOZKVsniBJcVw
QwyCtZoKPOESXVwjR1TFRz7aoibFwEUqYFFDPRrykIhMpCIXychGOnInAQEAOw==
""")
        self.label = image


class View(tk.Toplevel):
    """
    Stick blobs on the screen and respond to callbacks
    """

    def __init__(self, master, settings):
        tk.Toplevel.__init__(self, master)
        self.protocol('WM_DELETE_WINDOW', self.master.destroy)
        self.title(string='pzl_installer')
        self.resizable(False, False)
        self.settings = settings
        self.menu_callback = None
        self.control_frame = None
        self.outer_frame = None
        self.menu_bar = None
        self.images = SGImage()
        self.grid_widgets = []
        self.make_frames(self)
        self.label1 = tk.Label(self.menu_bar, image=self.images.file)
        self.label1.grid(row=0, column=1)
        self.label2 = tk.Label(self.menu_bar, image=self.images.label)
        self.label2.grid(row=0, column=1)

    def make_frames(self, root):
        bg = self.settings.grey
        self.outer_frame = tk.Frame(root, bg=bg)
        self.outer_frame.grid()
        self.control_frame = tk.Frame(self.outer_frame,
                bd=2, bg=bg, relief='raised')
        self.control_frame.grid(row=0, column=0, sticky='W')
        self.menu_bar = tk.Frame(self.control_frame, relief='raised',
                                bd=2, bg=bg)
        self.menu_bar.grid(row=0, column=0, sticky='W')


    def quit(self):
        my_title = 'Quit ' + Sgg.app_name + '             '
        my_text = 'Quit ' + Sgg.app_name + '?              '
        if tkMessageBox.askyesno(my_title, my_text):
            self.my_destroy()

    def my_destroy(self):
        self.master.destroy()


class Settings(object):
    """
    Set and update all user controlled values and most other constants
    For globals in code which does not have access to Settings use Sgg.
    """

    nonexclusive = 'N'

    def __init__(self):
        self.menu = {}
        self.gray = '#C0C0C0'
        self.grey = '#dfdfdf'
        self.green = '#82c026'
        self.white = '#ffffff'
        self.black = '#000000'
        self.red = '#ff0000'


class Controller(object):
    """
    Set up and control
    """

    def __init__(self, root):
        self.settings = Settings()
        self.master = root
        self.view = View(root, self.settings)
        self.my_title = 'pzl installer'
        self.start_game()


    def start_game(self):
        package_directory = '.pzl'
        app_path = os.path.realpath(__file__)
        here = app_path[:app_path.rfind(os.sep)]
        there = os.path.expanduser('~') + os.sep + package_directory

        # package directory
        path_name = there
        self.make_directory(path_name)
        # programs directory
        path_name = there + os.sep + 'PROGRAMS'
        self.make_directory(path_name)
        programs_dir = path_name
        # icons directory
        path_name = there + os.sep + 'ICONS'
        self.make_directory(path_name)
        icons_dir = path_name

        # copy main programs and shared files
        files = glob.glob(here + os.sep + '*.pyw')
        for file_name in files:
            shutil.copy(file_name, programs_dir)
        files = glob.glob(here + os.sep + '*.py')
        for file_name in files:
            shutil.copy(file_name, programs_dir)
        
        if Sgg.os != 'windows':
            # more microsoft rubbish
            # give the files  proper names
            # (we had to  call them .pyw to satisfy M$)
            files = glob.glob(programs_dir + os.sep + '*.pyw')
            for file_name in files:
                os.rename(file_name, file_name[:-1])

        # copy icons
        files = glob.glob(here + os.sep + '*_icon.png')
        for file_name in files:
            shutil.copy(file_name, icons_dir)

        # Copy locales, moving previous version if it exists.
        # locales directory
        path_name = there + os.sep + 'PROGRAMS'
        self.do_locales(here, path_name)

        my_text = 'Success.\nAll program files copied to\n'
        my_text += programs_dir
        my_text += '\nAll icon files copied to\n'
        my_text += icons_dir
        my_text += '\nAll locales files copied to\n'
        locales_path = path_name + os.sep + 'locales'
        my_text += locales_path

        if Sgg.os == 'linux':
            l_path_1, l_path_2 = self.do_desktop(programs_dir, icons_dir)
            launcher_text = '\nLauncher files added:\n'
            launcher_text += l_path_1 + '\n'
            launcher_text += l_path_2 + '\n'
            my_text += launcher_text
            
        # Success
        

        tkMessageBox.showinfo(self.my_title, detail=my_text)
        self.view.my_destroy()

    def make_directory(self, path_name):
        if os.path.exists(path_name):
            if os.path.isdir(path_name):
                # noting to create (should be True for all but ICONS)
                pass
            else:
                my_text = path_name
                my_text += ' exists and is not a directory.'
                my_text += ' Aborting installation'
                tkMessageBox.showinfo(self.my_title, detail=my_text)
                exit(1)
        else:
            try:
                os.mkdir(path_name)
            except OSError:
                my_text = 'Unable to make directory'
                my_text += path_name
                my_text += ' Aborting installation'
                tkMessageBox.showinfo(self.my_title, detail=my_text)
                exit(1)

    def do_locales(self, here, path_name):
        locales_path = path_name + os.sep + 'locales'
        copy_ok = True

        def move_it():
            copy_ok = True
            dt = str(datetime.now())
            short =  dt[:dt.find('.')]
            output = ''
            for item in short:
                if item not in string.digits and item != '-':
                    output += '-'
                else:
                    output += item
            dst = path_name + os.sep + output + '_locales'
            try:
                shutil.move(locales_path, dst)
            except OSError:
                copy_ok = False
            return copy_ok

        if os.path.exists(locales_path):
            copy_ok = move_it()

        if copy_ok:
            src = here + os.sep + 'locales'
            dst = path_name + os.sep + 'locales'
            try:
                shutil.copytree(src, dst, symlinks=False, ignore=None)
            except OSError:
                copy_ok = False
        if not copy_ok:
            my_text = 'Unable to copy locales. Installation incomplete'
            tkMessageBox.showinfo(self.my_title, detail=my_text)
            exit(1)

    def do_desktop(self, programs_dir, icons_dir):
        """
        Limited experience of desktop workings!
        If the corresponding directories exist try to put launcher icon
        and command on desktop and in Game menu.
        If applications directory is missing create it.
        path_1 = HOME + '/Desktop'
        path_2 = HOME + '/.local/share/applications'
        """

        text_1 = '[Desktop Entry]\nComment=PZL Games Launcher\nEncoding=UTF-8\nExec=' + Sgg.program + ' ' + programs_dir + '/pzl_launcher.py\nName=pzl\nIcon=' + icons_dir + '/pzl_icon.png\nType=Application\nCategories=Game;\nTerminal=false'

        
        HOME = os.path.expanduser('~')
        path_1 = HOME + '/Desktop'
        path_2 = HOME + '/.local/share/applications'
        if os.path.isdir(path_1):
            path_1 += '/pzl.desktop'
            with open(path_1, "w") as my_file:
                my_file.write(text_1)
            os.chmod(path_1, 0o755)

        self.make_directory(path_2)
        path_2 += '/pzl.desktop'
        with open(path_2, "w") as my_file:
            my_file.write(text_1)
        os.chmod(path_2, 0o755)
        return path_1, path_2

INITIALISE = Sgg()
Sgg.logger.logger.info("Start program")

if __name__ == '__main__':
    try:
        ROOT = tk.Tk()
        ROOT.withdraw()
        APP = Controller(ROOT)
        ROOT.mainloop()
        Sgg.logger.logger.info("Stop program")
    except:
        Sgg.logger.logger.info("Failure!")
        Sgg.logger.logger.exception("Unhandled exception during main")
