;;; This file builds the Javadoc tags 
(setq javadoc-name "[a-zA-Z_][.a-zA-Z0-9_]*")
(setq javadoc-space "[ \t\n]")
(setq javadoc-method-re 
	  (concat
	   "^\\([ \t]+\\)"
	   "\\(public\\|private\\|static\\|[ \t]+\\)*"
	   "\\(\\(" javadoc-name "\\)" javadoc-space "\\)?"
	   "\\(" javadoc-name "\\)" javadoc-space "*"
	   "(\\([^)]*\\))" javadoc-space "+"
	   "\\(throws" javadoc-space "+\\([^{;]+\\)\\)?"
	   ))
(setq javadoc-args-re 
	  (concat 
	   "\\(" javadoc-name "\\)" 
	   "\\(" javadoc-space "*\\[\\]\\)*"
	   javadoc-space "+"
	   "\\(" javadoc-name "\\)"
	   "\\(" javadoc-space "*\\[\\]\\)*"
	   ))
(setq javadoc-throws-re 
	  (concat 
	   "\\(" javadoc-name "\\)" javadoc-space "*,?"))
(setq javadoc-reserved '("catch" "if" "for" "while"))

(defun javadoc-file ()
  (interactive)
  (goto-char 1)
  (while (javadoc)
	(forward-line)
	))


(defun javadoc ()
  (interactive)
  (string-match "[^.]+" (buffer-name))
  (let ((object (match-string 0 (buffer-name)))
		gotit)
	(while (and (not gotit) (re-search-forward javadoc-method-re nil t))
	  (let* ((pad (match-string 1))
			 (return-type (match-string 4))
			 (name (match-string 5))
			 (args (match-string 6))
			 (throws (match-string 8))
			 (start (match-beginning 0))
			 old loc
			 )
		(when (and (not (equal name "if")) 	; else if (cccc) {
				   (or return-type (equal name object)))
		  (goto-char start)
		  (setq old (javadoc-parse-old-comment))
		  (goto-char start)
		  (insert "\n" pad "/**\n" pad " * " )
		  (setq loc (point))
		  (insert "\n" pad " * \n")
		  (insert (or (nth 1 old) ""))
		  (javadoc-params args pad (nth 2 old))
		  (javadoc-returns return-type pad (nth 3 old))
		  (javadoc-throws throws pad (nth 4 old))
		  (insert pad " */\n")
		  (setq gotit t)
		  (goto-char loc)
		  )))
	gotit
  ))

(defun javadoc-returns (type pad old) 
  (if type
	  (insert pad " * @return " type " " (or old "") "\n")))

(defun javadoc-params (string pad old) 
  (let ((pos 0)
		name comment array)
	(while (string-match javadoc-args-re string pos)
	  (setq name (match-string 3 string)
			comment (or (cdr (assoc name old)) "")
			array (or (match-string 2 string) (match-string 4 string) ""))
	  (insert  pad " * @param " name array " " (match-string 1 string) " " comment "\n")
	  (setq pos (match-end 0)))))

(defun javadoc-throws (string pad old)
  (if string
	  (let ((pos 0)
			name comment)
		(while (string-match javadoc-throws-re string pos)
		  (setq name (match-string 1 string)
				comment (or (cdr (assoc name old)) ""))
		  (insert  pad " * @throws " name " " (match-string 1 string) " " comment "\n")
		  (setq pos (match-end 0))
		  )))
  )

;;; Check for old comments, and include strings if they are there
(defun javadoc-parse-old-comment ()
  (let* ((comment (javadoc-get-old-comment)))
	(when comment 
	  (string-match javadoc-name comment)
	  (let* ((start (match-end 0))
			 (name (match-string 1 comment)))
		(string-match (concat javadoc-space "*\\([^@]*\\)") comment start)
		(list name 
			  (match-string 1 comment)
			  (javadoc-get-tags "return" comment)
			  (javadoc-alist (javadoc-get-tags "param" comment))
			  (javadoc-alist (javadoc-get-tags "throws" comment)))
		))))

(defun javadoc-get-tags (tag comment)
  (let ((start 0)
		(result ())
		)
	(while (string-match (concat "@" tag javadoc-space "+\\([^@]*\\)") comment start)
	  (setq start (match-end 0)
			result (append result (list (match-string 1 comment)))))
	result))

(defun javadoc-get-old-comment ()
  (if (re-search-backward (concat "\\*/" javadoc-space "*\\=") nil t)
	  (let ((end (match-beginning 0)))
		(if (and (re-search-backward "/\\*\\(\\*\\)?" nil t)
				 (match-string 1))
			(buffer-substring (match-end 0) end)))))

(defun javadoc-alist (list) 
  (let ((alist ()))
	(while list 
	  (string-match javadoc-name (car list))
	  (setq alist (append alist 
						  (list (cons (match-string 0 (car list)) 
									  (substring (car list) (match-end 0)))))
			list (cdr list)))
	alist))



