;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; Copyright (c) 1993 By William M. Perry
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; Experimental FORMS processing for html+
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

(require 'w3)

(defvar w3-forms-alist nil
  "An assoc list of forms and the zones associated wiht them")

(defun w3-handle-form (num)
  "Parse a form, expecting the region to be narrowed between the <FORM>
and </FORM> tags"
  (goto-char (point-min))
  (let ((action (progn
		  (if (re-search-forward
		       "<FORM +ACTION=\"\\([^\"]*\\)\">" nil t)
		      (prog1
			  (buffer-substring (match-beginning 1) (match-end 1))
			(goto-char (point-min)))
		    (w3-view-url t))))
	st nd input type name default value checked size maxlength prompt)
    (while (re-search-forward "<INPUT" nil t)
      (setq st (match-beginning 0)
	    nd (progn
		 (goto-char st)
		 (if (re-search-forward ">" nil t)
		     (match-end 0)
		   (progn (end-of-line) (point))))
	    input (buffer-substring st nd))
      (delete-region st nd)
      (if (string-match "TYPE[ \\\t]*=[ \\\t]*\"*\\([^\"]+\\)\"*" input)
	  (setq type (upcase
		      (substring input (match-beginning 1) (match-end 1))))
	(setq type ""))
      (if (string-match "NAME[ \\\t]*=[ \\\t]*\"*\\([^\"]+\\)\"*" input)
	  (setq name (substring input (match-beginning 1) (match-end 1)))
	(setq name ""))
      (if (string-match "VALUE[ \\\t]*=[ \\\t]*\"*\\([^\"]+\\)\"*" input)
	  (setq value (substring input (match-beginning 1) (match-end 1)))
	(setq value ""))
      (if (string-match "SIZE[ \\\t]*=[ \\\t]*\"*\\([^\"]+\\)\"*" input)
	  (setq size (string-to-int
		      (substring input (match-beginning 1) (match-end 1))))
	(setq size 20))
      (if (string-match "MAXLENGTH[ \\\t]*=[ \\\t]*\"*\\([^\"]+\\)\"*" input)
	  (setq maxlength (string-to-int
			   (substring input (match-beginning 1)
				      (match-end 1))))
	(setq maxlength 20))
      (setq default value)
      (if (string-match "CHECKED" input)
	  (setq checked t)
	(setq checked nil))
      (setq prompt
	    (cond
	     ((or (equal type "TEXT")
		  (equal type ""))
	      (format "%s%s" value (make-string (- size (length value)) ?_)))
	     ((equal type "CHECKBOX") (format "[%s]" (if checked "X" " ")))
	     ((equal type "SUBMIT") value)
	     ((equal type "RESET") value)
	     ((equal type "INT") (make-string size ?_))
	     ((equal type "URL") (make-string size ?_))
	     ((equal type "FLOAT") (make-string size ?_))
	     ((equal type "DATE") (make-string size ?_))
	     ((equal type "RADIO") (format "[%s]" (if checked "X" " ")))))
      (goto-char st)
      (insert prompt)
      (w3-add-zone st (point) w3-node-style
		   (list 'w3form
			 action type name default value
			 checked size maxlength num)))))

(defun w3-handle-forms ()
  "Take care of parsing an entire buffer for <FORM> tags"
  (set-buffer " *W3*")
  (let ((num 1))
    (goto-char (point-min))
    (while (re-search-forward "<FORM[^>]*>" nil t)
      (narrow-to-region (match-beginning 0)
			(if (re-search-forward "</FORM>" nil t) (match-end 0)
			  (point-max)))
      (w3-handle-form num)
      (setq num (1+ num))
      (widen))))

(defun w3-do-form-entry (formobj zone)
  "Read in a data entry field defined by FORMOBJ, covered by zone ZONE."
  (let ((actn (nth 1 formobj))
	(type (nth 2 formobj))
	(name (nth 3 formobj))
	(deft (nth 4 formobj))  ;; the default value
	(valu (nth 5 formobj))  ;; the current value
	(chkd (nth 6 formobj))  ;; is it checked?
	(size (nth 7 formobj))
	(maxl (nth 8 formobj))
	(ident (nth 9 formobj))
	(st (w3-zone-start zone))
	(nd (w3-zone-end zone)))	    
    (cond
     ((or (equal "TEXT" type)
	  (equal "" type))
      (setq valu (read-string "Enter text: " valu)))
     ((or (equal "CHECKBOX" type)
	  (equal "RADIO" type)) (setq chkd (not chkd)))
     ((or (equal "FLOAT" type)
	  (equal "INT" type))
      (setq valu (read-string "Enter numeric value: " valu)))
     ((equal "DATE" type)
      (setq valu (read-string "Enter date: " valu)))
     ((equal "URL" type)
      (setq valu (read-string "Enter valid URL: " valu)))
     ((equal "SUBMIT" type) (w3-submit-form ident))
     ((equal "RESET" type) (w3-revert-form ident)))
    (if (not (or (equal "SUBMIT" type)
		 (equal "RESET" type)))
	(progn
	  (if buffer-read-only (toggle-read-only))
	  (if (or (equal "CHECKBOX" type)
		  (equal "RADIO" type))
	      (progn
		(delete-region st nd)
		(insert (format "[%s]" (if chkd "X" " "))))
	    (progn
	      (delete-region st nd)
	      (goto-char st)
	      (if (> (length valu) size) (setq valu (substring valu 0 size)))
	      (insert valu (make-string (- size (length valu)) ?_))))
	  (w3-add-zone st nd w3-node-style
		       (list 'w3form actn type name deft valu chkd
			     size maxl ident))
	  (overlay-put zone 'face w3-node-style)
	  (if (not buffer-read-only) (toggle-read-only))))))	

(defun w3-submit-form (actn)
  "Submit form entry fields matching ACTN as their action identifier"
  (let* ((tmp (overlay-lists))
	 (big (append (car tmp) (cdr tmp)))
	 (data nil)
	 (result nil)
	 (cur nil))
    (message "Scanning for matching entry fields...")
    (while big
      (setq data (overlay-get (car big) 'data)
	    cur (car big)
	    big (cdr big))
      (if (and
	   (eq (nth 0 data) 'w3form)
	   (equal (nth 9 data) actn))
	  (setq result (cons data result))))
    result))  

(defun w3-mouse-entry (e)
  (interactive "e")
  (mouse-set-point e)
  (let* ((zone (car (overlays-at (point))))
	 (data (overlay-get zone 'data)))
    (w3-do-form-entry data zone)))
		

(provide 'w3-forms)
