#!/opt/anaconda1anaconda2anaconda3/bin/python
# encoding: utf-8
"""The Menpo Deformable Model benchmarking suite

<experiment_config> can be either the name of a predefined experiment, or the
path to a .yaml experiment configuration file.

Usage:
  menpobench run <experiment_config> [--output <dir>] [--overwrite] [--mat] [--force]
  menpobench upload <experiment_config> [--force]
  menpobench list
  menpobench bbox <detector> <pattern> [--synthesize] [--overwrite]
  menpobench test [-v]
  menpobench config <config_key> <config_value>
  menpobench (-h | --help)
  menpobench --version

Options:
  upload             Upload new test results to the Menpo CDN (requires credentials)
  bbox               Generate detector bounding boxes for images
  --output -o <dir>  Output directory [default: ./menpobench_result].
  --overwrite        Any existing output dir will be removed.
  --force            Ignore the Menpo CDN and run the experiment locally.
  --mat              A Matlab .mat file will be saved out for each method.
  -h --help          Show this screen.
  --version          Show version.
"""
import traceback
from docopt import docopt
import menpobench
from menpobench import (invoke_benchmark, configure_cache_dir,
                        configure_matlab_bin_path)
from menpobench.bbox import save_bounding_boxes
from menpobench.config import save_custom_config
from menpobench.utils import centre_str
from menpobench.exception import (ModuleNotFoundError, SchemaError,
                                  MissingMetadataError, MissingConfigKeyError,
                                  MenpoCDNCredentialsMissingError,
                                  OutputDirExistsError)


def invoke_benchmark_with_config_prompts(*args, **kwargs):
    try:
        invoke_benchmark(*args, **kwargs)
    except MissingConfigKeyError as e:
        if e.message == 'cache_dir':
            print('Welcome to menpobench. To start, you will need to choose a directory')
            print('that menpobench can use as a cache.')
            print('This directory will be managed by menpobench to store datasets and')
            print('temporary results. Anticipate it to get quite large (~20GB).')
            cache_dir = raw_input('Please enter cache directory: ')
            configure_cache_dir(cache_dir)
            # now we have a cache dir, re-run
            invoke_benchmark_with_config_prompts(*args, **kwargs)
        elif e.message == 'matlab_bin_path':
            print('One of the methods you are testing requires matlab.')
            print('To use a Matlab method you must have installed and '
                  'configured Matlab correctly.')
            print('menpobench was unable to automatically find the Matlab executable '
                  '- please')
            print('specify the path to the Matlab executable, '
                  "usually found in the 'bin' directory")
            matlab_bin_dir = raw_input('Please enter Matlab executable path: ')
            configure_matlab_bin_path(matlab_bin_dir)
            # now we have a Matlab bin path, re-run
            invoke_benchmark_with_config_prompts(*args, **kwargs)
        else:
            print('Unexpected missing config value: {}'.format(e))
            exit(1)
    except SchemaError as e:
        print('')
        print(centre_str('-- SCHEMA ERROR --'))
        print('')
        print(e)
    except MissingMetadataError as e:
        print('')
        print(centre_str('-- MISSING METADATA --'))
        print('')
        print(e)
    except ModuleNotFoundError as e:
        print('')
        print(centre_str('-- MODULE NOT FOUND --'))
        print('')
        print(e)
    except MenpoCDNCredentialsMissingError as e:
        print('')
        print(centre_str('-- MENPO CDN CREDENTIALS MISSING --'))
        print('')
        print(e)
    except OutputDirExistsError as e:
        print('')
        print(centre_str('-- OUTPUT DIR EXISTS --'))
        print('')
        print(e)
    except Exception:
        print('\n')
        print(centre_str('ERROR', c='!'))
        print(centre_str('-- menpobench has encountered an unrecoverable error --'))
        print(' ')
        print(traceback.format_exc())
    else:
        exit(0)
    print('\nCorrect this issue and try running menpobench again.')
    exit(1)


def list_all_predefined():
    from menpobench.experiment import list_predefined_experiments
    from menpobench.dataset import list_predefined_datasets
    from menpobench.method import (list_predefined_trainable_methods,
                                   list_predefined_untrainable_methods)
    from menpobench.lmprocess import list_predefined_lm_processes
    import yaml
    print(yaml.dump({'datasets': list_predefined_datasets(),
                     'methods': list_predefined_trainable_methods(),
                     'untrainable_methods': list_predefined_untrainable_methods(),
                     'experiments': list_predefined_experiments(),
                     'landmark_processes': list_predefined_lm_processes()
                     }, default_flow_style=False))


def update_config(key, value):
    try:
        save_custom_config({key: value})
    except SchemaError as e:
        print(e)
        print('Due to this, user configuration file was not updated.')
        exit(1)
    else:
        print('Successfully updated {} to {} in config'.format(key, value))


if __name__ == '__main__':
    a = docopt(__doc__,
               version='menpobench v{}'.format(menpobench.__version__))
    if a['list']:
        list_all_predefined()
    elif a['run']:
        invoke_benchmark_with_config_prompts(a['<experiment_config>'],
                                             output_dir=a['--output'],
                                             overwrite=a['--overwrite'],
                                             matlab=a['--mat'],
                                             force=a['--force'])
    elif a['upload']:
        invoke_benchmark_with_config_prompts(a['<experiment_config>'],
                                             upload=True,
                                             force_upload=a['--force'])
    elif a['test']:
        from menpobench.test import run_test_suite
        print(run_test_suite(verbose=a['-v']))
    elif a['config']:
        update_config(a['<config_key>'], a['<config_value>'])
    elif a['bbox']:
        save_bounding_boxes(a['<pattern>'], a['<detector>'],
                            sythesize_problematic=a['--synthesize'],
                            overwrite=a['--overwrite'])
