# -*- encoding: utf-8 -*-
from flask import ( request
                  , Response
                  , json
                  , session
                  , render_template
                  , current_app
                  , abort
                  )

from . import blueprint

from utils.json import fmtForCallback
from utils.logger import logSimpleLookups
from i18n.utils import iso_filter

from morphology.utils import tagfilter
from flask.ext.babel import gettext as _
from flask.ext.babel import lazy_gettext

from datetime import timedelta
from flask import make_response, request, current_app
from functools import update_wrapper

from bookmarklet_code import generate_bookmarklet_code


def json_response(data, *args, **kwargs):
    return Response( response=json.dumps(data)
                   , status=200
                   , mimetype="application/json"
                   )


def crossdomain(origin=None, methods=None, headers=None,
                max_age=21600, attach_to_all=True,
                automatic_options=True):
    """ Cross-domain decorator from Flask documentation with some
    modifications. This provides an OPTIONS response containing
    permitted headers and content types.
    """

    if methods is not None:
        methods = ', '.join(sorted(x.upper() for x in methods))
    if headers is not None and not isinstance(headers, basestring):
        headers = ', '.join(x.upper() for x in headers)
    if not isinstance(origin, basestring):
        origin = ', '.join(origin)
    if isinstance(max_age, timedelta):
        max_age = max_age.total_seconds()

    def get_methods():
        if methods is not None:
            return methods

        options_resp = current_app.make_default_options_response()
        return options_resp.headers['allow']

    def decorator(f):
        def wrapped_function(*args, **kwargs):
            if automatic_options and request.method == 'OPTIONS':
                resp = current_app.make_default_options_response()
            else:
                resp = make_response(f(*args, **kwargs))
            if not attach_to_all and request.method != 'OPTIONS':
                return resp

            h = resp.headers

            # origin is '*' here
            h['Access-Control-Allow-Origin'] = origin
            h['Access-Control-Allow-Methods'] = get_methods()
            h['Access-Control-Max-Age'] = str(max_age)
            # NB: Content-Type wasn't set, so I'm doing it here, but
            # also it needs to be in the Access-Control-Allow-Headers.
            h['Content-Type'] = 'application/json'
            if headers is not None:
                h['Access-Control-Allow-Headers'] = headers
            return resp

        f.provide_automatic_options = False
        return update_wrapper(wrapped_function, f)
    return decorator

@crossdomain(origin='*', headers=['Content-Type'])
def lookupWord(from_language, to_language):
    """
    .. http:post:: /lookup/(string:from_language)/(string:to_language)

       Looks up a query in the lexicon. Lookups are lemmatized first,
       but the non-lemmatized input is also checked in the lexicon.

       The lookup string may contain multiple lookups as well, separated
       by `|`, but this needs to be signaled by an additional parameter,
       `multiword`.

       :param from_language: the source language of the lookup
       :param to_language:   the target language to display translations
       :form lookup: the search word.
       :form multiword: (optional) enable multiple lookups, separated by
           `|` in the lookup string.

       :throws Http404: In the event that the language pair does not exist.
       :returns:
           JSON data is returned with the help of the formatter
           :py:class:`lexicon.formatters.SimpleJSON`
    """
    import simplejson

    from lexicon import SimpleJSON

    current_app.limiter.check()

    if (from_language, to_language) not in current_app.config.dictionaries and \
       (from_language, to_language) not in current_app.config.variant_dictionaries:
        abort(404)

    success = False

    if request.method == 'GET':
        # URL parameters
        lookup_key = user_input = request.args.get('lookup', False)
        has_callback            = request.args.get('callback', False)
        pretty                  = request.args.get('pretty', False)

        multiword   = request.args.get('multiword', False)

    elif request.method == 'POST':
        input_json = simplejson.loads(request.data)

        lookup_key = user_input = input_json.get('lookup', False)
        has_callback            = request.args.get('callback', False) or input_json.get('callback', False)
        pretty                  = input_json.get('pretty', False)

        multiword   = input_json.get('multiword', False)
    elif request.method == 'OPTIONS':
        return json_response({})

    if multiword:
        if isinstance(lookup_key, str) or isinstance(lookup_key, unicode):
            lookups = lookup_key.split('|')
        else:
            lookups = lookup_key
            lookup_key = '|'.join(lookup_key)
    else:
        lookups = [lookup_key]

    # Sometimes due to probably weird client-side behavior, the lookup
    # key is set but set to nothing, as such we need to return a
    # response when this happens, but the response is nothing.

    response_data = {
        'result'  : [],
        'tags'    : [],
        'tag_msg' : "",
        'success' : False
    }

    if lookup_key is False or not lookup_key.strip():
        return json_response(response_data)

    mlex = current_app.morpholexicon

    multi_lookups = []
    multi_tags = []

    for lookup in lookups:
        morpholexicon_lookup = mlex.lookup( lookup
                                      , source_lang=from_language
                                      , target_lang=to_language
                                      , split_compounds=True
                                      # , non_compound_only=True
                                      # , no_derivations=True
                                      )

        def filterPOSAndTag(analysis):
            filtered_pos = tagfilter(analysis.pos, from_language, to_language)
            joined = ' '.join(analysis.tag)
            return (analysis.lemma, joined)

        analyses = morpholexicon_lookup.analyses

        tags = map(
            filterPOSAndTag,
            analyses
        )

        if multiword:
            _u_in = lookup
        else:
            _u_in = user_input

        ui_lang = iso_filter(session.get('locale', to_language))
        result = SimpleJSON( morpholexicon_lookup.entries
                           , target_lang=to_language
                           , source_lang=from_language
                           , ui_lang=ui_lang
                           , user_input=_u_in
                           )

        result = result.sorted_by_pos()

        if len(result) > 0:
            success = True

        result_with_input = [{'input': lookup, 'lookups': result}]

        logSimpleLookups( lookup
                        , result_with_input
                        , from_language
                        , to_language
                        )

        multi_lookups.extend(result)
        multi_tags.extend(tags)

    results_with_input = [{'input': lookup_key, 'lookups': multi_lookups}]

    data = json.dumps({ 'result': results_with_input
                      , 'tags': tags
                      , 'tag_msg': _(" is a possible form of ... ")
                      , 'success': success
                      })

    if pretty:
        data = json.dumps( json.loads(data)
                         , sort_keys=True
                         , indent=4
                         , separators=(',', ': ')
                         )

    if has_callback:
        data = '%s(%s)' % (has_callback, data)

    return Response( response=data
                   , status=200
                   , mimetype="application/json"
                   )

def ie8_instrux():
    return render_template('reader_ie8_notice.html')

def ie8_instrux_json():
    # Force template into json response
    has_callback = request.args.get('callback', False)
    r = render_template('reader_ie8_notice.html')

    formatted = fmtForCallback(json.dumps(r), has_callback)
    return Response( response=formatted
                   , status=200
                   , mimetype="application/json"
                   )

def reader_test_page():
    """ This is also tied to a context processer making this item
    visible in the navigational menu if the template is found. """

    return render_template('reader_tests.template')

def reader_update():

    reader_settings = current_app.config.reader_settings

    bkmklt = generate_bookmarklet_code( reader_settings
                                      , request.host
                                      )

    # Force template into json response
    has_callback = request.args.get('callback', False)
    return render_template('reader_update.html', bookmarklet=bkmklt)

def reader_update_json():

    # TODO: api_host and media_host from settings
    reader_settings = current_app.config.reader_settings

    bkmklt = generate_bookmarklet_code( reader_settings
                                      , request.host
                                      )

    # Force template into json response
    has_callback = request.args.get('callback', False)
    r = render_template('reader_update.html', bookmarklet=bkmklt)

    formatted = fmtForCallback(json.dumps(r), has_callback)

    return Response( response=formatted
                   , status=200
                   , mimetype="application/json"
                   )

def fetch_messages(locale):
    from i18n.polib import pofile

    try:
        _pofile = pofile('translations/%s/LC_MESSAGES/messages.po' % locale)
    except:
        _pofile = False

    if _pofile:
        jsentries = filter( lambda x: any(['.js' in a[0] for a in x.occurrences])
                          , list(_pofile)
                          )

        jsentries_dict = dict( [(e.msgid, e.msgstr or False) for e in jsentries] )

    else:
        jsentries_dict = dict()
    override_symbol = current_app.config.reader_settings.get('reader_symbol', False)
    if override_symbol:
        jsentries_dict[u'Á'] = override_symbol

    return jsentries_dict


def bookmarklet_configs():
    """ Compile a JSON response containing dictionary pairs,
    and internationalization strings.
    """

    from flask.ext.babel import get_locale

    NAMES = current_app.config.NAMES
    LOCALISATION_NAMES_BY_LANGUAGE = current_app.config.LOCALISATION_NAMES_BY_LANGUAGE

    has_callback = request.args.get('callback', False)
    sess_lang = request.args.get('language', get_locale())

    translated_messages = fetch_messages(sess_lang)
    print translated_messages

    dictionaries = []

    prepared = []

    pair_groups = current_app.config.pair_definitions_grouped_source_locale()

    new_group = False
    for grouper, group in pair_groups.iteritems():
        for (_from, _to), pair_options in group:
            prepared.append((_from, _to))

            reader_dict_opts = current_app.config.reader_options.get(_from, {})

            if grouper != new_group:
                group = { 'iso': grouper
                        , 'locale_name': unicode(NAMES.get(grouper))
                        , 'self_name': unicode(LOCALISATION_NAMES_BY_LANGUAGE.get(grouper))
                        }
            else:
                group = False

            new_group = grouper

            dictionaries.append(
                { 'from': {'iso': _from, 'name': unicode(NAMES.get(_from))}
                , 'to':   {'iso': _to,   'name': unicode(NAMES.get(_to))}
                , 'uri': "/lookup/%s/%s/" % (_from, _to)
                , 'settings': reader_dict_opts
                , 'group': group
                }
            )

            _has_variant = current_app.config.pair_definitions.get((_from, _to), {}) \
                                             .get('input_variants', False)

            if _has_variant:
                for variant in _has_variant:
                    v_from = variant.get('short_name')
                    variant_dict_opts = current_app.config.reader_options.get(v_from, {})
                    if not (v_from, _to) in prepared:
                        dictionaries.append(
                            { 'from': {'iso': v_from, 'name': "%s (%s)" % (unicode(NAMES.get(_from, _from)), _(variant.get('description', '')))}
                            , 'to':   {'iso': _to,    'name': "%s" % unicode(NAMES.get(_to))}
                            , 'uri': "/lookup/%s/%s/" % (v_from, _to)
                            , 'settings': variant_dict_opts
                            }
                        )
                        prepared.append((v_from, _to))

    data = { 'dictionaries': dictionaries
           , 'localization': translated_messages
           , 'default_language_pair': current_app.config.default_language_pair
           }

    formatted = fmtForCallback(json.dumps(data), has_callback)

    return Response( response=formatted
                   , status=200
                   , mimetype="application/json"
                   )

def bookmarklet():

    reader_settings = current_app.config.reader_settings

    bkmklt = generate_bookmarklet_code( reader_settings
                                      , request.host
                                      )

    return render_template( 'reader.html'
                          , bookmarklet=bkmklt
                          , language_pairs=current_app.config.pair_definitions
                          )
