#!/usr/bin/env python
import curses
import os
import sys
import time
from resources.Interface import Interface
from resources.Menu import Menu
from resources.ConfigureParameterFile import ConfigureParameterFile
from resources.LoadParameterFile import LoadParameterFile

def Commander1Module(stdscr):
    """Main function used to activate the interface.

    All menues are defined here. In addition, functionality not considering
    direct configuration to the parameterfile is defined here.
    """
    UI = Interface(stdscr)
    modules = (Commander1Module, Interface, ConfigureParameterFile,
               LoadParameterFile, Menu)

    bandlist = list(UI.config.band_labels)
    fglist = list(UI.config.fg_labels)
    main_menu = Menu('Main Menu',
                     ['Run Commander', 'Continue From Run',
                      'Configure Parameterfile',
                      'Get Help', '*Save and Exit'],
                     ['Select option:', 'ENTER: select highlighted option'])
    config_menu = Menu('Configure Parameterfile',
                       ['General Settings','Frequency Bands', 'Foregrounds'],
                       ['Select option:', 'ENTER: select highlighted option',
                        'BACKSPACE: return to previous menu',
                        'TAB/SPACE: view/edit parameterfile'],
                       main_menu)
    help_menu = Menu('Get Help',
                      ['Information', 'Code Documentation'],
                      ['Select option:', 'ENTER: select highlighted option',
                       'BACKSPACE: return to previous menu'],
                       main_menu)
    code_menu = Menu('Code Documentation',
                      [module.__name__ for module in modules],
                      ['Select module', 'ENTER: select highlighted option',
                       'BACKSPACE: return to previous menu'],
                      help_menu)
    general_settings_menu = Menu('General Settings',
                                 ['Savefile Name','Chain Directory', '*NSIDE',
                                  '*Toggle Output Frequencies',
                                  '*Toggle Template Fits'],
                                 ['Select option:',
                                  'ENTER: select highlighted option',
                                  'BACKSPACE: return to previous menu',
                                  'TAB/SPACE: view/edit parameterfile'],
                                 config_menu)
    nside_menu = Menu('*NSIDE', [str(2**i) for i in range(6,13)],
                      ['Select NSIDE value:',
                       'ENTER: select highlighted option',
                       'BACKSPACE: return to previous menu',
                       'TAB/SPACE: view/edit parameterfile'],
                      general_settings_menu)
    toggle_menu = Menu('*Toggle Template Fits', bandlist,
                       ['Select band to toggle:',
                        'ENTER: select highlighted option',
                        'BACKSPACE: return to previous menu',
                        'TAB/SPACE: view/edit parameterfile'],
                       general_settings_menu)
    toggle_menu.numbered = False
    output_menu = Menu('*Toggle Output Frequencies', ['.true.', '.false.'],
                       ['select new value:', 'ENTER: select highlighted option',
                       'BACKSPACE: return to previous menu',
                       'TAB/SPACE: view/edit parameterfile'],
                      general_settings_menu)
    frequencyband_menu = Menu('Frequency Bands',
                              ['Add Band', 'Remove Band'],
                              ['Select option:',
                               'ENTER: select highlighted option',
                               'BACKSPACE: return to previous menu',
                               'TAB/SPACE: view/edit parameterfile'],
                              config_menu)
    addband_menu = Menu('Add Band', list(UI.config.masterbands),
                        ['Select a band to add from list of masterbands:',
                         'ENTER: select highlighted option',
                         'BACKSPACE: return to previous menu',
                         'TAB/SPACE: view/edit parameterfile'],
                        frequencyband_menu)
    addband_menu.numbered = False
    removeband_menu = Menu('Remove Band', bandlist,
                           ['Select band to remove:',
                            'ENTER: select highlighted option',
                            'BACKSPACE: return to previous menu',
                            'TAB/SPACE: view/edit parameterfile'],
                           frequencyband_menu)
    removeband_menu.numbered = False
    foreground_menu = Menu('Foregrounds',
                           ['Add Foreground', 'Remove Foreground'],
                           ['Select option:',
                            'ENTER: select highlighted option',
                            'BACKSPACE: return to previous menu',
                            'TAB/SPACE: view/edit parameterfile'],
                           config_menu)
    addfg_menu = Menu('Add Foreground', list(UI.config.masterforegrounds),
                      ['Select a foreground to add:',
                       'ENTER: select highlighted option',
                       'BACKSPACE: return to previous menu',
                       'TAB/SPACE: view/edit parameterfile'],
                      foreground_menu)
    addfg_menu.numbered = False
    removefg_menu = Menu('Remove Foreground', fglist,
                         ['Select foreground to remove:',
                          'ENTER: select highlighted option',
                          'BACKSPACE: return to previous menu',
                          'TAB/SPACE: view/edit parameterfile'],
                         foreground_menu)
    removefg_menu.numbered = False

    next_menu = UI.display_menu(main_menu)
    if next_menu =='*Save and Exit':
        curses.endwin()
        sys.exit()
    elif next_menu == 'Continue From Run':
        try:
            chain_dir, data_dir, tag, sample = UI.get_init_dirs()
            UI.config.update_init_files(chain_dir, data_dir, tag, sample)
        except TypeError:
            pass
        except NameError as e:
            raise e
        next_menu = main_menu
    elif next_menu == 'Run Commander':
        UI.run_commander()
        next_menu = main_menu

    while True:
        previous_menu = next_menu
        next_menu = UI.display_menu(next_menu)
        if not isinstance(next_menu, Menu):
            selected_option_menu_name = previous_menu.name
            selected_option = next_menu
            if selected_option == '*Save and Exit':
                os.chdir(UI.run_path)
                UI.config.write_to_file(UI.savefile)
                if os.path.exists(UI.tempfile):
                    os.remove(UI.tempfile)
                curses.endwin()
                sys.exit()

            elif selected_option_menu_name == '*NSIDE':
                nside = int(selected_option)
                UI.config.update_nside(nside)

            elif selected_option == 'Chain Directory':
                chain_dir = UI.get_user_input(previous_menu,
                            'Input new Chain Directory name:',
                            ['ENTER: confirm/cancel(empty field)'])
                UI.config.update_chains_dir(chain_dir)
                os.chdir(UI.run_path)
                if chain_dir and not os.path.isdir(chain_dir):
                    os.mkdir(chain_dir)
                os.chdir(UI.dir_path)
                next_menu = previous_menu
                continue

            elif selected_option == 'Savefile Name':
                new_paramfile_name = UI.get_user_input(previous_menu,
                                     'Input new parameterfile name:',
                                     ['ENTER: confirm/cancel(empty field)'])
                UI.update_parameterfile_name(new_paramfile_name)
                next_menu = previous_menu
                continue

            elif selected_option_menu_name == '*Toggle Output Frequencies':
                UI.config.toggle_outputs(selected_option)

            elif selected_option_menu_name == '*Toggle Template Fits':
                UI.config.toggle_template_fit(selected_option)

            elif selected_option_menu_name == 'Add Band':
                UI.config.add_band(selected_option)
                removeband_menu.items = list(UI.config.band_labels)
                toggle_menu.items = list(UI.config.band_labels)

            elif selected_option_menu_name == 'Remove Band':
                try:
                    UI.config.delete_band(selected_option)
                except ValueError:
                    curses.beep()
                removeband_menu.items = list(UI.config.band_labels)
                toggle_menu.items = list(UI.config.band_labels)
                next_menu = previous_menu
                continue

            elif selected_option_menu_name == 'Add Foreground':
                UI.config.add_foreground(selected_option)
                removefg_menu.items = list(UI.config.fg_labels)

            elif selected_option_menu_name == 'Remove Foreground':
                UI.config.delete_foreground(selected_option)
                removefg_menu.items = list(UI.config.fg_labels)
                next_menu = previous_menu
                continue

            elif selected_option_menu_name == 'Code Documentation':
                for i, mod in enumerate(modules):
                    if selected_option == mod.__name__:
                        curses.endwin()
                        help(mod)
                        curses.doupdate()
                next_menu = previous_menu
                continue

            elif selected_option == 'Information':
                UI.user_manual()
                next_menu = previous_menu
                continue

            elif selected_option == 'Continue From Run':
                try:
                    chain_dir, data_dir, tag, sample = UI.get_init_dirs()
                    UI.config.update_init_files(chain_dir, data_dir, tag, sample)
                except TypeError:
                    pass
                next_menu = main_menu
                continue

            elif next_menu == 'Run Commander':
                UI.run_commander()
                next_menu = main_menu
                continue

            next_menu = previous_menu.parent
        UI.save(UI.tempfile)

if __name__ == '__main__':
    """Interface loop."""

    arguments = sys.argv
    if len(sys.argv) == 1:
        curses.wrapper(Commander1Module)
    else:
        run_path = os.getcwd()
        dir_path = os.path.dirname(os.path.realpath(__file__))
        commands = {
                    'nside': ['parameterfile', 'new nside'],
                    'removeband': ['parameterfile', 'band to remove'],
                    'addband':['parameterfile', 'band to add'],
                    'removefg':['parameterfile', 'fg to remove'],
                    'addfg':['parameterfile', 'fg to add'],
                    'continue':['parameterfile', 'chain dir','tag', 'sample'],
                    'masterbands':['parameterfile'],
                    'masterfgs':['parameterfile']
                    }
        if sys.argv[1] in ['-h', 'help']:
            dashes_len = 56
            title = 'Commander1 Module Help'
            print(dashes_len*'-')
            print(((dashes_len//2)-len(title)//2)*' '+title)
            print(dashes_len*'-')
            print('Usage:')
            print('    Enter interface by running c1. Start by selecting')
            print('    the parameterfile you wish to work with. Proceed')
            print('    by navigating through the menues to select different')
            print('    methods.\n')

            print('Usage without interface:')
            print('    The different methods can be performed without entering')
            print('    the interface.')
            print('Available Commands:')
            for command in commands:
                print(f'   - {command}', ' '.join([f'[{arg}]' for arg in commands[command]]))
            print('\nFor more help on each command, '
                  'type:\n    c1 -h [command]\n    c1 -help [command]')
            print(dashes_len*'-')
        else:
            if sys.argv[1] == 'nside':
                try:
                    paramfile = sys.argv[2]
                    new_nside = int(sys.argv[3])
                except IndexError:
                    args = ' '.join([f'[{arg}]' for arg in commands['nside']])
                    print(f'Missing arguments. nside arguments are: {args}')
                    sys.exit()
                except ValueError:
                    print(f'Could not convert {sys.argv[3]} to type <int>.')
                    sys.exit()

                if not os.path.isfile(paramfile):
                    print(f'{paramfile} is not a file in current work directory.')
                    sys.exit()

                os.chdir(f'{dir_path}/resources/')
                ConfigParams = ConfigureParameterFile(f'{run_path}/{paramfile}')
                ConfigParams.update_nside(new_nside)
                os.chdir(run_path)
                ConfigParams.write_to_file('param.txt')

            elif sys.argv[1] == 'removeband' or sys.argv[1] == 'addband':
                try:
                    paramfile = sys.argv[2]
                    band = sys.argv[3]
                except IndexError:
                    args = ' '.join([f'[{arg}]' for arg in commands[sys.argv[1]]])
                    print(f'Missing arguments. {sys.argv[1]} arguments are: {args}')
                    sys.exit()

                if not os.path.isfile(paramfile):
                    print(f'{paramfile} is not a file in current work directory.')
                    sys.exit()

                os.chdir(f'{dir_path}/resources/')
                ConfigParams = ConfigureParameterFile(f'{run_path}/{paramfile}')

                if sys.argv[1] == 'removeband':
                    if band not in ConfigParams.band_labels:
                        print(f'Band:{band} is not recognized.')
                        sys.exit()
                    else:
                        ConfigParams.delete_band(band)
                elif sys.argv[1] == 'addband':
                    if band not in ConfigParams.masterbands:
                        print(f'Band:{band} is not recognized.')
                        sys.exit()
                    else:
                        ConfigParams.add_band(band)

                os.chdir(run_path)
                ConfigParams.write_to_file('param.txt')


            elif sys.argv[1] == 'removefg' or sys.argv[1] == 'addfg':
                try:
                    paramfile = sys.argv[2]
                    fg = sys.argv[3]
                except IndexError:
                    args = ' '.join([f'[{arg}]' for arg in commands[sys.argv[1]]])
                    print(f'Missing arguments. {sys.argv[1]} arguments are: {args}')
                    sys.exit()

                if not os.path.isfile(paramfile):
                    print(f'{paramfile} is not a file in current work directory.')
                    sys.exit()

                os.chdir(f'{dir_path}/resources/')
                ConfigParams = ConfigureParameterFile(f'{run_path}/{paramfile}')

                if sys.argv[1] == 'removefg':
                    if fg not in ConfigParams.fg_labels:
                        print(f'Foreground:{fg} is not recognized.')
                        sys.exit()
                    else:
                        ConfigParams.delete_foreground(fg)
                elif sys.argv[1] == 'addfg':
                    if fg not in ConfigParams.masterforegrounds:
                        print(f'Foreground:{fg} is not recognized.')
                        sys.exit()
                    else:
                        ConfigParams.add_foreground(fg)

                os.chdir(run_path)
                ConfigParams.write_to_file('param.txt')

            elif sys.argv[1] == 'continue':
                try:
                    paramfile = sys.argv[2]
                    chain_dir = sys.argv[3]
                    tag = sys.argv[4]
                    sample = int(sys.argv[5])

                except IndexError:
                    args = ' '.join([f'[{arg}]' for arg in commands[sys.argv[1]]])
                    print(f'Missing arguments. {sys.argv[1]} arguments are: {args}')
                    sys.exit()
                except ValueError:
                    print(f'Could not convert {sys.argv[5]} to type <int>.')
                    sys.exit()

                if not os.path.isfile(paramfile):
                    print(f'{paramfile} is not a file in current work directory.')
                    sys.exit()

                if not os.path.isdir(os.path.join(run_path, chain_dir)):
                    print(f'{chain_dir} is not a directory in current work directory.')
                    sys.exit()
                if not os.path.isdir(os.path.join(run_path, 'data')):
                    print(f'data directory is missing in current work directory.')
                    sys.exit()

                os.chdir(f'{dir_path}/resources/')
                ConfigParams = ConfigureParameterFile(f'{run_path}/{paramfile}')
                os.chdir(run_path)
                ConfigParams.update_init_files(chain_dir, f'{run_path}/data', tag, sample)
                ConfigParams.write_to_file('param.txt')

            elif sys.argv[1] == 'masterbands' or sys.argv[1] == 'masterfgs':
                try:
                    paramfile = sys.argv[2]
                except IndexError:
                    args = ' '.join([f'[{arg}]' for arg in commands[sys.argv[1]]])
                    print(f'Missing arguments. {sys.argv[1]} arguments are: {args}')
                    sys.exit()

                if not os.path.isfile(paramfile):
                    print(f'{paramfile} is not a file in current work directory.')
                    sys.exit()

                os.chdir(f'{dir_path}/resources/')
                ConfigParams = ConfigureParameterFile(f'{run_path}/{paramfile}')
                if sys.argv[1] == 'masterbands':
                    for band in ConfigParams.masterbands:
                        print(band)
                elif sys.argv[1] == 'masterfgs':
                    for fg in ConfigParams.masterforegrounds:
                        print(fg)
            else:
                print('Arguments not recognized.')
                sys.exit()

        if sys.argv[1] not in ['masterbands', 'masterfgs', 'help', '-h']:
            print(f"Parameterfile updated. See 'param.txt'.")
