class AddressServer(Application):

    """
    This class is the gunicorn wrapper to serve up bottle.

    Strongly borrowed from:
    http://damianzaremba.co.uk/2012/08/running-a-wsgi-
    app-via-gunicorn-from-python/

    """

    def __init__(self, options={}):
        self.usage = None
        self.callable = None
        self.prog = None
        self.options = options
        self.do_load_config()

        self.setup_cork()

        super(AddressServer, self).__init__()
        self.app = Bottle()
        self.add_routes()
        self.add_middleware()

    def setup_cork(self):
        """Set up cork using environment variables."""

        EMAIL = os.environ.get('EMAIL_SENDER')
        EMAIL_PASS = os.environ.get('EMAIL_PASSWORD')
        self.MONGO_DB = os.environ.get('MONGOHQ_DB')
        self.MONGO_URL = os.environ.get('MONGOHQ_URL')
        mb = MongoDBBackend(self.MONGO_DB, self.MONGO_URL)
        self.loginPlugin = Cork(backend=mb, email_sender=EMAIL,
                                smtp_url='starttls://' + EMAIL + ':' +
                                EMAIL_PASS + '@smtp.gmail.com:587')

    def add_middleware(self):
        """Set up the session middleware."""

        ENCRYPT_KEY = os.environ.get('ENCRYPT_KEY')
        session_opts = {
            'session.cookie_expires': True,
            'session.encrypt_key': ENCRYPT_KEY,
            'session.httponly': True,
            'session.timeout': 3600 * 24,  # 1 day
            'session.type': 'cookie',
            'session.validate_key': True,
        }
        self.app = SessionMiddleware(self.app, session_opts)

    def add_routes(self):
        """Add all the application routes."""

        self.app.route(LOGIN_PATH, 'GET', callback=get_login)
        self.app.route(LOGIN_PATH, 'POST', callback=post_login,
                       apply=self.add_login_plugin)
        self.app.route('/logout', 'GET', callback=logout,
                       apply=self.add_login_plugin)
        self.app.route('/register', 'GET', callback=get_register,
                       apply=self.add_login_plugin)
        self.app.route('/register', 'POST', callback=post_register,
                       apply=self.add_login_plugin)
        self.app.route(VALIDATE_REGISTRATION_PATH + '/<registration_code>',
                       'GET', callback=validate_registration,
                       apply=self.add_login_plugin)
        self.app.route(CHANGE_PASSWORD_PATH + '/<reset_code>', 'GET',
                       callback=get_change_password)
        self.app.route(CHANGE_PASSWORD_PATH, 'POST',
                       callback=post_change_password,
                       apply=self.add_login_plugin)
        self.app.route('/reset_password', 'GET', callback=get_reset_password)
        self.app.route('/reset_password', 'POST', callback=post_reset_password,
                       apply=self.add_login_plugin)
        self.app.route('/', 'GET', callback=index, apply=self.check_login)
        self.app.route('/addresses', 'GET', callback=get_addresses,
                       apply=self.check_login)
        self.app.route('/addresses', 'POST', callback=post_addresses,
                       apply=self.check_login)
        self.app.route('/addresses', 'PUT', callback=put_addresses,
                       apply=self.check_login)
        self.app.route('/addresses/<deleteId>', 'DELETE',
                       callback=delete_addresses, apply=self.check_login)
        self.app.route('/csv', 'GET', callback=csv_export,
                       apply=self.check_login)
        self.app.route('/christmas_card', 'GET',
                       callback=christmas_card_csv_export,
                       apply=self.check_login)
#        self.app.route('/import_csv', 'GET', callback=csv_import,
#                       apply=self.check_login)

        self.app.route('/js/<filename>', 'GET', callback=js_static)
        self.app.route('/css/<filename>', 'GET', callback=css_static)

    def init(self, *args):
        """Add any options passed in to the config.

        :param *args: the arguments of the application
        :returns: config object
        :rtype: dict

        """

        cfg = {}
        for k, v in self.options.items():
            if k.lower() in self.cfg.settings and v is not None:
                cfg[k.lower()] = v
        return cfg

    def load(self):
        """Load and return the bottle app."""

        return self.app

    @hook('before_request')
    def check_login(self, fn):
        """Hook for checking the login before doing logic.

        :param fn: the function to call if the user is logged in
        :returns: the wrapped function
        :rtype: def

        """

        def check_uid(**kwargs):
            self.loginPlugin.require(fail_redirect=LOGIN_PATH)
            kwargs["helper"] = AddressModel(self.MONGO_URL, self.MONGO_DB)
            kwargs["userName"] = self.loginPlugin.current_user.username
            return fn(**kwargs)
        return check_uid

    @hook('before_request')
    def add_login_plugin(self, fn):
        """Hook for adding the plugin information.

        :param fn: the function to pass the plugin
        :returns: the wrapped function
        :rtype: def

        """

        def add_plugin(**kwargs):
            kwargs["loginPlugin"] = self.loginPlugin
            return fn(**kwargs)
        return add_plugin