(in-package :cl-user)

(defpackage :my-blog
  (:use :common-lisp)
)


(in-package :my-blog)
(require :hunchentoot)
(require :html-template)
(require :elephant)
(use-package :elephant)

(defpclass blog-post ()
  ((title :initarg :title
          :accessor title
)

   (body :initarg :body
         :accessor body
)

   (timestamp :initarg :timestamp
              :accessor timestamp
              :initform (get-universal-time)
              :index t
)

   (url-part :initarg :url-part
             :accessor url-part
             :initform nil
             :index t
)
)
)


(defmethod initialize-instance :after ((obj blog-post) &key)
  "If :url-part wasn't non-nil when making the instance, generate it
automatically."

  (cond ((eq nil (url-part obj))
         (setf (url-part obj) (make-url-part (title obj)))
)
)
)


(defun make-url-part (title)
  "Generate a url-part from a title. A url-part should only have
alphanumeric characters or dashes (in place of spaces)."

  (string-downcase
   (delete-if #'(lambda (x) (not (or (alphanumericp x) (char= #\- x))))
              (substitute #\- #\Space title)
)
)
)


(defun generate-index-page ()
  "Generate the index page showing all the blog posts."
  (with-output-to-string (stream)
    (html-template:fill-and-print-template
     #P"index.tmpl"
     (list :blog-posts
           (loop for blog-post in (nreverse (get-instances-by-range
              'blog-post 'timestamp nil nil
)
)

              collect (list :title (title blog-post)
                                                :body (body blog-post)
                                                :url-part (url-part blog-post)
)
)
)

     :stream stream
)
)
)


(defun generate-blog-post-page (template)
  "Generate a page using blog post data."
  (let ((url-part (hunchentoot:query-string)))
    (with-output-to-string (stream) ; Create a stream that will give us a sting
     (let ((blog-post (get-instance-by-value 'blog-post 'url-part url-part))) ; Get the right blog post
       (html-template:fill-and-print-template
         template
         (list :title (title blog-post)
               :body (body blog-post)
               :url-part (url-part blog-post)
)

         :stream stream
)
)
)
)
)


(defun view-blog-post-page ()
  "Generate a page for viewing a blog post."
  (generate-blog-post-page #P"post.tmpl")
)


(defun edit-blog-post ()
  (cond ((eq (hunchentoot:request-method) :GET)
         (generate-blog-post-page #P"post-edit.tmpl")
)

        ((eq (hunchentoot:request-method) :POST)
         (save-blog-post)
)
)
)



(defun save-blog-post ()
  "Read POST data and modify blog post."
  (let ((blog-post
         (get-instance-by-value 'blog-post
                                'url-part (hunchentoot:query-string)
)
)
)

    (setf (title blog-post) (hunchentoot:post-parameter "title"))
    (setf (body blog-post) (hunchentoot:post-parameter "body"))
    (setf (url-part blog-post) (make-url-part (title blog-post)))
    (hunchentoot:redirect (url-part blog-post))
)
)

         

; Set the web server dispatch table
(setq hunchentoot:*dispatch-table*
      (list (hunchentoot:create-regex-dispatcher "^/$" 'generate-index-page)
            (hunchentoot:create-regex-dispatcher "^/view/$"
                                                 'view-blog-post-page
)

            (hunchentoot:create-regex-dispatcher "^/edit/$"
                                                 'edit-blog-post
)
)
)


; Make sure html-template looks for files in the right directory
(setq html-template:*default-template-pathname* #P"/Users/vetler/Documents/devel/cl-webapp-intro/source/")

; Open the store where our data is stored
(defvar *elephant-store* (open-store '(:clsql (:sqlite3 "/tmp/blog.db"))))

; Start the web server
(defvar *ht-server* (hunchentoot:start-server :port 8080))