import os.path
import shutil
import subprocess
import sys

import PySimpleGUI as sg

"""
    Demo - GitHub File Management

    A program that helps manage the demo programs on a local PC.  This is done by copying files from your working folder to a folder that is kept in sync with GitHub.
    It works well when used in conjunction with the GUI version of GitHub.  

    Two folders are shown... 
        * the left side is your local "working copy"
        * the right side is the GitHub folder

    The basic file operations are
        * Copy from working folder to GitHub folder
        * Edit a file in PyCharm
        * Run a file (in either folder)
        * Filter file list
        * Search in files in list

    Additional operations
        * Edit this file in PyCharm
        * Launch GitHub GUI program

    Copyright 2020 PySimpleGUI.org
"""


def get_demo_git_files():
    """
    Get the files in the demo and the GitHub folders
    Returns files as 2 lists

    :return: two lists of files
    :rtype: Tuple[List[str], List[str]]
    """

    demo_path = sg.user_settings_get_entry('-demos folder-', '')
    git_demo_path = sg.user_settings_get_entry('-github folder-', '')

    try:
        git_demo_files = os.listdir(git_demo_path)
    except:
        git_demo_files = []

    try:
        demo_files = os.listdir(demo_path)
    except:
        demo_files = []

    return demo_files, git_demo_files


def find_in_file(string):
    """
    Search through the demo files for a string.
    The case of the string and the file contents are ignored

    :param string: String to search for
    :return: List of files containing the string
    :rtype: List[str]
    """

    demo_path = sg.user_settings_get_entry('-demos folder-')
    demo_files, git_files = get_demo_git_files()
    string = string.lower()
    file_list = []
    for file in demo_files:
        filename = os.path.join(demo_path, file)
        try:
            with open(filename, 'r', encoding="utf8") as f:
                for line in f.readlines():
                    if string in line.lower():
                        file_list.append(file)
                        # print(f'{os.path.basename(file)} -- {line}')
        except Exception as e:
            pass
            # print(e)
    return list(set(file_list))


def settings_window():
    """
    Show the settings window.
    This is where the folder paths and program paths are set.
    Returns True if settings were changed

    :return: True if settings were changed
    :rtype: (bool)
    """

    layout = [[sg.T('Program Settings', font='DEFAIULT 18')],
              [sg.T('Path to Demos', size=(20, 1)), sg.In(sg.user_settings_get_entry('-demos folder-', ''), k='-DEMOS-'), sg.FolderBrowse()],
              [sg.T('Path to GitHub Folder', size=(20, 1)), sg.In(sg.user_settings_get_entry('-github folder-', ''), k='-GITHUB-'), sg.FolderBrowse()],
              [sg.T('Github Program', size=(20, 1)), sg.In(sg.user_settings_get_entry('-GitHub Program-', ''), k='-GITHUB PROGRAM-'), sg.FileBrowse()],
              [sg.T('Editor Program', size=(20, 1)), sg.In(sg.user_settings_get_entry('-Editor Program-', ''), k='-EDITOR PROGRAM-'), sg.FileBrowse()],
              [sg.Combo(sg.theme_list(), sg.user_settings_get_entry('-theme-', None), k='-THEME-')],
              [sg.B('Ok'), sg.B('Cancel')],
              ]

    window = sg.Window('Settings', layout)
    event, values = window.read(close=True)
    if event == 'Ok':
        sg.user_settings_set_entry('-demos folder-', values['-DEMOS-'])
        sg.user_settings_set_entry('-github folder-', values['-GITHUB-'])
        sg.user_settings_set_entry('-GitHub Program-', values['-GITHUB PROGRAM-'])
        sg.user_settings_set_entry('-Editor Program-', values['-EDITOR PROGRAM-'])
        sg.user_settings_set_entry('-theme-', values['-THEME-'])
        return True

    return False


# --------------------------------- Create the window ---------------------------------
def make_window():
    """
    Creates the main window
    :return: The main window object
    :rtype: (Window)
    """

    theme = sg.user_settings_get_entry('-theme-')
    demo_files, git_files = get_demo_git_files()

    sg.theme(theme)
    # First the window layout...2 columns

    find_tooltip = "Find in file\nEnter a string in box to search for string inside of the files.\nFile list will update with list of files string found inside."
    filter_tooltip = "Filter files\nEnter a string in box to narrow down the list of files.\nFile list will update with list of files with string in filename."

    left_col = [
        [sg.Text('Demo Programs', font='Any 20')],
        [sg.Listbox(values=demo_files, select_mode=sg.SELECT_MODE_EXTENDED, size=(40, 20), key='-DEMO LIST-')],
        [sg.Text('Filter:', tooltip=filter_tooltip), sg.Input(size=(25, 1), enable_events=True, key='-FILTER-', tooltip=filter_tooltip)],
        [sg.Button('Run'), sg.Button('Copy'), sg.B('Edit')],
        [sg.Text('Find:', tooltip=find_tooltip), sg.Input(size=(25, 1), enable_events=True, key='-FIND-', tooltip=find_tooltip)],
    ]

    right_col = [
        [sg.Text('GitHub Demo Programs', font='Any 20')],
        [sg.Listbox(values=git_files, select_mode=sg.SELECT_MODE_EXTENDED, size=(40, 20), key='-GIT DEMO LIST-')],
        [sg.Button('Run', key='Run Git Version')],
    ]

    # ----- Full layout -----
    ML_KEY = '-ML-'  # Multline's key

    layout = [[sg.vtop(sg.Column(left_col, element_justification='c')), sg.VSeperator(), sg.vtop(sg.Column(right_col, element_justification='c'))],
              [sg.HorizontalSeparator()],
              [sg.Multiline(size=(90, 10), write_only=True, key=ML_KEY, reroute_stdout=True, echo_stdout_stderr=True)],
              [sg.Combo(sg.user_settings_get_entry('-filenames-', []), default_value=sg.user_settings_get_entry('-last filename-'), size=(65, 1),
                        k='-FILENAME-'), sg.FileBrowse(), sg.B('Clear'), sg.B('Run', k='-RUN INDIVIDUAL-'), sg.B('Edit', k='-EDIT INDIVIDUAL-')],
              [sg.Button('Edit Me (this program)'),
               sg.B('Launch GitHub', button_color=(sg.theme_input_background_color(), sg.theme_input_text_color())),
               sg.Button('Exit'), sg.B('Settings')],
              ]

    # --------------------------------- Create Window ---------------------------------
    window = sg.Window('GitHub Demo Copier', layout, icon=icon)

    sg.cprint_set_output_destination(window, ML_KEY)
    return window


# --------------------------------- Main Program Layout ---------------------------------

def main():
    """
    The main program that contains the event loop.
    It will call the make_window function to create the window.
    """

    demo_path = sg.user_settings_get_entry('-demos folder-', '')
    git_demo_path = sg.user_settings_get_entry('-github folder-', '')
    github_program = sg.user_settings_get_entry('-GitHub Program-', '')
    editor_program = sg.user_settings_get_entry('-Editor Program-', '')
    demo_files, git_files = get_demo_git_files()

    window = make_window()

    while True:
        event, values = window.read()
        if event == sg.WINDOW_CLOSED or event == 'Exit':
            break
        if event == 'Copy':
            confirm = sg.popup_yes_no('Are you sure you want to copy:', *values['-DEMO LIST-'], keep_on_top=True)
            if confirm == 'Yes':
                sg.cprint('Copying....', c='white on red')
                for file in values['-DEMO LIST-']:
                    sg.cprint(f'{os.path.join(demo_path, file)}', text_color='blue')
                    sg.cprint('TO', text_color='red', background_color='white')
                    sg.cprint(f'{os.path.join(git_demo_path, file)}', text_color='green')
                    shutil.copyfile(os.path.join(demo_path, file), os.path.join(git_demo_path, file))
                sg.cprint('Copy complete', background_color='red', text_color='white')
        elif event == 'Edit':
            for file in values['-DEMO LIST-']:
                sg.cprint(f'opening (in PyCharm)', text_color='white', background_color='red', end='')
                sg.cprint(f' {os.path.join(demo_path, file)}', text_color='purple')
                execute_command_subprocess(f'{editor_program}', os.path.join(demo_path, file))
        elif event == 'Run':
            sg.cprint('Running local program....', c='white on green')
            for file in values['-DEMO LIST-']:
                sg.cprint(os.path.join(demo_path, file))
                run_py(os.path.join(demo_path, file))
        elif event == 'Run Git Version':
            sg.cprint('Running GitHub version of program....', c='white on green')
            for file in values['-GIT DEMO LIST-']:
                sg.cprint(os.path.join(git_demo_path, file))
                run_py(os.path.join(git_demo_path, file))
        elif event.startswith('Edit Me'):
            sg.cprint(f'opening using {editor_program}\nThis file - {__file__}', text_color='white', background_color='green', end='')
            execute_command_subprocess(f'{editor_program}', __file__)
        elif event == 'Launch GitHub':
            run(github_program)
        elif event == '-FILTER-':
            new_list = [i for i in demo_files if values['-FILTER-'].lower() in i.lower()]
            window['-DEMO LIST-'].update(values=new_list)
        elif event == '-RUN INDIVIDUAL-':
            sg.user_settings_set_entry('-filenames-', list(set(sg.user_settings_get_entry('-filenames-', []) + [values['-FILENAME-'], ])))
            sg.user_settings_set_entry('-last filename-', values['-FILENAME-'])

            window['-FILENAME-'].update(values=list(set(sg.user_settings_get_entry('-filenames-', []))))
            sg.cprint('Running Individual File...', c='white on purple')
            sg.cprint(values['-FILENAME-'], c='white on red')
            run_py(values['-FILENAME-'])
        elif event == 'Clear':
            sg.user_settings_set_entry('-filenames-', [])
            sg.user_settings_set_entry('-last filename-', '')
            window['-FILENAME-'].update(values=[], value='')
        elif event == '-FIND-':
            file_list = find_in_file(values['-FIND-'])
            window['-DEMO LIST-'].update(values=sorted(file_list))
        elif event == 'Settings':
            if settings_window() is True:
                window.close()
                window = make_window()
                demo_path = sg.user_settings_get_entry('-demos folder-')
                git_demo_path = sg.user_settings_get_entry('-github folder-')
                github_program = sg.user_settings_get_entry('-GitHub Program-')
                editor_program = sg.user_settings_get_entry('-Editor Program-')
                demo_files, git_files = get_demo_git_files()
    window.close()


def run(app_name, parm=''):
    execute_command_subprocess(app_name, parm)


def run_py(pyfile, parms=None):
    if parms is not None:
        execute_command_subprocess('python', pyfile, parms)
    else:
        execute_command_subprocess('python', pyfile)


def execute_command_subprocess(command, *args, wait=False):
    if sys.platform == 'linux':
        arg_string = ''
        for arg in args:
            arg_string += ' ' + str(arg)
        sp = subprocess.Popen(['python3' + arg_string, ], shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    else:
        expanded_args = ' '.join(args)
        sp = subprocess.Popen([command, expanded_args], shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    if wait:
        out, err = sp.communicate()
        if out:
            print(out.decode("utf-8"))
        if err:
            print(err.decode("utf-8"))


if __name__ == '__main__':
    icon = b'[encoded data, 5836 characters]'

    main()

