(in-package :introspect) 

This form puts us in the namespace of the Introspect package.  

(defapplication intro-app
  :base-url "intro"
  :initial-element intro-packages
  :template-root "systems:imho;example;introspect;templates;"
  :script-root "systems:imho;example;introspect;javascript;")

Creates an imho application with the following features defined as
keyword arguments:

1) base-url: a url which, when requested via http, causes IMHO to
   execute the Introspect application.

2) initial-element: The element that is returned by the application
   at the start of a new session.

3) template-root: The directory in which the application's HTML
   templates are stored.  If an element does not have a render-html
   method defined for it, IMHO will search for a template matching the
   name of that element.  For example, Introspect uses an element
   called 'intro-header' for which there is no render-html method.
   When IMHO tries to render an instance of the intro-header class,
   it first tries to call the render-html method for intro-header.
   Failing that, it will look for the template file in the directory
   specified by the template-root slot.  The template file is then
   parsed, and any IMHO directives contained within it will be
   evaluated and have their elements returned to the client.

4) script-root: The directory in which javascript used by the
   Introspect application resides.

(defun start ()
  "Start the Introspect application."
  (init/application 'intro-app :start))

Initializes Introspect and tells it to start listening for connections
from clients.

(defun stop ()
  "Stop the Introspect application."
  (init/application 'intro-app :stop))

Tells Introspect to stop listening for connections from clients.

(define-wm intro-main ((element t))
  (session-instance 'intro-packages))

A webmethod that returns an instance of the intro-packages element to
the client.  The session-instance function does one of two things: 

1) If the element has already been initialized for the current http
   session, the function returns the instance from the
   session-instances hash of the active session.

2) Otherwise, it creates a new instance of the element and returns it.

(defclass intro-header (html-form)
  ((current-package
    :initarg :package
    :initform nil)))

The intro-header element is an element that inherits from html-form,
a special element that knows how to submit a query to the IMHO server.


(defbindings intro-header
  ((current-package
    :type static-string
    :binding (lambda (package)
	       (if package (package-name package)
		 "None.")))
   (package-list
    :type hyperlink
    :initargs (:value "Package List" :method intro-main))
   (search-string
    :type text-field
    :initargs (:cols 30))
   (submit-button
    :type submit-button)))

(define-wm process-intro-header ((self intro-header))
  (with-element-values (search-string) self
    (let ((pack (find-package search-string)))
      (if pack
	  (session-instance 'intro-single-package
			    :package pack)))))

(defclass intro-packages (html-page)
  )


(defmethod render-html ((element intro-packages) stream)
  (render-html (session-instance 'intro-header) stream)
  (format stream
          "Packages")
  (dolist (package (list-all-packages))
    (with-tag (:stream stream :tag "P")
      (write-string "The " stream)
      (let ((name (package-name package)))
        (imho::with-action (stream element display-package name)
	   (write-string name stream)))
      (write-string "package" stream))))

(defclass intro-single-package (html-page)
  ((package
    :initarg :package)))

(defmethod extern-ref ((sym symbol))
  (format nil "~a::~a" (package-name (symbol-package sym))
	  (symbol-name sym)))

(defmethod intern-ref ((type (eql 'symbol)) symref)
  symref)


(defmethod render-html ((element intro-single-package) stream)
  (with-slots (package)
    element
    (render-html (session-instance 'intro-header
				   :value package) stream)
    (do-external-symbols (sym package)
      (with-tag (:stream stream :tag "P")
	(imho::with-action (stream element display-symbol-page sym)
			   (write-string (symbol-name sym) stream))))))


(define-wm display-symbol-page ((caller t) (sym string))
  (make-instance 'intro-symbol :value (read-from-string sym)))

(define-wm display-package ((element t) (package-name string))
  (let ((page (session-instance 'intro-single-package)))
    (setf (slot-value page 'package) (find-package package-name))
    page))

(defclass intro-symbol (html-page)
  )

(defun display-symbol-value (sym stream)
  (when (boundp sym)
    (html-stream
     stream
     ((:h2)
      (write-string "Symbol Value: " stream))
     ((:p)
      (princ (symbol-value sym) stream)))))

(defun display-symbol-function (sym stream)
  (when (fboundp sym)
    (html-stream
     stream
     ((:h2)
      (write-string "Symbol Function: " stream))
     ((:p)
      (princ (symbol-function sym) stream)))))


(defmethod render-html ((element intro-symbol) stream)
  (let ((sym (element-value element)))
    (html-stream
     stream
     ((:p)
      ((:h1)
       (write-string (extern-ref (element-value element)) stream))
      (:p)
      (display-symbol-value sym stream)
      (:p)
      (display-symbol-function sym stream)))))

