import hashlib
import xml.etree.ElementTree as ET
from sys import argv

import requests
from bottle import route, request, run, static_file, response

# Configuration
from nerd.nerd import NerdClient

from HistoryFishing import HistoryFishing
from NerdEntitiesWrapper import NerdEntitiesWrapper
from XmlStrategies import GenericItemStrategy, PersonStrategy, LocationStrategy, PeriodStrategy, EventStrategy

geoLocationLocation = "http://api.geonames.org/search"

nerdClient = NerdClient()

strategies = {
    'person': PersonStrategy(),
    'generic': GenericItemStrategy(),
    'location': LocationStrategy(),
    'period': PeriodStrategy(),
    'event': EventStrategy()
}


@route('/info')
def info():
    returnText = "Configuration: \n\t- nerdLocation: " + nerdClient.getNerdLocation() + " \n\t- Geo Location: " + geoLocationLocation

    return returnText


@route('/<filename:path>')
def server_static(filename):
    return static_file(filename, root='webapp')


@route('/geotag', method='POST')
def geotagNerdLocations():
    success = False
    if 'text' not in request.json:
        return {'OK': success}

    text = request.json["text"]

    nerdResponse, statusCode = nerdClient.processText(text)

    if statusCode == 200:
        geoLocations = fetchGeolocation(nerdResponse)
        success = True
    else:
        geoLocations = {'error': statusCode}
        success = False

    return {'OK': success, 'locations': geoLocations}


def fetchGeolocation(nerdResponse):
    geoLocations = []

    if 'entities' in nerdResponse.keys():
        for entity in nerdResponse['entities']:
            if 'type' in entity and entity['type'] == "LOCATION":
                if 'preferredTerm' in entity:
                    placeName = entity['preferredTerm']
                else:
                    placeName = entity['rawName']

                isCountry = checkIfCountry(entity)

                geo = requests.get(geoLocationLocation,
                                   params={'maxRows': 1, 'type': 'json', 'username': 'lfoppiano', 'q': placeName})

                print("GEO gazetteer response for query " + placeName + ": " + str(geo.status_code) + " in " + str(
                    geo.elapsed))

                if geo.status_code == 200:

                    locationResponseJson = geo.json()
                    if 'geonames' in locationResponseJson:
                        geonames = locationResponseJson['geonames']
                        for location in geonames:
                            if 'countryName' in location:
                                countryName = location['countryName']
                            else:
                                countryName = None

                            geoLocations.append(
                                {
                                    'json': location,
                                    'name': location['name'],
                                    'isCountry': isCountry,
                                    'country': countryName,
                                    'coordinates': {
                                        'longitude': location['lng'],
                                        'latitude': location['lat']
                                    }
                                }
                            )
                            success = True
                else:
                    geoLocations[location] = "no location resolved in the Gazetteer";
    return geoLocations


def checkIfCountry(location):
    if 'sense' in location and 'fineSense' in location['sense']:
        if 'country' in location['sense']['fineSense']:
            return True

    return False


def populateTeiHeader(teiHeader, titleText):
    fileDesc = ET.SubElement(teiHeader, 'fileDesc')
    titleStmt = ET.SubElement(fileDesc, 'titleStmt')
    title = ET.SubElement(titleStmt, 'title').text = titleText

    profileDesc = ET.SubElement(teiHeader, 'profileDesc')
    creation = ET.SubElement(profileDesc,
                             'creation').text = "This file has been generated by the HedgeHog.JSON2XML service"


@route('/nerd', method='POST')
def teiBuilderNerd():
    response.headers['Content-Type'] = 'application/xml'
    text = request.json["text"]

    nerdResponse, statusCode = nerdClient.disambiguateText(text)

    if nerdResponse:
        root = ET.Element("TEI")
        teiHeader = ET.SubElement(root, "teiHeader")
        populateTeiHeader(teiHeader, 'Named Entities recognition and disambiguation (NERD), XML-TEI output');
        standOff = ET.SubElement(root, "standOff")
        text = ET.SubElement(root, "text")
        body = ET.SubElement(text, "body")

        tmpText = nerdResponse['text']
        m = hashlib.md5()
        m.update(tmpText.encode('utf-8'))
        textId = m.hexdigest()
        p = ET.SubElement(body, "p", attrib={"xml:id": textId})
        p.text = tmpText

        annotations = {}

        if statusCode == 200:
            if 'entities' in nerdResponse.keys():
                for entity in nerdResponse['entities']:
                    if 'type' in entity:
                        type = str(entity['type']).lower()
                    else:
                        type = 'generic'

                    if type not in annotations.keys():
                        annotations[type] = []

                    if 'wikipediaExternalRef' in entity:
                        entity['wikipediaExternalRef'] = str(entity['wikipediaExternalRef'])
                    annotations[type].append(entity)

        for key in annotations.keys():
            strategy = strategies.get(key)
            if strategy is None:
                strategy = strategies['generic']
            standOff.append(strategy.transform(annotations[key], key, textId))

        string = ET.tostring(root, encoding="utf8", method='xml')

        return string


@route('/processLongSentences', method="POST")
def processLongSentences():
    success = False
    if 'text' not in request.json:
        return {'OK': success}

    text = request.json["text"]

    wrapper = NerdEntitiesWrapper()

    return {'OK': success, 'text': text, 'entities': wrapper.process(text)}


## TODO: rename this crap
@route('/processHistory', method="POST")
def extractSubjectsAndEntities():
    success = False
    if 'text' not in request.json:
        return {'OK': success}

    text = request.json["text"]

    historyFishing = HistoryFishing()

    return {'OK': success, 'text': text, 'entities': historyFishing.process(text)}


if len(argv) == 3:
    port = argv[2]
    host = argv[1]
elif len(argv) == 2:
    port = argv[1]
    host = '0.0.0.0'
else:
    print("Not enough parameters")
    exit(-1)

run(host=host, port=port, debug=True)
