text: """
  Simple web-based list of dated memos kept in a MongoDB database accessed
  with Flask.
  
  @author H. Keith Hamm
  @date: Fall 2015
  
  """
  
  
  import flask
  from flask import render_template
  from flask import request
  from flask import url_for
  
  import json
  import logging
  import uuid
  import CONFIG
  import sys
  
  # Date handling 
  import arrow  # Replacement for datetime, based on moment.js
  import datetime  # But we may still need time
  from dateutil import tz  # For interpreting local times
  
  # Mongo database
  from pymongo import MongoClient
  from bson import ObjectId
  
  
  
  # Globals
  app = flask.Flask(__name__)
  
  try:
      dbclient = MongoClient(CONFIG.MONGO_URL)
      db = dbclient.memos
      collection = db.dated
  except:
      print("Failure opening database. Is Mongo running? Correct password?")
      sys.exit(1)
  
  app.secret_key = str(uuid.uuid4())
  
  
  # Pages
  
  @app.route("/")
  @app.route("/index")
  def index():
      app.logger.debug("Main page entry")
      flask.session['memos'] = get_memos()
      return flask.render_template('index.html')
  
  
  @app.route("/_add_memo")
  def add_memo():
      """
      Insert a memo into the database.
      """
      try:
          date = arrow.get(request.args.get('date', 0, type=str),
                           'YYYY/MM/DD').naive
          text = request.args.get('text', 0, type=str)
  
          record = {"type": "dated_memo",
                    "date": date,
                    "text": text}
          result = collection.insert_one(record)
          record_id = str(result.inserted_id)
  
          message = 'Memo added.'
          worked = True
      except:
          message = 'Memo not added.'
          record_id = ''
          worked = False
  
      return flask.jsonify(message=message, record_id=record_id, result=worked)
  
  
  @app.route("/_remove_memo")
  def remove_memo():
      """
      Delete a memo from the database.
      """
      try:
          object_id = request.args.get('object_id', 0, type=str)
  
          record = {"type": "dated_memo",
                    "_id": ObjectId(object_id)}
          result = collection.delete_one(record)
  
          app.logger.debug('result: ' + str(result.deleted_count))
          message = 'Memo removed.'
          result = True
      except:
          message = 'Memo not removed.'
          result = False
  
      return flask.jsonify(message=message, result=result)
  
  
  @app.errorhandler(404)
  def page_not_found(error):
      app.logger.debug("Page not found")
      return flask.render_template('page_not_found.html',
                                   badurl=request.base_url,
                                   linkback=url_for("index")), 404
  
  
  # Functions used within the templates
  
  @app.template_filter('humanize')
  def humanize_arrow_date(date):
      """
      Date is internal UTC ISO format string.
      Output should be "today", "yesterday", "in 5 days", etc.
      Arrow will try to humanize down to the minute, so we
      need to catch 'today' as a special case. 
      """
      try:
          then = arrow.get(date).to('local')
          now = arrow.utcnow().to('local')
          if then.date() == now.date():
              human = "Today"
          else:
              human = then.humanize(now)
              if human == "in a day":
                  human = "Tomorrow"
      except:
          human = date
      return human
  
  
  @app.template_filter('format')
  def format_arrow_date(date):
  
      return arrow.get(date).format('YYYY/MM/DD')
  
  
  # Functions available to the page code above
  
  def get_memos():
      """
      Returns all memos in the database, in a form that
      can be inserted directly in the 'session' object.
      """
      records = []
      records_dict = {}
      for record in collection.find({"type": "dated_memo"}):
          record['date'] = arrow.get(record['date']).isoformat()
          record['_id'] = str(record['_id'])
          records_dict[format_arrow_date(record['date'])] = record
      for key in sorted(records_dict):
          records.append(records_dict[key])
      return records
  
  
  if __name__ == "__main__":
      # App is created above so that it will
      # exist whether this is 'main' or not
      # (e.g., if we are running in a CGI script)
      app.debug = CONFIG.DEBUG
      app.logger.setLevel(logging.DEBUG)
      # We run on localhost only if debugging,
      # otherwise accessible to world
      if CONFIG.DEBUG:
          # Reachable only from the same computer
          app.run(port=CONFIG.PORT)
      else:
          # Reachable from anywhere 
          app.run(port=CONFIG.PORT, host="0.0.0.0")
  