#!python
##########################################################################
# codePost submission CLI
#
# DATE:    2019-02-12
# AUTHOR:  codePost (team@codepost.io)
# PARAMETERS:
# api_key
# course_name
# course_term
# assignment_name
# students (list of emails)
# files (list of filenames)
#
##########################################################################

# Python 2
from __future__ import print_function

import os
import sys
from yaml import load, dump
from argparse import ArgumentParser, FileType

import codePost_api as cP


class _Color:
    PURPLE = '\033[95m'
    CYAN = '\033[96m'
    DARKCYAN = '\033[36m'
    BLUE = '\033[94m'
    GREEN = '\033[92m'
    YELLOW = '\033[93m'
    RED = '\033[91m'
    BOLD = '\033[1m'
    UNDERLINE = '\033[4m'
    END = '\033[0m'


_TERM_INFO = "{END}[{BOLD}INFO{END}]{END}".format(**_Color.__dict__)
_TERM_ERROR = "{END}[{BOLD}{RED}ERROR{END}]{END}".format(**_Color.__dict__)
_TERM_OK = "{END}[{BOLD}{GREEN}OK{END}]{END}".format(**_Color.__dict__)
_TERM_WARN = "{END}[{BOLD}{BLUE}INFO{END}]{END}".format(**_Color.__dict__)


def _print_err(msg, fatal=None):
    print("{} {}".format(_TERM_ERROR, msg), file=sys.stderr)
    # fatal contains an error number; if non-empty, exit
    if fatal != None:
        sys.exit(fatal)


def _print_warn(msg):
    print("{} {}".format(_TERM_WARN, msg), file=sys.stderr)


def _print_info(msg):
    print("{} {}".format(_TERM_INFO, msg), file=sys.stderr)


def _print_ok(msg):
    print("{} {}".format(_TERM_OK, msg))


try:
    from yaml import CLoader as Loader, CDumper as Dumper
except ImportError:
    from yaml import Loader, Dumper

##########################################################################

# Try to load command line parameters
parser = ArgumentParser()
parser.add_argument('-api_key', help='The API key to authenticate upload')
parser.add_argument(
    '-course_name', help='The name of the course to upload to (e.g. COS126)')
parser.add_argument(
    '-course_period', help='The period of the course to upload to (e.g. S2019)')
parser.add_argument('-assignment_name',
                    help='The name of the assignment to upload to (e.g. Loops)')
parser.add_argument('-students', help='Comma-separated list of student emails')
parser.add_argument('-files', help='Comma-separated list of file paths',
                    nargs='+')
parser.add_argument('--extend', action='store_true',
                    help='If submission already exists, add new files to it and replace old files if the code has changed.')
parser.add_argument('--overwrite', action='store_true',
                    help='If submission already exists, overwrite it.')
args, unknown = parser.parse_known_args()

# Decide if we need to look for YAML config file. We only need to do this if an argument isn't
# specified on the command line
params = vars(args)
print(params)

needToLoadYAML = False
requiredArgs = ['api_key', 'course_name', 'course_period',
                'assignment_name', 'students', 'files']
for key in requiredArgs:
    if params[key] is None:
        needToLoadYAML = True
        break

# Load parameters from YAML file, if we need them
haveAllArgs = True
if needToLoadYAML:
    print('')
    print('*******************************************************')
    print('Configuration')
    print('*******************************************************')
    _print_info('Some arguments missing...looking for codepost-config.yaml')
    try:
        config = load(open('codepost-config.yaml'), Loader=Loader)
        for key in requiredArgs:
            if params[key] is None:
                if key in config.keys():
                    params[key] = config[key]
                    _print_info(
                        'Setting argument: %s from codepost-config' % (key))
                else:
                    _print_err(
                        'Missing argument: %s. Not specified in codepost-config or on the CLI' % (key))
                    haveAllArgs = False

    except IOError:
        _print_warn(
            'Could not find codepost-config.yaml. Please create one or specify all required arguments from the command line.')
        _print_warn(
            'To see all required arguments, run python upload-to-codePost -h')
        haveAllArgs = False

if not haveAllArgs:
    _print_err("Missing some necessary arguments, so aborting.", fatal=10)

print('')
print('*******************************************************')
print('Upload')
print('*******************************************************')

# Separate student list into actual list
studentList = params['students'].split(',')

# Iterate over file list to prepare payload for codePost-upload-utils
#fileNames = params['files'].split(',')
fileNames = params['files']
parsedFiles = []
for fileName in fileNames:
    try:
        code = open(fileName, 'r', encoding='utf-8').read()
        path, extension = os.path.splitext(fileName)
        name = os.path.basename(fileName)

        # Princeton hack
        if ".output.txt" in name:
            name = "TESTS.txt"

        parsedFiles.append(
            {
                'name': name,
                'extension': extension,
                'code': code
            }
        )
    except IOError:
        _print_err("Error reading specified file: %s" % (fileName), fatal=True)


# Set upload mode
modeToUse = cP.UploadModes.CAUTIOUS
if params['overwrite']:
    modeToUse = cP.UploadModes.OVERWRITE
elif params['extend']:
    modeToUse = cP.UploadModes.DIFFSCAN

# call upload_single_submission
try:
    assignmentObj = cP.get_assignment_info_by_name(params['api_key'],
                                                   params['course_name'],
                                                   params['course_period'],
                                                   params['assignment_name'])

    cP.upload_submission(api_key=params['api_key'],
                         assignment=assignmentObj,
                         students=studentList,
                         files=parsedFiles,
                         mode=modeToUse)

    _print_ok("Submission successfully uploaded.")
except RuntimeError as e:
    _print_err(str(e))

print('')
