from flask import Flask,request,redirect, json, render_template, url_for
import os, sys, random
import util_functions as util
import mailEvent as mail
from datetime import datetime
from googleEvent import addEvent, createSchedule
from flask_cors import cross_origin
from threading import Timer
import logging
import test

# Constants
app = Flask(__name__)
baseURL = '/home/ubuntu/testing/'
days = ['MO','TU','WE','TH','FR']
config = json.load(open('config/config.json'))
rooms = config['rooms']
classes = config['classes']
times = config['times']
profs = [row.strip('\n') for row in open('config/names.txt')]
logging.basicConfig(format='%(message)s', filename=baseURL + 'errors.log')
l = logging.getLogger('log')

@app.route('/getClasses', methods=['POST'])
@cross_origin()
def getClasses():
    #print request.data
    data = json.load(open('config/prof-schedule.json'))
    prof = request.data.lower()
    classes = data[prof].keys()
    return json.jsonify( {"classes": classes} )

@app.route('/config')
@cross_origin()
def sendConfig():
    global profs
    params = {'profs': profs}
    return json.jsonify(params)

# Intercept incoming request
@app.route('/',methods=['GET','POST'])
@cross_origin()
def shopping_cart():
    data = request.data
    #print data
    if data.find(' Physics Department') >= 0:
        demo = util.extractDemo(data)
        prof = util.extractProf(data)
        code = util.extractCode(data)
        start, end, date = util.extractDate(data,prof,code)
        room = util.extractRoom(prof,code)
    #print ("Demo:  " + demo)
    #print ("Name:  " + prof)
    #print ("Date:  " + date)
    #print ("Code:  " + code)
    #print ("Start:  "+ start)
    #print ("End:  "  + end)
    #print ("\n\n\n")
    try:
        data_handler(demo, prof, room+'  '+code,code, start, end, date)
        return 'Good'
    except Exception as e:
        #print "Error:   ", e
        l.error(e)
        return 'Bad'
    return 'All good'

def data_handler(demo, prof, room, code, start, end,date):
    # Setup path variables
    pathToFile = baseURL + 'demorequests/' + prof.lower() + '/' + date + '.txt'
    demos = ""
    # If professor's directory doesn't exist, make it
    # Needed else python IOError thrown
    if not os.path.exists('demorequests/' + prof):
        os.system('mkdir demorequests/' + prof)
    # Open the [date].txt file and record demo
    with open(pathToFile,'a+') as f:
        f.write(demo + '\n')
    with open(pathToFile) as f:
        for row in f:
            demos += row.replace('\n',', ')
    isAstroClass = code[0] == 'A'
    addEvent(prof.capitalize(),room,date,demos,start,end,isAstroClass)
    return

############# Stupid nginx required functions
# These methods are used to help nginx update files
# Without them, nginx will not correctly update 
def getProfs():
    return [row.strip('\n') for row in open('config/names.txt')]
    
def getConfig():
    return json.load(open('config/config.json'))

def getRooms():
    config = getConfig()
    return config['rooms']

def getTimes():
    config = getConfig()
    return config['times']

def getClasses():
    config = getConfig()
    return config['classes']
############ End stupid nginx required functions

@app.route('/updateProfList',methods=['GET','POST'])
def updateProfList():
    #global times, profs
    profs = getProfs()
    rooms = getRooms()
    times = getTimes()
    config = getConfig()
    rooms = config['rooms']
    classes = config['classes']
    times = config['times']
    profs.sort()
    # Format classes for user in format:
    # [class] [Prof] [start]-[end] [room]
    active_classes = json.load(open('config/prof-schedule.json'))
    for prof in active_classes:
        for c in active_classes[prof]:
            temp = active_classes[prof][c]
            start = temp['start'][0] + ':' + temp['start'][1]
            end   = temp['end'][0] + ':' + temp['end'][1]
            active_classes[prof][c]['days'] = util.clean_days(temp['days'])
            # Clean up days, convert mil time to AM/PM times
            active_classes[prof][c]["start"]= util.milTimeConv(start,'none',to_mil=False)
            active_classes[prof][c]["end"]= util.milTimeConv(end,'none',to_mil=False)
    # profs = list of professors that have classes
    # days = list of days in 2 letter format (i.e.: MO, TU, etc.)
    # times = list of active times (xx:yy-zz:aa AM/PM format)
    # classes = List of possible classes (P131, A100, etc.(
    # active = the prof-schedule.json file with some cleaning
    #       start/end in xx:yy format, days in normal format
    try:
        return render_template("edit_prof_list.html",profs=profs,
                           days=days,times=times,
                           classes=classes,rooms=rooms,
                           active=active_classes)
    except Exception as e:
        l.error(e)

@app.route('/removeProf', methods=['POST'])
def removeProf():
    global profs
    profs = getProfs()
    prof = request.form['prof']
    to_remove = profs.index(prof)
    profs.pop(to_remove)
    updateProfessors()
    return redirect('/updateProfList')

@app.route('/addProf',methods=['POST'])
def addProf():
    global profs
    profs = getProfs()
    prof = request.form['professor'].capitalize()
    profs += [prof]
    updateProfessors()
    return redirect('/updateProfList')

def updateProfessors():
    global profs
    with open('config/names.txt','w') as f:
        f.write( "\n".join(profs) )
    profs = getProfs()
    return

@app.route('/removeSchedule',methods=['POST'])
def removeSchedule():
    data = json.loads(request.form['data']) #data = { [prof name] : list([class names]) }
    json_data = json.load(open('config/prof-schedule.json'))
    for prof in data: # For every request, remove from prof-schedule.json
        for c in data[prof]:
            json_data[prof].pop(c,None)
            if len(json_data[prof]) == 0:# If prof has no classes, pop
                json_data.pop(prof)
    json.dump(json_data,open('config/prof-schedule.json','w'))
    return updateProfList()

@app.route('/addSchedule',methods=['POST'])
def addSchedule():
    global days
    data = request.form
    keys = data.keys()
    # Runs down all keys until only days are left
    c    = data[keys.pop(keys.index('class'))]
    room = data[keys.pop(keys.index('room'))]
    time = data[keys.pop(keys.index('time'))]
    prof = data[keys.pop(keys.index('prof'))].lower()
    sect = data[keys.pop(keys.index('section'))]
    # Sort keys by weekday and set that list to day
    d = sorted(keys,key=days.index)
    hyphen_pos = time.find('-')
    meridian = time[-2:]
    start = time[:hyphen_pos]
    start = util.milTimeConv(start,meridian)
    end = time[hyphen_pos+1:-3]
    end = util.milTimeConv(end,meridian)
    data = json.load(open('config/prof-schedule.json'))
    if sect != "":
        c += '-' + sect
    try:
        data[prof][c] = {"start": start, "end": end, "room": room,"days":d}
    except KeyError:
        data[prof] = {c: {"start":start,"end":end,"room":room,"days":d}}
    json.dump(data,open('config/prof-schedule.json','w'))
    return redirect('/updateProfList')

@app.route('/editSchedule', methods=['POST'])
def editShedule():
    data = dict(request.form)
    #print data
    sched = json.load(open('config/prof-schedule.json'))
    original = data.pop('to_edit')[0].split()
    keys = data.keys()
    c = original[0]
    prof = original[1].lower()
    time = original[2]
    days = []
    room = original[4]+" "+original[5]
    # Days
    for key in keys:
        if data[key][0] == 'on':
            days += [key]
    if len(days) == 0:
        days = original[3]
    sched[prof][c]['days'] = days
    # Fix time
    if 'time' in keys:
        time = data['time'][0]
        hyphen_pos = time.find('-')
        starting_time = time[:hyphen_pos]
        ending_time   = time[hyphen_pos+1:-3]
        meridian = time[-3:]
        start = util.milTimeConv(starting_time, meridian)
        end   = util.milTimeConv(ending_time, meridian)
        sched[prof][c]['start'] = start
        sched[prof][c]['end']   = end
    if 'room' in keys:
        sched[prof][c]['room'] = data['room'][0]
    if 'class' in keys:
        popped = sched[prof].pop(c)
        c = data['class'][0]
        sched[prof][c] = popped
    if 'prof' in keys:
        to_add = sched[prof].pop(c)
        prof_ = data['prof'][0].lower()
        try:
            sched[prof_][c] = to_add
        except KeyError:
            sched[prof_] = {c:to_add}
    if len(sched[prof]) == 0:
        sched.pop(prof)
    json.dump(sched, open('config/prof-schedule.json','w'))
    return redirect("/updateProfList")

@app.route('/purgeSchedule',methods=['POST'])
def purgeSchedule():
    json.dump({},open('config/prof-schedule.json','w'))
    return redirect('/updateProfList')

@app.route('/addRoom', methods=['POST'])
def addRoom():
    global rooms,config
    room = request.form['room']
    try:
        rooms.index(room)
        return redirect('/updateProfList')
    except ValueError:
        rooms.append(room)
        config['rooms'] = rooms
        json.dump(config,open('config/config.json','w+'))
    return redirect('/updateProfList')

@app.route('/removeRoom',methods=['POST'])
def removeRoom():
    global rooms,config
    room = request.form['room']
    rooms.remove(room)
    config['rooms'] = rooms
    json.dump(config,open('config/config.json','w+'))
    return redirect('/updateProfList')

@app.route('/addClass', methods=['POST'])
def addClass():
    global classes,config
    c = request.form['class']
    try:
        classes.index(c)
        return redirect('/updateProfList')
    except ValueError:
        classes.append(c)
        config['classes'] = classes
        json.dump(config,open('config/config.json','w+'))
    return redirect('/updateProfList')

@app.route('/removeClass',methods=['POST'])
def removeClass():
    global classes,config
    c = request.form['class']
    classes.remove(c)
    config['classes'] = classes
    json.dump(config,open('config/config.json','w+'))
    return redirect('/updateProfList')

@app.route('/addTime',methods=['POST'])
def addTime():
    global times, config
    data = request.form
    sHour = data['start_hour']
    sMin  = data['start_min']
    eHour = data['end_hour']
    eMin  = data['end_min']
    meridian = data['meridian']
    timeSort(sHour,sMin,eHour,eMin,meridian) # Adds new time in sorted slot
    config['times'] = times
    json.dump(config,open('config/config.json','w'))
    return redirect('/updateProfList')

def timeSort(sHour,sMin,eHour,eMin,meridian):
    global times
    start = sHour + ':' + sMin
    end = eHour + ':' + eMin
    temp = util.milTimeConv(start, meridian)
    cleaned_start = util.time_from_list(temp)
    updated_times = []
    to_add = util.formatTime(start,True)+'-'+util.formatTime(end,True)+' '+meridian

    for time in times:# Assume time to add > times element
        to_check = time[:time.find('-')]
        t = util.time_from_list(util.milTimeConv(to_check,time[-2:]))
        if cleaned_start < t: # Check if the starting time < the times element starting time
            i = times.index(time)
            updated_times += times[:i] + [to_add] + times[i:]
            times = updated_times
            return
    # If time to add > all elements in times, append it
    times += [to_add]
    return
            

@app.route('/removeTime',methods=['POST'])
def removeTime():
    global times,config
    data = request.form['time']
    times.remove(data)
    config['times']=times
    json.dump(config,open('config/config.json','w'))
    return redirect('/updateProfList')

def datePadding(date):
    if len(date) < 2:
        return '0'+date
    return date

@app.route('/addGoogleSched',methods=['POST'])
def addGoogleSched():
    data = request.form
    start = str(data['starting'][5:])
    end = str(data['ending'][5:])
    #print start, end
    createSchedule(start,end)
    return redirect("https://calendar.google.com")

def beginReportTimer():
    today = datetime.now()
    future_may = datetime(today.year, 2, 8, 17, 30, 0)
    future_dec = datetime(today.year, 2, 8, 15, 33, 0)
    diff_may = abs(today - future_may).total_seconds()
    diff_dec = abs(today - future_dec).total_seconds()
    if diff_may < diff_dec:
        t = Timer(diff_may, timerHandler)
    else:
        t = Timer(diff_dec, timerHandler)
    l.error('Starting TIMER')
    print "Starting"
    t.start()

def date_from_file_string(file_string):
    return file_string[:file_string.find('.')]

def generateReport():
    to_write = 'Report:\n\r\n\r'
    for root, dirs, files in os.walk(baseURL + 'demorequests'):
        for d in dirs:
            for root2, dirs2, files2 in os.walk(os.path.join(baseURL, 'demorequests',  d)):
                for f in files2:
                    end = f.find('.')
                    demo_date = datetime.strptime(f[:end],'%Y-%m-%d')
                    with open(os.path.join(root2,f)) as f1:
                        to_write += str(demo_date.date()) + '\n\r'
                        for row in f1:
                            to_write += '-' + row + '\n\r'
                        to_write += '\n\r'
    with open(os.path.join(baseURL,'demorequests','report.csv'),'w') as f:
        f.write(to_write)
    return
                    
def timerHandler():
    print "Starting time handler"
    email = mail.Email()
    msg = email.create_attachment_message('demorequests/report.csv')
    email.SendMessage(msg)
    beginReportTimer()
    
if __name__ == '__main__':
    #beginReportTimer()
    app.run(host='0.0.0.0',port=8888)
