# Source code of the Ubuntu-it website
# Copyright (C) 2015-2016  Pietro Albini <pietroalbini@ubuntu.com>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published
# by the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.

import os
import shutil

import flask


def enable(func):
    """This decorator will cache the view"""
    func.use_cache = True
    return func


def remove(path, recursive=False):
    """Remove a path from the cache"""
    app = flask.current_app
    path = os.path.join(app.config["CACHE_PATH"], path)

    try:
        if os.path.isdir(path):
            if recursive:
                shutil.rmtree(path)
                return
            path = os.path.join(path, "index.html")
        os.remove(path)
    except IOError:
        # If a file wasn't found, we're ok right?
        pass


def after_request(response):
    """Hook meant to be executed after a request"""
    # Don't do anything if the page hasn't an endpoint
    if flask.request.endpoint is None:
        return response

    app = flask.current_app

    # Get the function for the current app
    func = app.view_functions[flask.request.endpoint]

    # Do nothing if no cache is enabled either for the app
    # or for the endpoint
    if "CACHE_PATH" not in app.config or not hasattr(func, "use_cache"):
        return response
    else:
        cache_path = os.path.realpath(app.config["CACHE_PATH"])

    # Don't cache the page if flashed messages were displayed
    if flask.get_flashed_messages():
        return response

    # Don't cache the page if the user is authenticated
    if "auth_name" in flask.g:
        return response

    url = flask.request.path
    method = flask.request.method
    status = response.status_code
    content = response.get_data(as_text=True)

    # Do dome filtering
    if status != 200 or method != "GET":
        return response

    if url.endswith("/"):
        url += "index.html"
    elif "." not in url:
        url += ".html"

    if url.startswith("/"):
        url = url[1:]  # Remove / at the start

    path = os.path.join(cache_path, url)
    os.makedirs(path.rsplit("/", 1)[0], exist_ok=True)
    with open(path, "w") as f:
        f.write(content)

    return response


def install_cache(app):
    """Install the cache on a specific app"""
    app.after_request(after_request)
