Add a note to the database.  The title should be short (perhaps 3
        to 7 words).  The keywords are comma-separated, and should be similar
        in style to others in the database.  The content may be of any length. The
        attachments are comma-separated, and must be full pathnames to files 
        that exist.

def add(self, title="", keywords="", content="", attachments="", due="", book=1, privacy=0, date="", modified=""):
        ''' Add a note to the database.  The title should be short (perhaps 3
        to 7 words).  The keywords are comma-separated, and should be similar
        in style to others in the database.  The content may be of any length. The
        attachments are comma-separated, and must be full pathnames to files 
        that exist.'''
        #self.debug = 1
        try:
            known_books = []
            for b in self.cur.execute("SELECT number FROM book;").fetchall():
                known_books.extend(b)
        except:
            self.error("cannot look up list of known books")
        #print("known_books %s" % known_books)
        #print("book %s initially" % book)
        if not book in known_books:
            if book != -1:
                self.warning("the book is not known, so switching to \"Default\"")
            book = 1
        #print("book %s later" % book)
        self.fyi("add with title='%s'" % title)
        self.fyi("add with keywords='%s'" % keywords)
        self.fyi("add with attachments='%s' (comma-separated string)" % attachments)
        self.fyi("add with due='%s'" % due)
        self.fyi("add with book='%s'" % book)
        if not isinstance(due, str):
            due = ""
        due = self.interpret_time(due)[0]
        self.fyi("due: %s" % due)
        now = datetime.datetime.now()
        if date == "":
            date = now.strftime("%Y-%m-%d %H:%M:%S")
        try:
            self.cur.execute("INSERT INTO note(authorId, date, modified, title, content, privacy, due, book) VALUES(?, ?, ?, ?, ?, ?, ?, ?);",
                (self.authorId, date, modified, title, content, 0, due, book))
        except:
            self.error("error adding note to the database")
        noteId = self.cur.lastrowid
        self.fyi("noteId: %s" % noteId)
        hash = self.compute_hash(noteId=noteId, date=date, title=title)
        self.fyi("hash: %s" % hash)
        try:
            self.cur.execute("UPDATE note SET hash=? WHERE noteId=?;", (hash, noteId))
        except:
            self.error("error adding note hash to the database")
        for keyword in keywords:
            self.fyi("  inserting keyword:", keyword)
            keywordId = self.con.execute("SELECT keywordId FROM keyword WHERE keyword = ?;", [keyword]).fetchone()
            if keywordId:
                self.fyi("  (existing keyword with id %s)" % keywordId)
                keywordId = keywordId[0]
            else:
                self.fyi("  (new keyword)")
                self.cur.execute("INSERT INTO keyword(keyword) VALUES (?);", [keyword])
                keywordId = self.cur.lastrowid
            self.con.execute("INSERT INTO notekeyword(noteId, keywordID) VALUES(?, ?)", [noteId, keywordId])
        # Handle attachments, which must be existing files.
        attachments = [key.lstrip().rstrip() for key in attachments.split(',')]
        attachments = filter(None, attachments) # remove blanks
        for attachment in attachments:
            self.fyi("processing attachment '%s'" % attachment)
            if not os.path.isfile(attachment):
                self.warning(" cannot attach file '%s' because it does not exist" % attachment)
            else:
                self.fyi("    '%s' exists" % attachment)
                attachment = os.path.expanduser(attachment)
                afile = open(attachment, "rb")
                try:
                    blob = afile.read()
                    self.fyi("    read file '%s'" % attachment)
                    self.cur.execute('INSERT INTO attachment(filename,contents) VALUES(?,?)', [attachment,buffer(blob)])
                    attachmentId = self.cur.lastrowid
                    self.fyi("    inserted OK; attachmentID=%d" % attachmentId)
                    self.con.commit()
                    self.fyi("    added to attachment table")
                    self.fyi('    try "INSERT INTO note_attachment(noteId, attachmentId) VALUES(%d,%d)"' % (noteId,attachmentId))
                    self.cur.execute('INSERT INTO note_attachment(noteId, attachmentId) VALUES(?,?)', [noteId,attachmentId])
                    self.con.commit()
                    self.fyi("    ... OK")
                except:
                    self.error("Problem storing attachment named '%s'" % attachment)
                finally:
                    afile.close()
                self.fyi(" ... all done, writing attachment")
        self.con.commit()
        self.fyi("add() returning noteId=%d ... is all ok?" % noteId)
        return noteId