# this is a slightly modified version of the src/web/faces.py to account for uwsgi import requirements and other changes (see README.md)

import logging, requests, os, weakref

from flask import Flask, jsonify, make_response, request, abort, redirect, send_file
from flask_request_id import RequestID
from web.emotion_gender_processor import EGProcessor
from web import database
from flask import g

dirname = os.path.normpath(os.path.join(os.getcwd(), 'results'))
if not os.path.exists(dirname):
    os.mkdir(dirname)

# logging.basicConfig(filename = os.path.join(dirname, 'debug.log'), level = logging.DEBUG)
logging.basicConfig(filename = os.path.join(dirname, 'error.log'), level = logging.ERROR)

# File removal after processing (match with legal documentation about storage)
class FileCleaner(object):
    def __init__(self):
        self.weak_references = dict()

    def cleanup(self, response, path):
        self.weak_references[weakref.ref(response, self._deleteTask)] = path

    def _deleteTask(self, wref):
        filepath = self.weak_references[wref]
        if filepath:
            logging.debug('Deleting request result: {0}'.format(filepath))
            os.remove(filepath)

def initFlask():
    app = Flask(__name__)
    RequestID(app)
    return app

def getRequestID(request):
    return request.environ.get("FLASK_REQUEST_ID")

app = initFlask()
processor = EGProcessor(dirname = dirname)
cleaner = FileCleaner()

@app.before_request
def before_request():
    g.db = database.connect()

@app.teardown_request
def teardown_request(exc):
	database.close(g.db)

@app.route('/')
def index():
    return redirect("http://stop.capstone.utu.fi", code=302)

@app.route('/api/v<int:version>/classifyImage/', methods=['POST'])
@app.route('/api/v<int:version>/classifyImage/<type>', methods=['POST'])
def upload(version, type = 'mem'):
    response = None
    resultFile = None

    try:
        if int(version) != 1:
            raise Exception('Invalid API version number.')

        if not processor.isValid():
            abort(503)

        stopCode = request.args.get('stop_code', default = None, type = str)
        if stopCode == None:
            stopCode = request.form.get('stop_code', default = 'unknown', type = str)
        detectEmotion = request.args.get('detect_emotion', default = None, type = int)
        if detectEmotion == None:
            detectEmotion = request.form.get('detect_emotion', default = 0, type = int)

        result = processor.processImage(request.files['image'].read(), result_fname = getRequestID(request), type = type, detect_emotion = detectEmotion != 0)

        # VH Insert result into database
        database.addStats(result, stopCode)

        # by default avoid all disk I/O by using the result held in memory, explicit type argument will still roundtrip to disk
        # NOTE: the ordering in json results is not stable (python dictionaries are unordered)
        if type == 'mem':
            response = jsonify(result)
            response.headers.extend({'Cache-Control': 'no-cache', 'Expires': '0'})
            return response

        if type == 'png':
            resultFile = os.path.join(dirname, getRequestID(request) + '.png')
            response = send_file(resultFile, mimetype='image/png')

        if type == 'json':
            resultFile = os.path.join(dirname, getRequestID(request) + '.json')
            response = send_file(resultFile, mimetype='application/json')

        if response == None:
            raise Exception('Unsupported type requested.')
        
        cleaner.cleanup(response, resultFile)
        # require clients to explicitly handle caching results, HTTP caches are unpredictable
        response.headers.extend({'Cache-Control': 'no-cache', 'Expires': '0'})
        
        return response
    except Exception as err:
        logging.error('An error has occurred whilst processing the file: "{0}", from: {1}'.format(err, stopCode))
        if resultFile and os.path.isfile(resultFile):
            os.remove(resultFile)

        abort(400)

@app.route('/api/v<int:version>/classifyImage/', methods=['GET'])
@app.route('/api/v<int:version>/classifyImage/<type>', methods=['GET'])
def dowload(version, type = 'mem'):
    response = None
    resultFile = None

    try:
        if int(version) != 1:
            raise Exception('Invalid API version number.')

        uri = request.args.get('uri', default = '', type = str)
        if uri == '':
            raise Exception('No URI for image provided.')

        if not processor.isValid():
            abort(503)

        stopCode = request.args.get('stop_code', default = 'unknown', type = str)
        detectEmotion = request.args.get('detect_emotion', default = 0, type = int)
        result = processor.processImage(requests.get(uri).content, result_fname = getRequestID(request), type = type, detect_emotion = detectEmotion != 0)

        # VH Insert result into database
        database.addStats(result, stopCode)

        # by default avoid all disk I/O by using the result held in memory, explicit type argument will still roundtrip to disk
        # NOTE: the ordering in json results is not stable (python dictionaries are unordered)
        if type == 'mem':
            response = jsonify(result)
            response.headers.extend({'Cache-Control': 'no-cache', 'Expires': '0'})
            return response

        if type == 'png':
            resultFile = os.path.join(dirname, getRequestID(request) + '.png')
            response = send_file(resultFile, mimetype='image/png')

        if type == 'json':
            resultFile = os.path.join(dirname, getRequestID(request) + '.json')
            response = send_file(resultFile, mimetype='application/json')

        if response == None:
            raise Exception('Unsupported type requested.')

        cleaner.cleanup(response, resultFile)
        # require clients to explicitly handle caching results, HTTP caches are unpredictable
        response.headers.extend({'Cache-Control': 'no-cache', 'Expires': '0'})

        return response
    except Exception as err:
        logging.error('An error has occurred whilst processing the file: "{0}", from: {1}'.format(err, stopCode))
        if resultFile and os.path.isfile(resultFile):
            os.remove(resultFile)

        abort(400)

@app.errorhandler(400)
def bad_request(error):
    return make_response(jsonify({'error': 'We cannot process the file sent in the request.'}), 400, {'Cache-Control': 'no-cache', 'Expires': '0'})

@app.errorhandler(404)
def not_found(error):
    return make_response(jsonify({'error': 'Resource no found.'}), 404, {'Cache-Control': 'no-cache', 'Expires': '0'})

@app.errorhandler(503)
def server_error(error):
    logging.error('Internal server error: "{0}"'.format(error))
    return make_response(jsonify({'error': 'Service unavailable.'}), 503, {'Cache-Control': 'no-cache', 'Expires': '0'})
