#!/usr/bin/env python
# minervaclient: The command-line interface
# This file is from Minervac, a command-line client for Minerva
# <http://npaun.ca/projects/minervac>
# (C) Copyright 2016-2017 Nicholas Paun
# (C) Copyright 2018-2019 Ryan B Au


from minervaclient import reg,sched,exams,transcript,pub_search
from minervaclient.minerva_common import *
from minervaclient import config,credentials_local


import argparse,sys,json
state = {}

def parse_reg(subp):
	parser = subp.add_parser('reg',help='Register for a set of courses')
	parser.add_argument("-t","--term",help="The term (e.g. FALL2016, 201609, etc.) in which to register for these courses",required=True)
        parser.add_argument("-j","--job",help="A unique name. When this argument is given, only registration will only be attempted for remaining courses in the job.\n\nNOTE: It is recommended that you use the -R option with this feature (https://github.com/nicholaspaun/minervaclient/wiki/Registrable-courses-and-jobs). ")
	parser.add_argument("-A","--require-all",help="Only register for courses if all of the requested courses are available. NOTE: Only allowed when course codes are given.",action="store_true")
	parser.add_argument("-R","--require-reg",help="Only register for courses if you can enter the class or the waitlist. NOTE: Only allowed when course codes are given..",action="store_true")
	parser.add_argument("-n","--no-register",help="Don't actually perform registration.",action="store_true")
	parser.add_argument("-P","--public-search",help="[BUGGY] Do not log into Minerva to search !!! This option can only be used to register for the waitlist !!!",action="store_true")
	parser.add_argument("-v", "--verbose", help="Show details about the HTTP requests sent to Minerva",action="store_true")
	parser.add_argument("-q","--quiet",help="[TODO] Only print output for successful registration",action="store_true")
	parser.add_argument('course',nargs='+',help="A series of CRNs (e.g. 814 202) or course codes (POLI-244-001 COMP-251-002), but not both.")
	parser.set_defaults(which='reg')

def parse_sched(subp):
	parser = subp.add_parser('sched',help='Display your course schedule')
	parser.add_argument("-t","--term",help="The term (e.g. FALL2016, 201609, etc.) for which to display the schedule",required=True)
	parser.add_argument("-D","--diff-set",help="[TODO] Monitor the requested report for any changes compared with the previous reports in the diff set")
	parser.add_argument("-r","--report",help="choose which schedule report to display (see config.py to configure")
	parser.add_argument("-l","--long",help="Show a detailed report of the schedule",action="store_true")
	parser.add_argument("-s","--short",help="Show a brief report of the schedule",action="store_true")
	parser.add_argument("-V","--visual",help="Export a visual course timetable",action="store_true")
	parser.add_argument("-C","--calendar",help="Export a calendar for the course schedule (or exam schedule if -E is also given)",action="store_true")
        parser.add_argument("-E","--exams",help="Show the final exam schedule for your courses.",action="store_true")
	parser.add_argument("--conflicts-only",help="Only show course conflicts",action="store_true")
	parser.add_argument("--no-conflicts",help="Don't show course conflicts",action="store_true")
	parser.add_argument("-f","--format",help="[TODO] Choose text format for the displayed report")
	parser.add_argument("-v", "--verbose", help="Show details about the HTTP requests sent to Minerva",action="store_true")
	parser.set_defaults(which='sched')

def parse_transcript(subp):
	parser = subp.add_parser('transcript',help='Display your transcript')
	parser.add_argument("-t","--term",help="The term or terms, separated by commas for which to display the transcript. If no term is specified, records from all terms will be displayed")
	parser.add_argument("-D","--diff-set",help="[TODO] Monitor the requested report for any changes compared with the previous reports in the diff set")
	parser.add_argument("-r","--report",help="Choose which transcript report to display (see config.py to configure")
	parser.add_argument("-l","--long",help="Show a detailed report of the transcript",action="store_true")
	parser.add_argument("-s","--short",help="Show a brief report of the transcript",action="store_true")
	parser.add_argument("-G","--grades",help="Include grades in the report",action="store_true")
	parser.add_argument("-C","--credit",help="Include credit/GPA information in the report",action="store_true")
	parser.add_argument("-S","--summary",help="Include a summary (program, status, etc). in the report",action="store_true")
        parser.add_argument("-P","--header",help="Show the transcript header, which includes personal information and previous education, etc.",action="store_true")
	parser.add_argument("-f","--format",help="[TODO] Choose text format for the displayed report")
	parser.add_argument("-v", "--verbose", help="Show details about the HTTP requests sent to Minerva",action="store_true")
	parser.set_defaults(which='transcript')

def parse_search(subp):
	parser = subp.add_parser('search',help='Search for a course')
	parser.add_argument("-t","--term",help="The term (e.g. FALL2016, 201609, etc.) in which to register for these courses",required=True)
	parser.add_argument("-L", "--lecture-only", help="Show only courses that are Lecture types",action="store_true")
	parser.add_argument("-T", "--tutorial-only", help="Show only courses that are Tutorial types",action="store_true")
	parser.add_argument("-A", "--availability-only", help="Show only availability information",action="store_true")
	parser.add_argument("-v", "--verbose", help="Show details about the HTTP requests sent to Minerva",action="store_true")
	parser.add_argument("-d", "--debug", help="Show details about the HTTP requests sent to Minerva",action="store_true")
	parser.add_argument("-q","--quiet",help="[TODO] Only print output for successful registration",action="store_true")
	parser.add_argument('course',nargs='+',help="A series of full course codes or general course codes (POLI-244-001 COMP-251-002 FACC-100) ")
	parser.set_defaults(which='search')


def main():
	ap = argparse.ArgumentParser()
	subp = ap.add_subparsers(help = 'Minervaclient subcommands')

	parse_reg(subp)
	parse_sched(subp)
	parse_transcript(subp)
	parse_search(subp)

	args = ap.parse_args()


	if args.verbose:
		set_loglevel(True)

	if args.which == 'reg':
		exec_reg(args)
	elif args.which == 'sched':
		exec_sched(args)
	elif args.which == 'transcript':
		exec_transcript(args)
	elif args.which == 'search':
		exec_search(args)

def course_ref_type(arg):
	return arg[0].isalpha()

def get_state_filename():
        import os
        return os.path.dirname(os.path.abspath(sys.argv[0])) + "/state.dat"

def save_state(job,data):
        global state
	f = open(get_state_filename(),"w")
	state[job].extend(data)
	f.write(json.dumps(state))
	f.close()

def restore_state(job,courses):
	global state
	state = json.loads(open(get_state_filename()).read())
	if job in state:
		courses = list(set(courses) - set(state[job]))
                print ">>>",courses,"<<<"
	else:
		state[job] = []

	return courses

def exec_reg(args):
	codes_given = course_ref_type(args.course[0])
	term = get_term_code(args.term)
	
	if credentials_local.always_dry_run:
		args.no_register = True

	if args.job is None:
		args.job = False

	for course in args.course:
		if codes_given != course_ref_type(course):
			print "\033[1;31mERROR:\033[0m Course codes cannot be combined with CRNs"
			sys.exit(MinervaError.user_error)

	
	if args.job:
		courses = restore_state(args.job,args.course)
		if not courses:
			print "\033[1;32m**** Congratulations, you've gotten into all your courses ****\033[1m"
			sys.exit(0)
	else:
		courses = args.course

	if codes_given:
		data = reg.check_register(term,courses,require_all=args.require_all,require_reg=args.require_reg,dry_run=args.no_register,public_search=args.public_search)
	else:

		if args.require_all or args.require_reg:
			print "\033[1;31mERROR:\033[0m When using CRNs, it is not possible to verify the state of classes before attempting registration."
			sys.exit(MinervaError.user_error)
		elif args.public_search:
			print "\033[1;31mERROR:\033[0m This feature is implemented only when searching by course code"
			sys.exit(MinervaErrror.user_error)

		data = reg.fast_register(term,courses,dry_run=args.no_register)

	
	# If we're still here, nothing bad happened, hopefully
	if args.job:
		save_state(args.job,data)

def exec_sched(args):
	term = get_term_code(args.term)
	
	if args.report is not None:
		report = args.report
	elif args.visual:
		report = 'timetable_default'
	elif args.calendar:
                if args.exams:
                    report = 'cal_exams'
                else:
		    report = 'cal_default'
	elif args.conflicts_only:
		report = 'conflicts'
        elif args.exams:
                report = 'exams_default'
	elif args.long:
		report = 'long'
	elif args.short:
		report = 'short'
	else:
		report = 'default'

        if not args.exams:
	    sched.course_details(term,report,visual=args.visual,calendar=args.calendar,conflicts_only=args.conflicts_only,no_conflicts=args.no_conflicts)
        else:
            exams.final_exams(term,report,calendar=args.calendar)


def exec_transcript(args):
	if args.term is None:
		terms = None
	else:
		terms = []
		for term in args.term.split(','):
			terms.append(get_term_code(term))


	if args.report is not None:
		report = args.report
	elif args.long:
		report = 'transcript_long'
	elif args.short:
		report = 'transcript_short'
	else:
		report = 'transcript_default'


	show = ['summary','credit','grades']
	if args.summary or args.grades or args.credit:
		show = []

	if args.summary:
		show.append('summary')
	if args.credit:
		show.append('credit')
	if args.grades:
		show.append('grades')
        if args.header:
                show.append('header')

	transcript.get_transcript(terms,report,show)

def exec_search(args):
	codes_given = course_ref_type(args.course[0])
	term = get_term_code(args.term)
	courses = args.course

	# print courses
	print ""
	cType = ""
	if(args.lecture_only):
		cType = "Lecture"
	elif(args.tutorial_only):
		cType = "Tutorial"
	
	pub_search.print_search(term, courses, cType, avail=args.availability_only, verbose=args.verbose, Debug=args.debug)
	
main()


