# Copyright 2015 Google Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""
Sample application that demonstrates how to use the App Engine Memcache API.

For more information, see README.md.
"""

# [START gae_memcache_guestbook_all]
import cgi
import cStringIO
import logging
import urllib

from google.appengine.api import memcache
from google.appengine.api import users
from google.appengine.ext import ndb

import webapp2


class Greeting(ndb.Model):
    """Models an individual Guestbook entry with author, content, and date."""

    author = ndb.StringProperty()
    content = ndb.StringProperty()
    date = ndb.DateTimeProperty(auto_now_add=True)


def guestbook_key(guestbook_name=None):
    """Constructs a Datastore key for a Guestbook entity with guestbook_name"""
    return ndb.Key("Guestbook", guestbook_name or "default_guestbook")


class MainPage(webapp2.RequestHandler):
    def get(self):
        self.response.out.write("<html><body>")
        guestbook_name = self.request.get("guestbook_name")

        greetings = self.get_greetings(guestbook_name)
        stats = memcache.get_stats()

        self.response.write("<b>Cache Hits:{}</b><br>".format(stats["hits"]))
        self.response.write("<b>Cache Misses:{}</b><br><br>".format(stats["misses"]))
        self.response.write(greetings)

        self.response.write(
            """
          <form action="/sign?{}" method="post">
            <div><textarea name="content" rows="3" cols="60"></textarea></div>
            <div><input type="submit" value="Sign Guestbook"></div>
          </form>
          <hr>
          <form>Guestbook name: <input value="{}" name="guestbook_name">
          <input type="submit" value="switch"></form>
        </body>
      </html>""".format(
                urllib.urlencode({"guestbook_name": guestbook_name}),
                cgi.escape(guestbook_name),
            )
        )

    # [START gae_memcache_guestbook_check_memcache]
    def get_greetings(self, guestbook_name):
        """
        get_greetings()
        Checks the cache to see if there are cached greetings.
        If not, call render_greetings and set the cache

        Args:
          guestbook_name: Guestbook entity group key (string).

        Returns:
          A string of HTML containing greetings.
        """
        greetings = memcache.get("{}:greetings".format(guestbook_name))
        if greetings is None:
            greetings = self.render_greetings(guestbook_name)
            try:
                added = memcache.add(
                    "{}:greetings".format(guestbook_name), greetings, 10
                )
                if not added:
                    logging.error("Memcache set failed.")
            except ValueError:
                logging.error("Memcache set failed - data larger than 1MB")
        return greetings
    # [END gae_memcache_guestbook_check_memcache]

    # [START gae_memcache_guestbook_query_datastore]
    def render_greetings(self, guestbook_name):
        """
        render_greetings()
        Queries the database for greetings, iterate through the
        results and create the HTML.

        Args:
          guestbook_name: Guestbook entity group key (string).

        Returns:
          A string of HTML containing greetings
        """
        greetings = ndb.gql(
            "SELECT * "
            "FROM Greeting "
            "WHERE ANCESTOR IS :1 "
            "ORDER BY date DESC LIMIT 10",
            guestbook_key(guestbook_name),
        )
        output = cStringIO.StringIO()
        for greeting in greetings:
            if greeting.author:
                output.write("<b>{}</b> wrote:".format(greeting.author))
            else:
                output.write("An anonymous person wrote:")
            output.write(
                "<blockquote>{}</blockquote>".format(cgi.escape(greeting.content))
            )
        return output.getvalue()
    # [END gae_memcache_guestbook_query_datastore]


class Guestbook(webapp2.RequestHandler):
    def post(self):
        # We set the same parent key on the 'Greeting' to ensure each greeting
        # is in the same entity group. Queries across the single entity group
        # are strongly consistent. However, the write rate to a single entity
        # group is limited to ~1/second.
        guestbook_name = self.request.get("guestbook_name")
        greeting = Greeting(parent=guestbook_key(guestbook_name))

        if users.get_current_user():
            greeting.author = users.get_current_user().nickname()

        greeting.content = self.request.get("content")
        greeting.put()
        memcache.delete("{}:greetings".format(guestbook_name))
        self.redirect("/?" + urllib.urlencode({"guestbook_name": guestbook_name}))


app = webapp2.WSGIApplication([("/", MainPage), ("/sign", Guestbook)], debug=True)

# [END gae_memcache_guestbook_all]
