__all__ = [
    'create_app'
]

ADMINS = [
    'ryan.txanson+nds@gmail.com',
]

import sys, os
import logging
import urllib

from   flask                          import ( Flask
                                             , request
                                             , session
                                             )

# from   werkzeug.contrib.cache         import SimpleCache
from   config                         import Config
from   logging                        import getLogger

from   flask.ext.babel                 import Babel

from cache                            import cache

# Configure user_log
user_log = getLogger("user_log")
useLogFile = logging.FileHandler('user_log.txt')
user_log.addHandler(useLogFile)
user_log.setLevel("INFO")

def jinja_options_and_filters(app):

    from filters import register_filters

    app = register_filters(app)
    app.jinja_env.line_statement_prefix = '#'
    app.jinja_env.add_extension('jinja2.ext.i18n')
    app.jinja_env.add_extension('jinja2.ext.do')
    app.jinja_env.add_extension('jinja2.ext.loopcontrols')

    return app

def register_babel(app):

    babel = Babel(app)
    babel.init_app(app)

    app.babel = babel

    @app.before_request
    def append_session_globals():
        """ Add two-character and three-char session locale to global
        template contexts: session_locale, session_locale_long_iso.
        """

        from i18n.utils import iso_filter
        from socket import gethostname
        from itertools import izip_longest

        loc = get_locale()

        app.jinja_env.globals['session_locale'] = loc
        app.jinja_env.globals['zip'] = zip
        app.jinja_env.globals['izip_longest'] = izip_longest
        app.jinja_env.globals['session_locale_long_iso'] = iso_filter(loc)

    @app.babel.localeselector
    def get_locale():
        """ This function defines the behavior involved in selecting a
        locale. """

        locales = app.config.locales_available

        # Does the locale exist already?
        ses_lang = session.get('locale', None)
        if ses_lang is not None:
            return ses_lang
        else:
            # Is there a default locale specified in config file?
            ses_lang = app.config.default_locale
            if not app.config.default_locale:
                # Guess the locale based on some magic that babel performs
                # on request headers.
                ses_lang = request.accept_languages.best_match(locales)
            # Append to session
            session.locale = ses_lang
            app.jinja_env.globals['session'] = session

        return ses_lang

    return app

def prepare_assets(app):
    """ Prepare asset registries, collect and combine them into several lists.

        Prepare template tags for collecting additional assets along the way.

    """

    # TODO: how to collect additional assets called in templates?

    from flask.ext.assets import Environment, Bundle

    assets = Environment(app)
    app.assets = assets

    # assumes you've npm install uglify
    if not os.path.exists('./node_modules/uglify-js/bin/uglifyjs'):
        print >> sys.stderr, "Couldn't find uglify js: `npm install uglify-js`"
        sys.exit()

    app.assets.config['UGLIFYJS_BIN'] = './node_modules/uglify-js/bin/uglifyjs'
    app.assets.init_app(app)

    proj_css = []
    if app.config.has_project_css:
        proj_css.append(app.config.has_project_css.replace('static/',''))

    # assets
    app.assets.main_js_assets = [
        'js/DSt.js',
        'js/bootstrap-collapse.js',
        'js/bootstrap-dropdown.js',
        'js/standalone-app.js',
        'js/bootstrap-typeahead-fork.js',
        'js/base.js',
        'js/index.js',
        'js/detail.js',
        # TODO: underscore? angular? async_paradigms? 
    ]

    app.assets.main_css_assets = [
        'css/bootstrap.css',
        'css/bootstrap-responsive.css',
        'css/base.css',
        'css/detail.css',
        'css/about.css',
    ] + proj_css

    app.assets.t_css_assets = [
        "bootstra.386/css/bootstrap.css",
        "bootstra.386/css/bootstrap-responsive.css",
        "css/text-tv-base.css",
    ] + proj_css

    app.assets.t_js_assets = [
        "bootstra.386/js/jquery.js",
        "bootstra.386/js/bootstrap-386.js",
    ]

    # mobile nav
    app.assets.nav_menu_css = [
        'navmenu/css/normalize.css',
        'navmenu/css/icons.css',
        'navmenu/css/component.css',
    ]

    # for footer
    app.assets.nav_menu_js = [
        'navmenu/js/modernizr.custom.js',
        'navmenu/js/classie.js',
        'navmenu/js/mlpushmenu.js',
        'navmenu/js/mobile_nav_init.js',
    ]

    app.assets.prepared = False

    # TODO: register separate asset path for inclusion of navmenu stuff
    # TODO: register separate asset path for texttv

    # TODO: this requires preprocessing templates once so the function
    # runs.

    #### @app.context_processor
    #### def register_asset():

    ####     def registerer_js(path):
    ####         if not app.assets.prepared:
    ####             print "add " + path
    ####             app.assets.main_js_assets.append(path)
    ####         return ''

    ####     def registerer_css(path):
    ####         if not app.assets.prepared:
    ####             print "add " + path
    ####             app.assets.main_css_assets.append(path)
    ####         return ''

    ####     return dict(register_js_asset=registerer_js, register_css_asset=registerer_css)

    return app

def register_assets(app):
    """ After all assets have been collected from parsed templates...

      * js/app-compiled-PROJNAME.js
      * js/app-t-compiled-PROJNAME.js
      * js/nav-menu-compiled-PROJNAME.js

      * css/app-compiled-PROJNAME.css
      * css/app-t-compiled-PROJNAME.css
      * css/nav-menu-compiled-PROJNAME.css

    """

    from flask.ext.assets import Environment, Bundle

    # TODO: register output including proj name

    # app.config['ASSETS_DEBUG'] = True

    js_filters = "uglifyjs"
    css_filters = "cssmin"

    PROJ = app.config.short_name

    main_js = Bundle(*app.assets.main_js_assets, filters=js_filters, output="js/app-compiled-%s.js" % PROJ)
    main_css = Bundle(*app.assets.main_css_assets, filters=css_filters, output="css/app-compiled-%s.css" % PROJ)
    app.assets.register('main_js', main_js)
    app.assets.register('main_css', main_css)

    main_t_js = Bundle(*app.assets.t_js_assets, filters=js_filters, output="js/app-t-compiled-%s.js" % PROJ)
    main_t_css = Bundle(*app.assets.t_css_assets, filters=css_filters, output="css/app-t-compiled-%s.css" % PROJ)
    app.assets.register('main_t_js', main_t_js)
    app.assets.register('main_t_css', main_t_css)

    nav_menu_js = Bundle(*app.assets.nav_menu_js, filters=js_filters, output="js/nav-menu-compiled-%s.js" % PROJ)
    nav_menu_css = Bundle(*app.assets.nav_menu_css, filters=css_filters, output="css/nav-menu-compiled-%s.css" % PROJ)
    app.assets.register('nav_menu_js', nav_menu_js)
    app.assets.register('nav_menu_css', nav_menu_css)

    # Trigger this to prevent stuff from being reregistered on each
    # view
    app.assets.prepared = True

    return app


def create_app():
    """ Set up the Flask app, cache, read app configuration file, and
    other things.
    """
    import views
    import configs

    from morpholex import MorphoLexicon

    # TODO: this is called twice sometimes, slowdowns have been reduced,
    # but don't know why yet. Need to check. It only happens on the
    # first POST lookup, however...

    # import inspect
    # curframe = inspect.currentframe()
    # calframe = inspect.getouterframes(curframe, 2)
    # print "caller name", calframe[1]

    app = Flask(__name__,
        static_url_path='/static',)

    app = jinja_options_and_filters(app)
    app.production = False
    app.register_blueprint(views.blueprint)

    app.config['cache'] = cache
    app.config['jinja_env'] = app.jinja_env

    app.config['jinja_env'] = app.jinja_env
    app.config = Config('.', defaults=app.config)
    app.config.from_envvar('NDS_CONFIG')
    app.config.overrides = configs.blueprint.load_language_overrides(app)
    app.config.prepare_lexica()
    app.config.add_optional_routes()

    # Prepare assets before custom templates are read
    app = prepare_assets(app)

    # Register language specific config information
    app.register_blueprint(configs.blueprint)

    # Prepare cache
    cache_path = os.path.join(os.getcwd(), 'tmp/generator_cache/%s/' % app.config.short_name)
    cache.init_app(app, {'CACHE_TYPE': 'filesystem', 'CACHE_DIR': cache_path})

    app.cache = cache

    with app.app_context():
        app.cache.clear()

    app.config['cache'] = cache

    app.morpholexicon = MorphoLexicon(app.config)

    from paradigms import ParadigmConfig

    pc = ParadigmConfig(app)
    app.morpholexicon.paradigms = pc

    ## Read and prepare the templates

    from entry_template_filters import register_template_filters
    from entry_templates import TemplateConfig

    app = register_template_filters(app)
    app.lexicon_templates = TemplateConfig(app, debug=True)

    try:
        with open('secret_key.do.not.check.in', 'r') as F:
            key = F.readlines()[0].strip()
        app.config['SECRET_KEY'] = key
    except IOError:
        print >> sys.stderr, """
        You need to generate a secret key, and store it in a file with the
        following name: secret_key.do.not.check.in """
        sys.exit()

    app = register_babel(app)
    if not app.debug:
        import logging
        from logging.handlers import SMTPHandler
        mail_handler = SMTPHandler('127.0.0.1',
                                   'server-error@gtweb.uit.no',
                                   ADMINS, 'NDS error')
        mail_handler.setLevel(logging.ERROR)
        app.logger.addHandler(mail_handler)
    
    from logging import FileHandler
    from logging.handlers import SMTPHandler
    from socket import gethostname

    if app.debug:
        mail_handler = FileHandler('debug_email_log.txt')
    else:
        _admins = ADMINS + app.config.admins
        mail_handler = SMTPHandler('127.0.0.1',
                                   "server-error@%s" % gethostname(),
                                   ADMINS, "NDS-%s Failed" %  app.config.short_name)
        app.logger.smtp_handler = mail_handler

    # Templates are read, register the assets
    register_assets(app)

    mail_handler.setLevel(logging.ERROR)

    app.logger.addHandler(mail_handler)

    return app
