;;; cbrow.el --- A C++ class browser

;; Copyright (C) 2006-2011 Davin Pearson

;; Author/Maintainer: m4_davin_pearson
;; Keywords: C++ Code Browser
;; Version: 1.0

;;; Commentary:

;; This file is not part of GNU Emacs.

;; Pressing f5 inside a method of a source file (e.g. *.cpp or *.cc)
;; takes you to corresponding line for that function in the the header
;; file for that class (e.g. *.hh) Pressing enter at this point takes
;; you back to the source file. Otherwise pressing f5 takes you to a
;; summary list of all the classes in your program. At this point,
;; pressing enter takes you back to the class browswer.  See the
;; following Website for a diagram that clarifies this text:
;;
;; To use this code, you will need to customise the function
;; cbrow--init and the variable cbrow--footer which can be both found
;; at the end of cbrow.el.

;;; m4_limitation_of_warranty

;;; m4_install_instructions(cbrow)

;;; Known Bugs:

;; None so far!

;;; Code:

(setq cbrow--buffer-name "*Class Browser*")
(setq cbrow--buffer      nil)

;;; debugging functions...

(global-set-key [kp-enter] (function (lambda () (interactive)
                                       (message "cbrow--inside-method=%s"
                                                (cbrow--inside-method)))))

(global-set-key [kp-enter] (function (lambda () (interactive)
                                       (message "cbrow--inside-class=%s"
                                                (cbrow--inside-class)))))

;;(cbrow--inside-namespace-p1-and-p2)
(defun cbrow--inside-namespace-p1-and-p2 ()
  (save-match-data
    (save-excursion
      (let (orig squiggly result)
        (setq orig (point))
        (setq result (cons nil nil))
        (when (re-search-backward "^{" nil t)
          (setq squiggly (point))
          (forward-line -1)
          (beginning-of-line)
          (when (looking-at "^namespace _*[a-zA-Z][a-zA-Z0-9_]*[ \t]*$")
            (goto-char squiggly)
            ;;(debug "Apple")
            (forward-sexp 1)
            (if (< orig (point))
                (setq result (cons squiggly (point))))))
        (if (not (car result)) (setcar result (point-min)))
        (if (not (cdr result)) (setcdr result (point-max)))
        result
        ))))

;;(cbrow--inside-class-p1-and-p2)
(defun cbrow--inside-class-p1-and-p2 ()
  (save-match-data
    (save-excursion
      (let (orig squiggly result)
        (setq result (cons nil nil))
        (setq orig (point))
        ;; BEGIN COND!
        (cond
         ((save-excursion
            (beginning-of-line)
            (looking-at (if *namespace* "^[ ][ ][ ]{" "^{")))
          (setq squiggly (point))
          (forward-sexp 1)
          (when (< orig (point))
            (setq result (cons squiggly (point)))))
         ((save-excursion
            (beginning-of-line)
            (when (looking-at (concat
                               (if *namespace* "^[ ][ ][ ]" "^")
                               "\\([A-Z]+ \\)*class \\(_*[a-zA-Z][a-zA-Z0-9_]*\\)"))
              (forward-line 1)
              (looking-at (if *namespace* "^[ ][ ][ ]{" "^{"))
              (setq squiggly (point))
              (forward-sexp 1)
              (when (< orig (point))
                (setq result (cons squiggly (point)))))))
         ((save-excursion
            (re-search-backward (if *namespace* "^[ ][ ][ ]{" "^{") nil t)
            (setq squiggly (point))
            (forward-sexp 1)
            (when (< orig (point))
              (setq result (cons squiggly (point))))))
         )
         ;; END COND!
        (if (not (car result)) (setcar result (point-min)))
        (if (not (cdr result)) (setcdr result (point-max)))
        result
        ))))

(defun cbrow--inside-method-p1-and-p2--inner ()
  (cond
   ((and *namespace* *class*) "^[ ][ ][ ][ ][ ][ ]{")
   ((or *namespace* *class*)  "^[ ][ ][ ]{")
   (t                         "^{")))

(defun cbrow--inside-method-p1-and-p2 ()
  (save-match-data
    (save-excursion
      (let (orig squiggly space-squigglies result p)
        (setq *namespace*      (cbrow--inside-namespace))
        (setq *class*          (cbrow--inside-class))
        (setq orig             (point))
        (setq space-squigglies (cbrow--inside-method-p1-and-p2--inner))
        (setq result           (cons nil nil))
        (cond
         ((save-excursion
            (when (looking-at space-squigglies)
              (setq squiggly (point))
              (forward-sexp -1) ;; SKIP ARGS!
              (beginning-of-line)
              (when (looking-at (concat "^[ \t]*" cbrow--inside-method--regexp "("))
                (setq p (point))
                (goto-char squiggly)
                (forward-sexp 1) ;; SKIP SQUIGGLIES!
                ;;(debug "Nectarine")
                (when (< orig (point))
                  (setq result (cons p (point)))
                  ;;(debug "Hole in two")
                  result))))
            ;;(debug "line 0")
          result)
         ((save-excursion
           (when (re-search-backward space-squigglies nil t)
             (setq squiggly (point))
             ;;(debug "Carrot Parrot")
             (forward-sexp -1) ;; SKIP ARGS!
             (beginning-of-line)
             (setq p (point))
             (when (looking-at (concat "^[ \t]*" cbrow--inside-method--regexp ")"))
               (goto-char squiggly)
               (forward-sexp 1) ;; SKIP SQUIGGLIES!
               ;;(debug "Apricot")
               (when (< orig (point))
                 (setq result (cons p (point)))
                 ;;(debug "Hole in three")
                 result
                 ))))
          ;;(debug "line 1")
           result)
         ((save-excursion
            ;;(debug "Carrot Parrot")
            (when (re-search-forward space-squigglies nil t)
              (forward-char -1)
              (setq squiggly (point))
              (forward-sexp 1) ;; SKIP SQUIGGLIES!
              (setq squiggly-end (point))
              ;;(debug "Holy Smoke!")
              (goto-char squiggly)
              (forward-sexp -1) ;; SKIP ARGS!
              (beginning-of-line)
              (if (looking-at (concat "^[ \t]*" cbrow--inside-method--regexp "("))
                  (setq result (cons (point) squiggly-end)))
                ))
          result))
        (if (not (car result)) (setcar result (point-min)))
        (if (not (cdr result)) (setcdr result (point-max)))
        result))))

(defun cbrow--inside-namespace ()
  (save-match-data
    (save-excursion
      (let ((namespace nil)
            (oldp      (point)))
        (if (re-search-backward "^{" nil t)
            (progn
              (forward-line -1)
              (when (looking-at "namespace[ \t]+\\(_*[a-zA-Z][a-zA-Z0-9_]*\\)")
                (setq namespace (buffer-substring-no-properties (match-beginning 1) (match-end 1)))
                (forward-line 1)
                (forward-sexp 1)
                ;;(debug "Foo")
                (if (> (point) oldp)
                    namespace))))))))

(defun cbrow--inside-class ()
  ;;(interactive)
  (save-match-data
    (save-excursion
      (let ((oldp        (point))
            ;;(*namespace*   (cbrow--inside-namespace))
            (class-point nil)
            (p1          nil)
            (p2          nil)
            (*class*     nil)
            (*namespace* (cbrow--inside-namespace))
            (meth-class  nil))
        (cond
         ((save-excursion
            (beginning-of-line)
            (looking-at (concat (if *namespace* "^[ ][ ][ ]" "^") "\\([A-Z]+[ \t]+\\)*class[ \t][a-zA-Z0-9_:]+")))
          ;;(debug 123)
          (beginning-of-line)
          (forward-line 1)
          (when (save-excursion
                  (beginning-of-line)
                  (looking-at "^-+$"))
            (beginning-of-line)
            (forward-line 2))
          (forward-line 1)
          ;;(debug 123)
          )
         ((save-excursion
            (beginning-of-line)
            (looking-at "^-+$"))
          (beginning-of-line)
          (forward-line 2)
          ;;(debug 456)
          )
         ((save-excursion
            (beginning-of-line)
            (looking-at (if *namespace* "^[ ][ ][ ]{" "{")))
          (beginning-of-line)
          (forward-line 1)
          ;;(debug 789)
          )
         (t
          (forward-line 1)
          ;;(debug "green eggs and ham")
          )
         )
        (when (re-search-backward (if *namespace* "^[ ][ ][ ]{" "^{") nil t)
          (setq class-point (point))
          (skip-chars-forward " \t")
          (if 123 (forward-sexp 1))
          (when (> (point) oldp)
            (goto-char class-point)
            (forward-line -1)
            (while (looking-at "^-+$")
              (forward-line -1)
              (beginning-of-line))
            (beginning-of-line)
            ;;(debug "Salami")
            (if (looking-at (concat "^"
                                    (if *namespace* "[ ][ ][ ]")
                                    "\\([A-Z0-9_]+[ \t]+\\)*class[ \t]\\([a-zA-Z0-9_:]+\\)"))
                (progn
                  ;;(if (and (match-beginning 2) (match-end 2))
                  ;;    (setq *namespace* (buffer-substring-no-properties (match-beginning 2) (match-end 2)))
                  ;;(debug "not beg")
                  (setq meth-class (buffer-substring-no-properties (match-beginning 2) (match-end 2))))
              ;;(debug "Antelope")
              (setq meth-class nil)
              )
            ;;(debug "Red Hot Chilli Peppers")
            (if (and *namespace* meth-class)
                (concat *namespace* "::" meth-class)
              meth-class)))))))

(setq cbrow--inside-class--regexp "^\\([A-Z]+[ \t]+\\)?class \\(_*[a-zA-Z][a-zA-Z0-9_]*::\\)?\\([A-Za-z][A-Za-z0-9_]*\\)[^;\n]*\n")

(setq cbrow--identifier--chars "~A-Za-z0-9_")

(setq cbrow--inside-method--regexp
      (concat "\\(_*[a-zA-Z][A-Za-z0-9_<]*[> ]*[&*]*[ \t]+\\)*"
              "\\(_*[a-zA-Z][~a-zA-Z0-9_:]*\\)"))

;; (cbrow--number-of-commas method)
(defun cbrow--number-of-commas (method)
  (let ((count 0) (method-2 method))
    (while (string-match "," method-2)
      (incf count)
      (setq method-2 (concat
                      (substring method-2 0 (match-beginning 0))
                      "."
                      (substring method-2 (match-end 0)))))
    count))

;; (cbrow--remove-spaces "abc\ndef\nghi")
;; (cbrow--remove-spaces "abc   def   \tghi")
(defun cbrow--remove-spaces (s)
  (let ((len (length s))
        (i   0)
        (answer ""))
    ;;(debug "Zenzi")
    (while (< i len)
      (let ((ch (aref s i)))
        (if (or (= ch ?\t)
                (= ch ?\r)
                (= ch ?\n))
            (setq ch ? ))
        (setq answer (format "%s%c"  answer ch)))
      (if (cbrow--is-space s i)
          (while (and (< i len)
                      (cbrow--is-space s i))
            (incf i))
        (incf i))
      )
    answer))

(defun cbrow--trim-spaces-in-args (method)
  (progn
    (while (string-match "( " method)
      (setq method (concat (substring method 0 (match-beginning 0))
                           "("
                           (substring method (match-end 0)))))
    (while (string-match ", " method)
      (setq method (concat (substring method 0 (match-beginning 0))
                           ","
                           (substring method (match-end 0)))))
    (while (string-match " )" method)
      (setq method (concat (substring method 0 (match-beginning 0))
                           ")"
                           (substring method (match-end 0)))))
    method))

;; (setq old-method (cbrow--inside-method))
;; (setq method old-method)
;; (setq method "(int*** i, ptr<Foo_A>&&&* j, const char**** str = null)")
;; (cbrow--trim-spaces-in-args method)
;; (cbrow--change-args method)
(defun cbrow--change-args (method)
  ;;method)
  (when (not (string-match "()" method))
    (let (count beg end len len+1)
      (progn
        (setq count  0)
        (setq method (cbrow--remove-spaces method))
        (setq method (cbrow--trim-spaces-in-args method))
        (setq len    (cbrow--number-of-commas method))
        (setq len+1  (1+ len))
        (while (< count len+1)
          (progn
            (if (= count 0)
                (setq beg "(")
              (setq beg ","))
            (if (= count len)
                (setq end ")")
              (setq end ","))
            (cons beg end))
          (when ;;(string-match (concat "\\(" beg "[^,]+ +\\( = ?[a-zA-Z0-9]+\\)?\\)\\(_*[a-zA-Z][a-zA-Z0-9_]*\\)" end) method)
              (string-match (concat beg
                                    "\\(\\(const \\|unsigned \\|signed\\)*[a-zA-Z0-9_<:]+[ >]*[&*]*\\) "
                                    "\\(_*[a-zA-Z][a-zA-Z0-9_]*\\)\\(\\( ?= ?_*[a-zA-Z][a-zA-Z0-9_]*\\)?\\)"
                                    end)
                            method)
            ;;(d-beeps "count=%s" count)
            (setq method (concat (substring method 0 (match-end 1))
                                 (substring method (match-end 4))
                                 )))
          ;;(setq method (concat (substring method 0 (match-end 1)) (substring method (match-end 3)))))
          (incf count)))
      )
    )
  method
  )

(defun cbrow--space-regexp ()
  (cond
   ((and *namespace* *class*)
    "^[ ][ ][ ][ ][ ][ ]{"
    )
   ((or *namespace* *class*)
    "^[ ][ ][ ]{")
   (t
    "^{")))

(defun cbrow--sqiggly-regexp ()
  (cond
   ((and *namespace* *class*)
    "^[ ][ ][ ][ ][ ][ ]{"
    )
   ((or *namespace* *class*)
    "^[ ][ ][ ]{")
   (t
    "^{")))

(defun cbrow--inside-method ()
  (save-match-data
    (save-excursion
      (let ((orig (point)) p *namespace* *class* found squiggly result namespace-ps class-ps)

        (beginning-of-line)

        (setq *namespace* (cbrow--inside-namespace))
        (setq *class*     (cbrow--inside-class))

        (if *namespace*
            (setq namespace-ps (cbrow--inside-namespace-p1-and-p2)))
        (if *class*
            (setq class-ps     (cbrow--inside-class-p1-and-p2)))

        ;;(debug "Salami Sandwiches")

        (if (and *class* (string-match (concat "\\(" *namespace* "::\\)") *class*))
            (setq *class* (substring *class* (match-end 1))))

        ;;(debug "Bitter question")

        ;; BEGIN COND!
        (cond
         ((save-excursion
            ;;(forward-line -1)
            ;;(setq p (point))
            ;;(forward-line 1)
            (beginning-of-line)
            ;;(debug "weather forecast")
            (when (looking-at (cbrow--space-regexp))
              ;;(debug "would you?")
              (setq squiggly (point))
              (forward-sexp -1) ;; SKIP ARGS!
              (beginning-of-line)
              (setq p (point))
              (goto-char squiggly)
              (forward-sexp 1) ;;; SKIP SQUIGGLIES!
              (when (< orig (point))
                (goto-char p)
                (when (re-search-forward (concat (cbrow--space-regexp) cbrow--inside-method--regexp "(")
                                         (if *namespace* (cdr namespace-ps) (cdr class-ps))
                                         t)
                  (setq found (buffer-substring-no-properties (match-beginning 2) (match-end 2)))
                  (forward-char -1)
                  (setq p (point))
                  (forward-sexp 1) ;; SKIP ARGS!
                  (setq found (concat found (cbrow--change-args (buffer-substring-no-properties p (point)))))
                  ;;(debug 123)
                  found))))
          found)
         ((save-excursion
            (beginning-of-line)
            (when (re-search-forward (cbrow--sqiggly-regexp)
                                     (cond
                                      ((and namespace-ps class-ps)
                                       (min (cdr namespace-ps) (cdr class-ps)))
                                      (namespace-ps
                                       (cdr namespace-ps))
                                      (class-ps
                                       (cdr class-ps))
                                      (t
                                       nil)) t)
              (forward-char -1)
              (setq squiggly (point))
              (forward-sexp -1) ;; SKIP ARGS!
              (beginning-of-line)
              (setq p (point))
              (goto-char squiggly)
              ;;(debug "Would you #2")
              (forward-sexp 1) ;; SKIP SQUIGGLIES!
              (when (< orig (point))
                ;;(debug "Rocket")
                (goto-char squiggly)
                (if 'foomatic (forward-sexp -1)) ;; SKIP ARGS!
                (beginning-of-line)
                (when (re-search-forward (concat (cbrow--space-regexp) cbrow--inside-method--regexp "(")
                                         (if *namespace* (cdr namespace-ps) (cdr class-ps) )
                                         t)
                  (setq found (buffer-substring-no-properties (match-beginning 2) (match-end 2)))
                  ;;(debug "Would you $100")
                  (forward-char -1)
                  (setq p (point))
                  (forward-sexp 1) ;; SKIP ARGS!
                  (setq found (concat found (cbrow--change-args (buffer-substring-no-properties p (point)))))
                  ;;(d-beeps "456")
                  found))))
          found)
         ((save-excursion
            (when (re-search-backward (cbrow--sqiggly-regexp) nil t)
              (setq squiggly (point))
              (if 'mac (forward-sexp -1)) ;; SKIP ARGS!
              (beginning-of-line)
              ;;(debug "Would you #3")
              (setq p (point))
              ;;(debug 789)
              (goto-char squiggly)
              (forward-sexp 1) ;; SKIP SQUIGGLIES!
              (when (< orig (point))
                (goto-char p)
                (when (re-search-forward (concat (cbrow--space-regexp) cbrow--inside-method--regexp "(")
                                         (if *namespace* (cdr namespace-ps) (cdr class-ps))
                                         t)
                  (setq found (buffer-substring-no-properties (match-beginning 2) (match-end 2)))
                  (forward-char -1)
                  (setq p (point))
                  (forward-sexp 1) ;; SKIP ARGS!
                  (setq found (concat found (cbrow--change-args (buffer-substring-no-properties p (point)))))
                  ;;(debug 789)
                  found
                  ))))
          ;; END SAVE-EXCURSION!
          found)
         ((save-excursion
            (and (not *namespace*)
                 (prog1
                     (re-search-backward (if *class* "^[ ][ ][ ]{" "^{")
                                         (car class-ps)
                                         t)
                   (setq squiggly (point)))
                 (progn
                   ;;(debug "Would you #4")
                   ;;(forward-line -1)
                   ;;(end-of-line)
                   (if 'args (forward-sexp -1)) ;; SKIP ARGS!
                   (beginning-of-line)
                   (setq p (point))
                   ;;(forward-line 1)
                   (goto-char squiggly)
                   ;;(beginning-of-line)
                   (if 'zed (forward-sexp 1)) ;; SKIP SQUIGGLIES!
                   (when (< orig (point))
                     (goto-char p)
                     ;;(debug "smeg")
                     (when (re-search-forward (concat (if *class* "^[ ][ ][ ]" "^")
                                                      cbrow--inside-method--regexp "(") (point-at-eol) t)
                       (setq found (buffer-substring-no-properties (match-beginning 2) (match-end 2)))
                       ;;(debug "PI")
                       )))))
          found)
         ((save-excursion
            (and (not *namespace*)
                 (progn
                   (beginning-of-line)
                   ;;(debug "Roger Ramjet")
                   (when (setq result (re-search-forward (if *class* "^[ ][ ][ ]{" "^{")
                                                         (if *namespace* (cdr namespace-ps) (cdr class-ps))
                                                         t))
                     (forward-char -1)
                     (setq squiggly (point))
                     result))
                 (progn
                   ;;(beginning-of-line)
                   (forward-line -1)
                   (end-of-line)
                   (if 'banana (forward-sexp -1))
                   (beginning-of-line)
                   (setq p (point))
                   (goto-char squiggly)
                   ;;(forward-line 1)
                   (if 'id (forward-sexp 1))
                   ;;(debug "would you #5")
                   (when (< orig (point))
                     (goto-char p)
                     ;;(debug 456)
                     (when (re-search-forward (concat (if *class* "^[ ][ ][ ]" "^")
                                                      cbrow--inside-method--regexp "(") (point-at-eol) t)
                       ;;(debug 789)
                       (setq found (buffer-substring-no-properties (match-beginning 2) (match-end 2)))
                       ;;(d-beeps "Zippo Lighters")
                  (forward-char -1)
                  (setq p (point))
                  (forward-sexp 1) ;; SKIP ARGS!
                  (setq found (concat found (cbrow--change-args (buffer-substring-no-properties p (point)))))
                  found)))))
          found)
         )
        ;; END COND!
        ;;(debug "Fynall Bynall")
        (if found
            (concat (if *namespace* (concat *namespace* "::"))
                    (if *class*     (concat *class* "::"))
                    found))
        ;;(debug "Cold Potatoes")
        )
      )
    )
  )

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;
;;; BEGIN: cbrow generic functions
;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

(defun cbrow--current-line-as-string ()
  (buffer-substring-no-properties (point-at-bol)
                                  (point-at-eol)))

(defun cbrow--skip-word (word)
  (assert (looking-at word))
  (let ((i 0)
        (len (length word)))
  (while (< i len)
    (assert (eq (char-after) (aref word i)))
    (incf i)
    (forward-char 1))))

(defun cbrow--is-space (string index)
  (or (= (aref string index) ? )
      (= (aref string index) ?\t)
      (= (aref string index) ?\n)
      (= (aref string index) ?\r)))

(defun cbrow--trim-left (s)
  (let (i len ch)
    (setq i 0)
    (setq len (length s))
    (while (and (< i len)
                (setq ch (aref s i))
                (or (eq ch ?\ )
                    (eq ch ?\t)
                    (eq ch ?\r)
                    (eq ch ?\n)))
      (incf i))
    (setq s (substring s i)))
  s)

(defun cbrow--trim-right (s)
  (let (i ch)
    (setq i (1- (length s)))
    (while (and (>= i 0)
                (setq ch (aref s i))
                (or (eq ch ?\ )
                    (eq ch ?\t)
                    (eq ch ?\r)
                    (eq ch ?\n)))
      ;;(setq s (substring s 0 i))
      (decf i))
    (setq s (substring s 0 (1+ i)))
    )
  )

(defun cbrow--trim-string (s)
  (if (or (not s) (string= s ""))
      ""
    (if s (d-trim-left (d-trim-right s)))))

;;(cbrow--trim-return-value "  void    abc(int i, char**** str, ptr<Foo_A> foo)")
(defun cbrow--trim-return-value (method-spec)
  (if (string-match "\\(^[ \t]*\\)\\([a-zA-Z0-9_<>]+[ >]*[&*]*[ \t]+\\)*\\([~a-zA-Z0-9_:]+(\\)" method-spec)
      (setq method-spec (substring method-spec (match-beginning 3)))))


(defun cbrow--what-line ()
  "Different from what-line in that it returns the result rather than printing it"
  (save-excursion
    (beginning-of-line)
    (1+ (count-lines 1 (point)))))

(defun cbrow--message (string)
  (message "Class Browser: %s" string)
  ;;(beep)
  ;;(sit-for .2)
  ;;(beep)
  )


;;(cbrow--tail (setq string "///\n/// Tile Mode functions\n///abc"))
(defun cbrow--tail (string)
  (while ;;(string-match "^[\r\n]+[^\r\n]*[\r\n]+$" string)
      (string-match "[\r\n]+[^\r\n]*[\r\n]+" string)
    (setq string (substring string (match-end 0)))
    )
  string)

(defun cbrow--log--simple (string)
  (save-excursion
    (set-buffer cbrow--buffer-name)
    (goto-char (point-max))
    (if (not (null string))
        (insert string))))

(defun cbrow--log--complex (string &optional not-here)
  ;;(d-beeps "cbrow--log--complex string=%s" string)
  ;;(message "*** string=%s" string)
  ;;(when (and (not (string= "" string))
  ;;           (not (string-match "^[\r\n]$" string)))
  (let ((what-line        (cbrow--what-line))
        (spaces           0)
        (string-last-line nil))
    (while (and (> (length string) 0)
                (= (aref string 0) ?\n))
      ;;(save-excursion
      ;;(set-buffer cbrow--buffer)
      ;;(goto-char (point-max))
      ;;(insert "\n")
      (setq string (substring string 1)))

    ;;(if (or (string= "" string) (string= "\n" string))
    ;;    (debug "Toilet paper"))

    ;;(if (string-match "foomatic" string) (debug "Carrot"))
    (if (and (not (string= "" string))
             ;;(not (string-match "//" string))
             ;;(not (string=      "" string))
             (not (string-match "{$"                        string))
             (not (string-match "[\r\n]+$"                  string))
             (not (string-match "^class[ \t][a-zA-Z0-9_:]+" string))
             (not (string-match "^public:"                  string))
             (not (string-match "^private:"                 string))
             (not (string-match "^protected:"               string))
             (not (string-match "^#"                        string)))
        ;;(debug "foo"))
        (when (/= (aref string (1- (length string))) ?\;)
          ;;(debug "Bar")
          (setq string (concat string ";"))
          ))

    (when (string-match "\\([\r\n]+$\\)" string)
      (setq string (substring string 0 (match-beginning 0))))

    ;;(if (string-match "Tile Mode functions" string)
    ;;    (debug "foomatic"))

    ;;(setq string "/// abc\n///def ghi\n/// foomatic")
    ;;(if (string-match "[\r\n]+\\([^\r\n]+\\)$" string)
    (setq string-last-line (cbrow--tail string))

    (progn
      (setq f-w (frame-width))
      (setq spaces
            (if (<= (length string-last-line) f-w)
                (make-string (max 0 (- f-w 20 (length string-last-line))) ? )
              " "))
      (setq string (concat string spaces)))

    (if not-here
        (setq string (concat string "//LINE:" (format "%d" what-line)  " NOT HERE!"))
      (setq string (concat string "//LINE:" (format "%d" what-line))))

    (save-excursion
      (set-buffer cbrow--buffer)
      (goto-char (point-max))
      ;;(insert "KKK:" string ":LLL\n")
      (insert string "\n")
      )
    )
    ;;(if (string-match "respond(" string)
    ;;    (debug "Pencil neck"))
    ;;(if (string= "\n" string)
    ;;   (debug "Zipper"))
    ;;(debug "Cactus")
  )

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;
;;; END: cbrow generic functions
;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

(defun cbrow--scan-comment--this-line ()
  (save-match-data
    (let ((comment-end   nil)
          (comment-start nil)
          (answer        nil))
      (save-excursion
        (forward-line -1)
        (beginning-of-line)
        (while (string-match "^[ \t]*$" (cbrow--current-line-as-string))
          (forward-line -1))
        (forward-line 1)
        (setq comment-end (point-at-bol))
        (forward-line -1)
        (while (and (looking-at (concat (if *namespace* "^[ ][ ][ ][ ][ ][ ]" "^[ ][ ][ ]") "//[^\n\r]*$"))
                    ;;(looking-at "^   //[^\n\r]*$")
                    (not (bobp)))
          (forward-line -1)
          (beginning-of-line))
        (forward-line 1)
        (setq comment-start (point))
        (setq answer (buffer-substring-no-properties comment-start comment-end))
        ;;(if (string-match "//" answer) (debug "Bastard"))
        ;;(error "smeg")
        answer))))

;; (cbrow--scan-method)
(defun cbrow--scan-method ()
  (save-excursion
    (save-match-data
      (if (string= (buffer-substring-no-properties (point-min) (point-max)) "")
          (error "*Class Browser* is empty"))
      ;;(d-beeps "Current Buffer=%s" (current-buffer))
      ;;(if *namespace*
      (let* (str)
        (setq str (buffer-substring-no-properties
                   (point-at-bol)
                   (if (progn
                         (beginning-of-line)
                         (search-forward "(" (point-at-eol) t))
                       (progn
                         (backward-char 1)
                         (forward-sexp 1)
                         (point-at-eol))
                     (point-at-eol))))
        ;;(concat "   " (cbrow--remove-spaces str))
        (cbrow--change-args str)
        )
      )
    )
  )

;; (cbrow--scan-property--this-line)
(defun cbrow--scan-property--this-line ()
  (save-match-data
    (let ((str (buffer-substring-no-properties
                (point-at-bol)
                (save-excursion
                  (progn
                    (beginning-of-line)
                    (search-forward ";")
                    (point)
                    )))))
      ;; fixes job down by remove-spaces
      (concat "  " (cbrow--remove-spaces str))
      )))

;;; (setq class-max (point-max))
(defun cbrow--found-a-method (class-max)
  (save-match-data
    (let* (;;(*namespace* (cbrow--inside-namespace))
           (f1 (save-excursion
                 (re-search-forward
                  (concat (if *namespace* "^[ ][ ][ ][ ][ ][ ]" "^[ ][ ][ ]")
                          "\\(_*[a-zA-Z][a-zA-Z0-9_:<]*[ >]*[*&]*[ \t]+\\)*~?\\([a-zA-Z][a-zA-Z0-9_]*\\)(")
                  class-max
                  t)))
           (f2 (save-excursion
                 (re-search-forward
                  (concat (if *namespace* "^[ ][ ][ ][ ][ ][ ]" "^[ ][ ][ ]")
                          "\\(_*[a-zA-Z][a-zA-Z0-9_:<]*[ >]*[*&]*[ \t]+\\)*operator[ \t]+"
                          "\\(=\\|==\\|!=\\|+\\|+=\\|-\\|-=\\|<<\\|<<=\\|>>\\|>>=\\)[ \t]+(")
                  class-max
                  t))))
      (cond
       ((and (numberp f1) (numberp f2))
        (min f1 f2))
       ((numberp f1)
        f1)
       ((numberp f2)
        f2)
       nil))))

(defun cbrow--found-a-property (class-max)
  (save-match-data
    (save-excursion
      (re-search-forward (concat (if *namespace* "^[ ][ ][ ][ ][ ][ ]" "^[ ][ ][ ]")
                                 "\\([a-zA-Z_][a-zA-Z0-9_<>:]*[> ]*[&*]*[ \t]+\\)*"
                                 "[a-zA-Z_][a-zA-Z0-9_]*\\([ \t]*=[^;]+\\)?;")
                         class-max
                         t))))

(defun cbrow--found-a-template (class-max)
  (save-match-data
    (save-excursion
      (re-search-forward (concat (if *namespace* "^[ ][ ][ ][ ][ ][ ]" "^[ ][ ][ ]")
                                 "template.*;")
                         class-max
                         t))))

(defun cbrow--found-an-outer-template ()
  (cond
   ((looking-at "^class")
    (setq p (point)))
   ((save-excursion
      (prog2
          (forward-line -1)
          (looking-at "^class")
        (setq p (point)))))
   ((save-excursion
      (prog1
          (re-search-backward "^class" nil t)
        (setq p (point))))))
  (save-excursion
    (goto-char p)
    (forward-line -1)
    (if (looking-at "^template.*$")
        (concat (cbrow--current-line-as-string) "\n"))))

;;(cbrow--found-a-hash)
(defun cbrow--found-a-hash (class-max)
  (save-match-data
    (save-excursion
      (re-search-forward "^#.*$" class-max t))))
(progn
  (setq *verbose*   nil)
  ;;(setq *namespace* nil)
  ;;(setq *class*     nil)
  )

(defun cbrow--found-a-public (class-max)
  (save-match-data
    (save-excursion
      (re-search-forward (if *namespace* "^   public:" "^public:") class-max t))))

(defun cbrow--found-a-private (class-max)
  (save-match-data
    (save-excursion
      (re-search-forward (if *namespace* "^   private:" "^private:") class-max t))))

(defun cbrow--found-a-protected (class-max)
  (save-match-data
    (save-excursion
      (re-search-forward (if *namespace* "^   protected:" "^protected:") class-max t))))

(defun cbrow--found-empty-line (class-max)
  (save-match-data
    (save-excursion
      (re-search-forward "^[ \t]*$" class-max t))))

(defun cbrow--found-a-friend (class-max)
  (save-match-data
    (save-excursion
      (re-search-forward (concat (if *namespace*
                                     "^[ ][ ][ ][ ][ ][ ]friend[ \t]"
                                   "^[ ][ ][ ]friend[ \t]")
                                 ".*$") class-max t))
    ))

;;;
;;; strictly don't need this function
;;; as it is only called once...
;;;
(defun cbrow--generate-browser-inner (*class* class-min class-max)
  ;;(d-beeps "min=%s max=%s" class-min class-max)
  (save-match-data
    (save-excursion
      ;;(debug)
      ;;(assert (looking-at "ABSTRACT"))
      (goto-char class-min)
      (forward-line -1)
      (cbrow--log--simple (cbrow--found-an-outer-template))

      ;;(debug "Dance of the dolphins")

      (if (string-match "^_*[a-zA-Z][a-zA-Z0-9_]*::\\(_*[a-zA-Z][a-zA-Z0-9_]*\\)" *class*)
          (setq class-only (substring *class* (match-beginning 1))))

      (cbrow--log--complex (concat "class " (if *namespace* (concat *namespace* "::" class-only) *class*)))
      (cbrow--log--simple
       "---------------------------------------------------------------------------------------\n")
      (cbrow--log--complex "{")

      ;;(debug "Spinster")

      (let ((found-friend     nil)
            (found-method     nil)
            (found-property   nil)
            (found-public     nil)
            (found-private    nil)
            (found-protected  nil)
            (found-template   nil)
            (found-hash       nil)
            ;;(found-empty-line nil)
            (comment          nil)
            (min              nil))

        (while (progn (setq found-friend     (cbrow--found-a-friend    class-max))
                      (setq found-method     (cbrow--found-a-method    class-max))
                      (setq found-property   (cbrow--found-a-property  class-max))
                      (setq found-public     (cbrow--found-a-public    class-max))
                      (setq found-private    (cbrow--found-a-private   class-max))
                      (setq found-protected  (cbrow--found-a-protected class-max))
                      (setq found-template   (cbrow--found-a-template  class-max))
                      (setq found-hash       (cbrow--found-a-hash      class-max))
                      ;;(setq found-empty-line (cbrow--found-empty-line  class-max))
                      (or found-friend
                          found-method
                          found-property
                          found-public
                          found-private
                          found-protected
                          found-template
                          ;;found-empty-line
                          ))
          ;;(if (string-match "protected:" (cbrow--current-line-as-string))
          ;;   (debug "*** line=%s" (cbrow--current-line-as-string)))
          ;;(if (string-match "draw_inner(" (cbrow--current-line-as-string))
          ;;    (debug "Earl of Spencer"))
          ;;(if found-method   (message "*** found-method=%s" found-method))
          ;;(if found-property (message "*** found-property=%s" found-property))
          (if (not found-friend)    (setq found-friend    1e100))
          (if (not found-method)    (setq found-method    1e100))
          (if (not found-property)  (setq found-property  1e100))
          (if (not found-public)    (setq found-public    1e100))
          (if (not found-private)   (setq found-private   1e100))
          (if (not found-protected) (setq found-protected 1e100))
          (if (not found-template)  (setq found-template  1e100))
          (if (not found-hash)      (setq found-hash      1e100))
          ;;(if (not found-empty-line) (setq found-empty-line 1e100))

          (setq min (min found-friend
                         found-method
                         found-property
                         found-public
                         found-private
                         found-protected
                         found-template
                         found-hash
                         ;;found-empty-line
                         ))

          (cond
           ;;((= min found-empty-line)
           ;; (cbrow--log--simple "\n")
           ;; (forward-line 1))

           ((= min found-friend)
            (goto-char found-friend)
            (cbrow--log--complex (concat
                                  "   "
                                  (if *verbose* "FRIEND:")
                                  (cbrow--trim-string (cbrow--current-line-as-string)))))

           ((= min found-method)
            (let ((method-name    nil)
                  (method-comment nil))
              (goto-char found-method)
              (setq method-name (cbrow--scan-method))
              (setq method-comment (cbrow--scan-comment--this-line))
              (cbrow--log--simple method-comment)
              ;;(debug "Hot potatoes")
              ;;(if (string-match "^[\r\n]" method-name)
              ;;    (debug "Toadstools"))

              (if (eq ?\; (aref method-name (1- (length method-name))))
                  (cbrow--log--complex (concat "   "
                                               (if *verbose* "METHOD NOT HERE:")
                                               (cbrow--trim-string method-name)
                                               ) 'not-here)
                (cbrow--log--complex   (concat "   "
                                               (if *verbose* "METHOD HERE:")
                                               (cbrow--trim-string method-name)))
                )
              ;;(debug "Texas Chainsaw Massacre")
              ;;(if (string-match "ctor(" method-name)
              ;;    (debug "Smell you later"))
              ))

           ((= min found-property)
            (let ((property-name nil)
                  (property-comment nil))
              (goto-char found-property)
              (setq property-name    (cbrow--scan-property--this-line))
              (setq property-comment (cbrow--scan-comment--this-line))
              ;;(debug)
              (cbrow--log--simple property-comment)
              (cbrow--log--complex (concat
                                    "   "
                                    (if *verbose* "PROPERTY:")
                                    (cbrow--trim-string property-name)
                                    ))
              ;;(debug 123)
              ))

           ((= min found-public)
            (goto-char found-public)
            (setq comment (cbrow--scan-comment--this-line))
            ;;(debug 123)
            (cbrow--log--complex comment)
            (cbrow--log--complex "\npublic:"))

           ((= min found-private)
            (goto-char found-private)
            (setq comment (save-excursion
                            ;;(forward-line -1)
                            (cbrow--scan-comment--this-line)))
            (cbrow--log--complex comment)
            (cbrow--log--complex "\nprivate:")
            ;;(debug "Doughnut")
            )

           ((= min found-protected)
            (goto-char found-protected)
            (setq comment (cbrow--scan-comment--this-line))
            (cbrow--log--complex comment)
            (cbrow--log--complex "\nprotected:")
            )

           ((= min found-template)
            (goto-char found-template)
            (setq comment (cbrow--scan-comment--this-line))
            (cbrow--log--complex comment)
            (cbrow--log--complex (cbrow--current-line-as-string)))

           ((= min found-hash)
            (goto-char found-hash)
            (setq comment (cbrow--scan-comment--this-line))
            (cbrow--log--complex comment)
            (cbrow--log--complex (cbrow--current-line-as-string)))

           ;;((= min found-empty-line)
           ;; (goto-char found-empty-line)
           ;; (setq comment (cbrow--scan-comment--this-line))
           ;; (cbrow--log--complex comment)
           ;; (cbrow--log--complex (cbrow--current-line-as-string)))

           (t
            (error "Function cbrow--generate-browser-inner: should never happen")))

          )
        (re-search-forward (if *namespace* "^[ ][ ][ ]}" "^}") nil t)
        ;;(debug "Pencil")
        (cbrow--log--simple (cbrow--scan-comment--this-line))
        (cbrow--log--simple "};\n\n")
        (cbrow--level--begin-or-end 1 "END" *class*)
        ))))

(defun cbrow--line-ptr ()
  (save-match-data
    (save-excursion
      (beginning-of-line)
      (if (re-search-forward "LINE:" (point-at-eol) t)
          (read-str (buffer-substring-no-properties (point) (save-excursion
                                                              (skip-chars-forward "0-9")
                                                              (point))))
        1e100))))


;;(defvar cbrow--class--local nil)

(defun cbrow--level--begin-or-end (level begin-or-end *class*)
  (cbrow--log--simple         (concat (make-string (frame-width) ?/) "\n"))
  (cbrow--log--simple         "///\n")
  (cbrow--log--simple (concat "/// CLASS BROWSER LEVEL "
                              (format "%d" level)
                              " "
                              begin-or-end
                              " : "
                              *class*
                              " "
                              (cadr (assoc *class* cbrow--header-alist))
                              "\n"
                              ))
  (cbrow--log--simple         "///\n")
  (cbrow--log--simple         (concat (make-string (frame-width) ?/) "\n"))
)

;;;; vvvvv

;;;
;;; NOT NEEDED: (set-syntax-table c++-mode-syntax-table)
;;;
(defun cbrow--generate-browser (*class* line-or-method-or-class)
  ;;(debug 123)
  ;;(assert (eq line-or-method-or-class '*class*))
  ;;(d-beeps "*class*=%s" *class*)
  ;;(debug "Foo!")
  ;;(assert (numberp line-or-method-or-class))
  (save-match-data
    (save-excursion
      (setq *namespace* (cbrow--inside-namespace))
      (if (get-buffer cbrow--buffer-name)
          (kill-buffer cbrow--buffer-name))
      (setq cbrow--buffer (generate-new-buffer cbrow--buffer-name))
      (unwind-protect
          ;; BEGIN LET!
          (let ((header           nil)
                (buf              nil)
                (extra            nil)
                (case-fold-search nil)
                (found            nil)
                )
            (setq header (cadr (assoc *class* cbrow--header-alist)))
            (cond
             ((not header)
              (error "(1) Header file is nil for class %s" *class*))
             ((not (file-exists-p header))
              (error "(2) Header file %s not found for class %s" header *class*))
             (t
              ;;
              ;; FIXED BUG! if header is the same buffer as the current buffer...
              ;;
              ;; NOTE: safe to kill the buffer as it has been saved and from now on it is read-only
              ;;
              ;;(save-buffer (setq buf (find-file-read-only header)))
              (setq buf (find-file header))
              (goto-char (point-min))
              ;;(error "smeg")
              ))

            (cbrow--level--begin-or-end 1 "BEGIN" *class*)

            ;;(setq *class* "dmp::string_buffer")
            (let* ((ptr (cdr (assoc *class* cbrow--superclass-alist)))
                   (len (length ptr)))
              (while ptr
                (cbrow--log--simple (concat "SUPERCLASS: " (car ptr) "\n"))
                (setq ptr (cdr ptr)))
              (if (/= len 0)
                  (cbrow--log--simple "\n")))

            (let* ((ptr (cdr (assoc *class* cbrow--subclass-alist)))
                   (len (length ptr)))
              (while ptr
                (cbrow--log--simple (concat "SUBCLASS: " (car ptr) "\n"))
                (setq ptr (cdr ptr)))
              (if (/= len 0)
                  (cbrow--log--simple "\n")))

            ;;(debug "Hairy Lemon")

            (if (string-match "[a-zA-Z0-9_]*::\\(_*[a-zA-Z][a-zA-Z0-9_]*\\)" *class*)
                (setq class-only (substring *class* (match-beginning 1) (match-end 1)))
              (setq class-only *class*))

            ;;(debug "Scary Movie")

            ;;(cbrow--log--simple "sex\n")
            (setq strobe 0)
            (cond
             ((progn
                (goto-char (point-min))
                (re-search-forward (concat "^\\(\\([A-Z]+[ \t]+\\)*\\)class[ \t]+"
                                           *class*
                                           "\\([ \t].*[\r\n]\\|[\r\n]+\\){") nil t))
              (progn
                ;;(debug "Summer Holiday")
                (setq strobe 1)
                (setq *namespace* nil)
                (setq extra (buffer-substring-no-properties (match-beginning 1) (match-end 1)))))

             ((progn
                (goto-char (point-min))
                (re-search-forward (concat "^[ ][ ][ ]\\(\\([A-Z]+[ \t]+\\)*\\)class[ \t]+"
                                           *class*
                                           "\\([ \t].*[\r\n]\\|[\r\n]+\\)[ ][ ][ ]{") nil t))
              (progn
                (setq strobe 2)
                (setq *namespace* (cbrow--inside-namespace))
                (setq extra (buffer-substring-no-properties (match-beginning 1) (match-end 1)))))

             ((progn
                (goto-char (point-min))
                (re-search-forward (concat "^\\(\\([A-Z]+[ \t]+\\)*\\)*class*[ \t]+"
                                           class-only
                                           "\\([ \t].*[\r\n]\\|[\r\n]+\\){") nil t))
              (progn
                ;;(debug "Summer Holiday")
                (setq strobe 3)
                (setq *namespace* nil)
                (setq extra (buffer-substring-no-properties (match-beginning 1) (match-end 1)))))

             ((progn
                (goto-char (point-min))
                (re-search-forward (concat "^[ ][ ][ ]\\(\\([A-Z]+[ \t]+\\)*\\)class[ \t]+"
                                           class-only
                                           "\\([ \t].*[\r\n]\\|[\r\n]+\\)[ ][ ][ ]{") nil t))
              (progn
                (setq strobe 4)
                (setq *namespace* (cbrow--inside-namespace))
                (setq extra (buffer-substring-no-properties (match-beginning 1) (match-end 1)))))

             ((progn
                (goto-char (point-min))
                (setq strobe 5)
                (setq *namespace* (cbrow--inside-namespace))
                (re-search-forward (cond
                                    ((and *namespace* *class*)
                                     "^[ ][ ][ ][ ][ ][ ]{")
                                    ((or *namespace* *class*)
                                     "^[ ][ ][ ]{")
                                    (t
                                     "^{")) nil t)))
             (t
              (error "(3) Class %s not found in namespace %s in header file %s" *class* *namespace* header)))
            ;;(message "extra=%s" (prin1-to-string extra))
            ;;(sit-for 1)
            ;;(debug)
            ;; log ABSTRACT or FINAL
            (cbrow--log--simple (concat extra (if (string= extra "") nil "\n")))
            ;;(d-beeps "buf=%s" (current-buffer))
            ;;(if (not (bobp))
            (forward-char -1)
            (assert (looking-at "{"))
            ;;(error "foo")
            (let ((p1 nil)
                  (p2 nil))
              (setq p1 (point))
              (setq p2 (save-excursion
                         (forward-sexp 1) ;; SKIP CLASS!
                         (point)))
              (cbrow--generate-browser-inner *class* p1 p2)
              ;;(debug "Calamansi")
              ;;(kill-buffer buf)
              ))
            ;; END LET!
        ;;(debug "Cabbage")
        (switch-to-buffer cbrow--buffer) ;;;; <--------- switch to buffer
        (cond
         ((numberp line-or-method-or-class)
          ;;
          ;; NOTE: line-or-method-or-class is a line number
          ;;
          (let ((orig-line line-or-method-or-class))
            ;;(debug "Regina")
            (progn
              ;;(setq orig-line nil)
              (goto-char (point-max))
              (while (and (not (bobp))
                          (< orig-line (cbrow--line-ptr))) ;;;   LINE:333
                (forward-line -1))
              (if (bobp)
                  (error "(5) Function cbrow--generate-browser: Line %s not found" orig-line)
                (setq found t)))
            )
          )

         ((stringp line-or-method-or-class)
          ;;
          ;; NOTE: line-or-method-or-class is the name of a method
          ;;
          (let ((orig-method line-or-method-or-class))
            ;;(debug "Foo!")
            (goto-char (point-min))
            (re-search-forward "^-+$")
            (beginning-of-line)
            (forward-line 1)
            (re-search-forward (concat "\\($\\|[ \t]\\)" orig-method "(")) ;;; WHY? [^~] ???
            (beginning-of-line)
            (setq found t)
            ))
         ;;
         ;; NOTE: line-or-method-or-class is bound to 'class
         ;;
         ((eq 'class line-or-method-or-class)
          (goto-char (point-min))
          ;;(debug "Lambada")
          (re-search-forward (concat "class[ \t]+" *class*) nil t)
          ;;(debug "Line Reef")
          (beginning-of-line)
          (setq found t)
          )

         ;; PUTBACK:
         (t (error "(6) Function cbrow--generate-browser: should never happen"))
         )
        (when (eq (current-buffer) (get-buffer cbrow--buffer))
          (switch-to-buffer cbrow--buffer)
          (c++-mode)
          (use-local-map cbrow--map1)
          (read-only-mode 1)
          (set (make-local-variable 'truncate-lines) t)
          ;;(debug "Scream II")
          (when (not found)
            (goto-char (point-min))
            (if (and *namespace* (not (string-match "_*[a-zA-Z][a-zA-Z0-9_]*::_*[a-zA-Z][a-zA-Z0-9_]*" *class*)))
                (re-search-forward (concat "^class " *namespace* "::" *class*) nil t)
              (re-search-forward (concat "^class " *class* "\\>") nil t))
            (beginning-of-line))
          (cbrow--message "Level 1")
          ;;(debug "Spencer")
          )))))

;;;
;;; control-n narrow to sexp
;;;
(defun cbrow--global--f5 ()
  (interactive)
  (let (line
        line2
        *namespace*
        *class*
        *method*
        result
        found
        namespace-class-method
        class-method
        class-only
        class-2
        method-only
        args
        method-args
        class-method-args-quoted
        namespace-ps
        class-ps
        method-ps)

    (if (not cbrow--init-done)
        (cbrow--init))

    (setq *namespace* (cbrow--inside-namespace))
    ;;(debug "Jing Jia")
    (setq cbrow--file  (buffer-file-name (current-buffer)))
    (setq cbrow--point (point))

    (if (eq major-mode 'c++-mode)
        ;; BEGIN SAVE-EXCURSION!
        (save-excursion
          ;;(setq line (cbrow--what-line))
          (setq namespace-ps (cbrow--inside-namespace-p1-and-p2))
          (setq class-ps     (cbrow--inside-class-p1-and-p2))
          (setq method-ps    (cbrow--inside-method-p1-and-p2))
          ;;(when (not (save-excursion
          ;;             (beginning-of-line)
          ;;             (looking-at (concat "\\(^\\|[ \t\r\n]+\\)"
            ;;                                 cbrow--inside-method--regexp
            ;;                                 ;;"[a-zA-Z0-9_<]+[> ]*[&*]*"
            ;;                                 ;;"\\(_*[a-zA-Z][a-zA-Z0-9_]*\\)::"
            ;;                                 ;;"\\(_*[a-zA-Z][a-zA-Z0-9_]*\\)"
            ;;                                 ))))
            ;;  ;;(setq found t)
            ;;  ;;(debug 123)
            ;;  )
            ;;(beginning-of-line)
            ;;(forward-line 2)
            (setq *method* (cbrow--inside-method))
            ;;(debug "Sausage Sandwiches")
            ;;(forward-sexp -1)
            ;;(setq *method* (cbrow--scan-method))
            (setq *class* (cbrow--inside-class))
            ;;(debug "Skimpy Skirts: *method*=%s" *method*)

            ;;(assert *method*)
            (when *method*

              (when (string-match (concat "\\(^\\|[ \t\r\n]\\)" cbrow--inside-method--regexp "(") *method*)
                (setq namespace-class-method (substring *method* (match-beginning 3) (match-end 3)))
                (when (string-match "\\(_*[a-zA-Z][a-zA-Z0-9_]*\\)::\\([~a-zA-Z0-9_]+\\)" *method*)
                  (setq class-method (concat (substring *method* (match-beginning 1) (match-end 2))))))

              (when (string-match "\\(^\\|[ \t\r\n]\\)\\(_*[a-zA-Z][a-zA-Z0-9_]*\\)::\\([~a-zA-Z0-9_]+\\)" *method*)
                (setq class-method (substring *method* (match-beginning 2) (match-end 3)))
                (setq class-only (substring *method* (match-beginning 2) (match-end 2))))

              (when (string-match "\\(_*[a-zA-Z][a-zA-Z0-9_]*::\\)\\([~a-zA-Z0-9_]+\\)" *method*)
                (setq method-only (substring *method* (match-beginning 2) (match-end 2))))

              ;;(if (and *class* (string-match "^_*[a-zA-Z][a-zA-Z0-9_]*::\\(_*[a-zA-Z][a-zA-Z0-9_]*\\)$" *class*))
              ;;    (setq class-only (substring *class* (match-beginning 1) (match-end 1)))
              ;;  (setq class-only *class*))

              ;;(debug "toilet paper")

              (when (and (not *class*) class-method (string-match "\\(_*[a-zA-Z][a-zA-Z0-9_]*\\)::" class-method))
                ;;(setq *class*    (substring class-method (match-beginning 1) (match-end 1)))
                (setq class-only (substring class-method (match-beginning 1) (match-end 1))))
              ;;(debug "Snake Oil")
              )

            ;;(debug "Middle of cbrow--global--f5")

            (cond
             ((save-excursion
                (beginning-of-line)
                (looking-at "^ *\\([A-Z]+ \\)*class _*[a-zA-Z][a-zA-Z0-9_]*"))
              (setq class-2 (cbrow--inside-class))
              (when (and class-2 456)
                ;;(debug "First cond in cbrow--global--f5")
                (cbrow--generate-browser class-2 'class)
                (goto-char (point-min))
                (re-search-forward "class " nil t)
                (beginning-of-line)
                ))

             (*method*
              (cond
               ((and *namespace*
                     *class*
                     (string-match (concat "\\(" *namespace* "\\)::\\(" *class* "\\)::\\(.*\\)(") *method*))
                (setq class-method (substring *method*
                                              (match-beginning 2)
                                              (match-end 3)))
                (setq method-only (substring *method*
                                             (match-beginning 2)
                                             (match-end 2))))
               ((and *class* (string-match (concat "\\(" *class* "\\)::\\(.*\\)(") *method*))
                (setq class-method (substring *method*
                                              (match-beginning 1)
                                              (match-end 2)))
                (setq method-only (substring *method*
                                             (match-beginning 2)
                                             (match-end 2))))
               ((string-match "\\(_*[a-zA-Z][a-zA-Z0-9_]*\\)::\\(_*[a-zA-Z][a-zA-Z0-9_]*\\)::\\([~a-zA-Z0-9_]+\\)(" *method*)
                (setq *namespace* (substring *method*
                                             (match-beginning 1)
                                             (match-end 1)))
                (setq *class* (substring *method*
                                         (match-beginning 1)
                                         (match-end 2)))
                (setq class-only (substring *method*
                                            (match-beginning 2)
                                            (match-end 2)))
                (setq class-method (substring *method*
                                              (match-beginning 1)
                                              (match-end 2)))
                (setq method-only (substring *method*
                                             (match-beginning 3)
                                             (match-end 3)))
                )
               ((string-match "\\(_*[a-zA-Z][a-zA-Z0-9_]*\\)::\\([~a-zA-Z0-9_]+\\)(" *method*)
                (setq *class* (concat *namespace*
                                      (substring *method*
                                                 (match-beginning 1)
                                                 (match-end 1))))
                (setq class-only (substring *method*
                                            (match-beginning 1)
                                            (match-end 1)))
                (setq class-method (substring *method*
                                              (match-beginning 1)
                                              (match-end 2)))
                (setq method-only (substring *method*
                                             (match-beginning 2)
                                             (match-end 2)))
                ))

              (when (string-match "(.*)" *method*)
                (setq args (substring *method*
                                      (match-beginning 0)
                                      (match-end 0)))
                (setq method-args (concat method-only args)))

              (when (and (not *class*) (not (string-match "\\(_*[a-zA-Z][a-zA-Z0-9_]*\\)::\\(_*[a-zA-Z][a-zA-Z0-9_]*\\)" *method*)))
                ;;(debug "Cannot find a class for a function")
                (cbrow--message "Cannot find a class for a function"))

              (if (and (not *class*) (string-match "\\(_*[a-zA-Z][a-zA-Z0-9_]*\\)::\\(_*[a-zA-Z][a-zA-Z0-9_]*\\)" *method*))
                  (setq *class* (substring *method* (match-beginning 1) (match-end 1))))

              (when *class*

                ;;(debug "Middle of cbrow--global--f5")

                (if 'cat (cbrow--generate-browser *class* 'class))
                (progn
                  (switch-to-buffer cbrow--buffer-name)
                  (goto-char (point-min))
                ;;(debug "Lancer")
                  (re-search-forward (if (= (aref method-only 0) ?~)
                                         (regexp-quote method-args)
                                       (concat "\\<" (regexp-quote method-args))))
                  (beginning-of-line)
                  )
                ;;(debug "Smells like teen spirit")
                )
              ;;(debug "Smell ya later")
              )

             ((setq class-2 (cbrow--inside-class))
              ;;(setq class-ps (cbrow--inside-class-p1-and-p2))
              ;;(setq line (cbrow--what-line))
              (if 456 (cbrow--generate-browser class-2 (cbrow--what-line)))
              ;;(debug "Valencia")
              ;;(switch-to-buffer cbrow--buffer-name)
              ;;              (goto-char (point-min))
              ;;              (setq found nil)
              ;;              (while (and (not found) (re-search-forward "//LINE:\\([0-9]+\\)" (cdr class-ps) t))
              ;;                (setq line-found (read-str (buffer-substring-no-properties (match-beginning 1) (match-end 1))))
              ;;                (if (= line-found line)
              ;;                    (setq found t)))
              ;;(debug "Feng shui")
              (setq found t)
              )
             (*class*
              ;;(debug "Tomato")
              ;;(setq line (cbrow--what-line))
              (if 789 (cbrow--generate-browser (if *namespace*
                                                   (concat *namespace* "::" class-only)
                                                 *class*) 'class))
              (switch-to-buffer cbrow--buffer-name)
              (goto-line (point-min))
              (re-search-forward "^class" nil t)
              (forward-line 2)
              (re-search-forward method-only nil t)
              (beginning-of-line)
              (debug "sausages")
              ;;(switch-to-buffer cbrow--buffer-name)
              ;;(goto-char (point-min))
              ;;(re-search-forward (concat "\\<" method-only "(") nil t)
              ;;(beginning-of-line)
              ;;(set-buffer cbrow--buffer)
              ;;(d-beeps "line=%s" line)
              ;;(goto-char (point-min))
              ;;(debug "789")
              )
             ;;(t
             ;; (find-file cbrow--file)
             ;; (goto-char cbrow--point))
             (t
              ;;(error "cbrow--global--f5: Not inside a *class* or inside an outer *method*")
              ;;(debug "Melon")
              ;;(debug "123")
              ;;(switch-to-buffer cbrow--buffer-name)
              (setq result (cbrow--inside-method))
              (when (string-match "^\\(_*[a-zA-Z][a-zA-Z0-9_]*\\)::\\([a-zA-Z0-9]+\\)::\\(_*[a-zA-Z][a-zA-Z0-9_]*\\)$" result)
                (setq *namespace* (substring result (match-beginning 1) (match-end 1)))
                (setq *class*     (substring result (match-beginning 2) (match-end 2)))
                (setq *method*    (substring result (match-beginning 3) (match-end 3)))
                )
              (when (string-match "^\\([a-zA-Z0-9]+\\)::\\(_*[a-zA-Z][a-zA-Z0-9_]*\\)$" result)
                (setq *class*     (substring result (match-beginning 1) (match-end 1)))
                (setq *method*    (substring result (match-beginning 2) (match-end 2)))
                )
              (when (and *class* *method*)
                (set-buffer (find-file (cadr (assoc *class* cbrow--header-alist))))
                (setq meth (cbrow--trim-return-value *method*))
                (re-search-forward meth nil t)
                (beginning-of-line)
                (if 1230 (cbrow--generate-browser *class* meth))
                (debug "Tom Clancy")
                )
              )
             )
            )
      ;; END SAVE-EXCURSION!
      (if 123 (cbrow--map1--f5))
      ;;(debug "Roger Dodger")
      )))

;; (assoc "Dipper" cbrow--header-alist)
(defun cbrow--map1--enter ()
  (interactive)
  (let (*class* class-only *namespace* file line)
    (setq *class*     (cbrow--inside-class))
    (setq *namespace* (cbrow--inside-namespace))
    ;;(debug "Hairy Tomato")
    (d-quote if (save-excursion
                  (re-search-forward "//LINE:" (point-at-eol) t))
             (setq line (save-excursion
                          (re-search-forward "//LINE:\\([0-9]+\\)" (point-at-eol) t)
                          (read-str (buffer-substring-no-properties (match-beginning 1) (match-end 1))))))
    ;; BEGIN COND!
    (cond
     ((save-excursion
        (beginning-of-line)
        (looking-at "^\\(SUPERCLASS\\|SUBCLASS\\): "))
      ;;(debug "Ratipo")
      (save-excursion
        ;;(d-beeps "Foomatic")
        (beginning-of-line)
        (skip-chars-forward "A-Z") ;;; skip SUPERCLASS or SUBCLASS
        (skip-chars-forward ":")
        (skip-chars-forward " \t")
        (setq *class* (buffer-substring-no-properties (point) (save-excursion
                                                              (skip-chars-forward (concat cbrow--identifier--chars ":"))
                                                              (point))))
        (if (string-match "^_*[a-zA-Z][a-zA-Z0-9_]*::\\(_*[a-zA-Z][a-zA-Z0-9_]*\\)$" *class*)
            (setq class-only (substring *class* (match-beginning 1) (match-end 1))))

        (setq file (cadr (assoc *class* cbrow--header-alist)))
        (if file
            (cbrow--generate-browser *class* 'class)
          (setq file (cadr (assoc class-only cbrow--header-alist)))
          (if file
              (cbrow--generate-browser class-only 'class)
            (if 'nerd (error "No header file for class %s" *class*))))
        ;;(debug "Smeg")
        ;;(debug "Salami")
        ;;(message *class*)
        ))

     ((save-excursion
        (re-search-forward "=[ \t]*null;" (point-at-eol) t))
      (cbrow--message "Cannot browse a pure virtual function"))

     ((save-excursion
        (re-search-forward "NOT HERE!" (point-at-eol) t))
      (let ((method                 nil)
            (method-signature       nil)
            (method-only            nil)
            (class-method           nil)
            (namespace-class-method nil)
            (class-only             nil)
            (file                   nil))
        (progn
          (setq method-signature (cbrow--trim-string (cbrow--current-line-as-string)))
          ;;(setq method (cbrow--inside-method))

          (if (string-match "\\(operator[ \t]+[^;]+\\)[ \t](" method-signature)
              (setq method-only (substring method-signature (match-beginning 1) (match-end 1)))

            (assert (string-match "\\([^ ]*\\)(" method-signature))
            (setq method-only (substring method-signature
                                         (match-beginning 1)
                                         (match-end 1)))

            (assert *class*)

            (setq method (concat *class* "::" method-only))

            ;;(if (string-match "\\(_*[a-zA-Z][a-zA-Z0-9_]*\\)" *class*)
            ;;    (setq class-only (substring *class* (match-beginning 1) (match-end 1))))

            (when (string-match "\\(_*[a-zA-Z][a-zA-Z0-9_]*::\\)?\\(_*[a-zA-Z][a-zA-Z0-9_]*\\)" *class*)
              (setq class-only (substring *class* (match-beginning 2) (match-end 2)))
              ;;(setq *class* class-only)
              )

            (setq class-method (concat class-only "::" method-only))
            (if *namespace*
                (setq namespace-class-method (concat *namespace* *class* "::" method-only))
              (setq namespace-class-method class-method))

            (progn
              ;;(kill-buffer)
              (setq file (cadr (assoc (if *namespace* (concat *namespace* "::" class-only) *class*)
                                      cbrow--header-alist)))
              (if (cbrow--find-file file *class*)
                  ;;(debug "Found here")
                'foo
                (setq file (cadr (assoc (if *namespace* (concat *namespace* "::" class-only) class-only)
                                        cbrow--footer-alist))))
              ;;(debug "file=%s" file)
              (when (not (cbrow--find-file file *class*))
                (d-beeps "Tags file search")
                (if (string-match "\\(friend\\|operator\\)" method-signature)
                    (tags-search method-only)
                  (tags-search class-method))
                (beginning-of-line)))))))

     ((save-excursion
        (re-search-forward "//LINE:" (point-at-eol) t))
      (let ((what-line nil)
            (file      nil))
        (save-excursion
          (re-search-forward "//LINE:" (point-at-eol) t)
          (setq what-line (read (buffer-substring-no-properties (point)
                                                                (save-excursion
                                                                  (skip-chars-forward "0-9")
                                                                  (point)))))
          (setq file (cadr (assoc *class* cbrow--header-alist)))
          ;;(debug)
          )

        (if (not file)
            (if 123 (error "Variable file is nil")))

        (if (not (file-exists-p file))
            (if 456 (error "Header file %s for class %s does not exist" file *class*)))

        (if 'ibm-computers (find-file file))
        (goto-line what-line)
        (recenter)
        (message "Here it is in the header file")
        (read-only-mode -1)
        ))

     (t
      (beep)
      )
     )
    ;; END COND!
    )
  )

(defun cbrow--find-file (file *class*)
  (let ((found           nil)
        (found-namespace nil)
        (*namespace*     nil)
        ;;args
        ;;namespace-only
        ;;class-only
        ;;class-method
        ;;class-method-args
        ;;class-method-args-quoted
        line
        line2)
    ;;(debug "Rocket fuel")
    ;; BEGIN COND!
    (cond
     ((not file)
      (setq found nil))
     ((not (file-exists-p file))
      (setq found nil))
     ((progn
        (find-file file)
        (goto-char (point-min))
        ;;(debug "Challenger")

        (when (string-match "([^()]*)" method-signature)
          (setq args (substring method-signature (match-beginning 0) (match-end 0)))
          (setq args (cbrow--change-args args))
          )

        (when (string-match "\\(_*[a-zA-Z][a-zA-Z0-9_]*\\)::\\(_*[a-zA-Z][a-zA-Z0-9_]*\\)" *class*)
          (setq namespace-only (substring *class* (match-beginning 1) (match-end 1)))
          (setq class-only     (substring *class* (match-beginning 2) (match-end 2)))
          )

        (setq class-method             (concat (if class-only (concat class-only "::")) method-only))
        (setq class-method-args        (concat (if class-only (concat class-only "::")) method-only args))
        (setq class-method-args-quoted (regexp-quote class-method-args))

        ;; BEGIN COND!
        (cond
         ((string= method-only class-only)
          ;;
          ;; NOTE: it's a constructor!
          ;;
          ;;(debug "It's a ctor!")
          (while (and (not found) (re-search-forward (concat class-method "(") nil t))
            ;;(beginning-of-line)
            (setq line  (cbrow--scan-method))
            (setq line2 (cbrow--trim-return-value line))
            (when (string-match "([^()]*)" method-signature)
              (setq args (substring method-signature (match-beginning 0) (match-end 0)))
              (setq args (cbrow--change-args args))
              )
            (when (string-match class-method-args-quoted line2)
              ;;(debug "Found is true")
              (setq found t)))
          (beginning-of-line)
          ;;(debug "It's a ctor!")
          found)

         ((eq (aref method-only 0) ?~)
          ;;
          ;; NOTE: it's a destructor!
          ;;
          (re-search-forward (concat class-method "("))
          (beginning-of-line)
          ;;(debug "It's a dtor!")
          (setq found t)
          )

         (t
          ;;
          ;; NOTE: just a method!
          ;;
          ;;(debug "Stay at home dad")
          (progn
            (setq found nil)
            ;;(if (string-match "\\.ch$" file) (debug "Hole in one"))
            ;;(debug "Middle of cbrow--find-file")
            (while (and (not found) (re-search-forward (concat class-method "(") nil t))
              (setq line (cbrow--scan-method))
              (setq line (cbrow--trim-return-value line))
              ;;(cbrow--trim-return-value "   int*** function()")
              ;;(debug "toilet seat")
              (setq found-namespace t)
              (beginning-of-line)
              (if (progn
                    (beginning-of-line)
                    (re-search-forward (concat *namespace* "::") (point-at-eol) t))
                  (setq found-namespace t)
                (setq found-namespace nil))
              (when (string= *namespace* (cbrow--inside-namespace))
                (setq found-namespace t))
              (if (not found-namespace) (debug "Anchor milk"))
              (when found-namespace
                ;;(if (/= (aref line2 (1- (length line2))) ?\;)
                ;;    (setq line2 (concat line2 ";")))
                ;;(setq line (cbrow--trim-return-value line))
                ;;(if (string-match (concat "^" (regexp-quote "Bar::function(int***);") "$") line2)
                ;;(if (string= "Bar::function(int***);" line2) )
                (when (string-match class-method-args-quoted line)
                  ;;(debug "Found is true")
                  (setq found t))))
            ;;(debug "It's the spitz")
            (beginning-of-line))))
        ;; END COND!
        )))
    ;; END COND!
    (if (not found)
        (kill-buffer)
      ;;(d-beeps "Here it is in file %s" file)
      (message "Here it is in file %s" file))
    ;;(debug "Not found")
    found))

(defun cbrow--map1--f5 ()
  (interactive)
  (let* ((list    nil)
         (ptr     cbrow--header-alist)
         (*class* (cbrow--inside-class))
         (result  nil))
    ;;(debug "Tiger Woods")
    (assert (boundp '*class*))
    (while ptr
      (setq list (cons (caar ptr) list))
      (setq ptr (cdr ptr)))
    ;;(debug "Smegulator")
    (progn
      (if (get-buffer cbrow--buffer-name)
          (kill-buffer cbrow--buffer-name))
      ;;(debug "Hole in one")
      (switch-to-buffer (generate-new-buffer cbrow--buffer-name))
      (c++-mode)
      ;;(setq list (reverse list))
      ;;(setq list (cbrow--bubble-sort list 'cbrow--less-than))
      (cbrow--level--begin-or-end 2 "BEGIN" nil)
      (setq ptr list)
      (while ptr
        (goto-char (point-max))

        (let (class)
          ;; NOTE: adds <T> to class spec
          (setq class (car ptr))
          ;;(if (string-match "Xyd_A" *class*) (debug "Tomato soup"))
          (setq *template* (cadr (assoc class cbrow--template-list))))

        (let* ((c (car ptr))
               (r (cadr (assoc c cbrow--rest-alist))))
          (insert (concat "class " (if *template* *template* c)))
          (insert (if r (concat " : " r "\n") "\n"))
          ;;(if (string-match "\\(dmp::\\)?Reader$" c)
          ;;    (debug "Ten pin bowling"))
          ;;(debug)
          ;;(if (cadr (assoc c cbrow--rest-alist))
          ;;(insert (cadr (assoc c cbrow--rest-alist)))
          )
        (backward-delete-char 1)
        (insert "\n")
        (setq ptr (cdr ptr)))

      (let ((sort-fold-case t))
        (sort-lines nil (save-excursion (goto-char (point-min))
                                        (re-search-forward "class" nil t)
                                        (forward-line -1)
                                        (point)) (point-max))
        ;;(debug "Carroty")
        )

      (cbrow--level--begin-or-end 2 "END" nil)
      ;;(save-excursion (goto-char (point-max)) (re-search-backward "////" nil t) (point)))
      ;;(goto-char (point-min))
      ;;(goto-char (point-max))

      (goto-char (point-min))
      (re-search-forward "class")
      ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
      ;;;
      ;;; Here is how to do a condition-case statement:
      ;;;
      ;;;      (condition-case nil
      ;;;          (error "smeg")
      ;;;        (error (setq i "ren")))
      ;;;
      ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
      ;;;
      ;;; TODO: condition-case here
      ;;;
      ;;(debug "Viagra")
      (if (not *class*)
          (progn
            (cbrow--message "Class is nil")
            ;;(debug "Helicopter")
            )
        (if (string-match (concat "^" *namespace* "::") *class*)
            (setq result *class*)
          (setq result (concat (if *namespace* (concat *namespace* "::")) *class*)))

        (goto-char (point-min))
        (let ((search (concat "class[ \t]+" result "\\([ \t<>]\\|$\\)")))
          (if (not (re-search-forward search nil t))
              (error (format "*** Cbrow Search failed: %s" *class*))
            (cbrow--message "Level 2"))))

      (beginning-of-line)
      (use-local-map cbrow--map2)
      (read-only-mode 1)
      ;;(debug "Foomatic")
      ))
  )

(defun cbrow--map2--enter ()
  (interactive)
  (save-excursion
    (let (*class* class-only)
      (beginning-of-line)
      (cbrow--skip-word "class")
      (skip-chars-forward " \t")
      (cond
       ((looking-at "\\(_*[a-zA-Z][a-zA-Z0-9_]*\\)::\\(_*[a-zA-Z][a-zA-Z0-9_]*\\)")
        (setq *namespace* (buffer-substring-no-properties
                           (match-beginning 1)
                           (match-end 1)))
        (setq *class* (buffer-substring-no-properties
                     (match-beginning 1)
                     (match-end 2)))
        (setq class-only (buffer-substring-no-properties
                          (match-beginning 2)
                          (match-end 2))))
      ((looking-at "\\(_*[a-zA-Z][a-zA-Z0-9_]*\\)")
       (setq *class* (buffer-substring-no-properties (match-beginning 1)
                                                   (match-end 1))))
      )
      ;;(setq file (cadr (assoc *class* cbrow--header-alist)))
      ;;(if (string-match "[a-z]::\\(_*[a-zA-Z][a-zA-Z0-9_]*\\)" *class*)
      ;;    (setq *class* (substring *class* (match-beginning 1) (match-end 1))))
      ;;(debug "Splatter film")
      (if 'banana (cbrow--generate-browser ;;(if *namespace* (concat *namespace* *class*) *class*)
                   *class*
                   'class))
      ;;(debug "Suzy Salmon")
      ;;(message class)
      )
    )
  )

(defun cbrow--map2--f5 ()
  (interactive)
  ;;(bury-buffer)
  (if (not cbrow--file)
      (bury-buffer)
    (find-file cbrow--file)
    (goto-char cbrow--point))
  (cbrow--message "Back to editing")
  ;;(d-beeps "Can't go back any further")
  )

(defvar cbrow--map1 (make-keymap))
(define-key cbrow--map1 "\C-m" 'cbrow--map1--enter)
(define-key cbrow--map1 [f5]   'cbrow--map1--f5)
(global-set-key [f5] 'cbrow--global--f5)

(defvar cbrow--map2 (make-keymap))
(define-key cbrow--map2 "\C-m" 'cbrow--map2--enter)
(define-key cbrow--map2 [f5]   'cbrow--map2--f5)

;; (setq list '("abc" "def" "abc" "def" "zed"))
;; (setq list (delete-duplicates list :test 'string=))
;; (cbrow--init--header-alist)
(defun cbrow--init--header-alist ()
  (let* ((search-list (reverse cbrow--headers))
         (ptr         search-list))
    (setq cbrow--header-alist nil)
    (setq cbrow--template-list nil)
    (while ptr

      ;;(if (string= (car ptr) "~/zallegro/2005/dd/mesh.cc")

      ;;
      ;; NOTE: loads it in fundamental mode if not already in memory,
      ;; else keeps it in the current mode...
      ;;
      (let ((auto-mode-alist (cons '("" . fundamental-mode) auto-mode-alist)))
      ;; NOTE: safe to kill the buffer as it has been saved and from now on it is read-only
        (save-buffer (find-file-read-only (car ptr))))

      ;;(debug "Phlegm")

      (let ((class-list nil))
        (goto-char (point-min))
        (while (re-search-forward "^[ ][ ][ ]\\([A-Z]+[ \t]+\\)?class" nil t)
          ;;(debug "Xenophobe")
          (if (setq *namespace* (cbrow--inside-namespace))
              (when (progn
                      (forward-line 1)
                      (looking-at "^[ ][ ][ ]{"))
                (forward-line -1)
                ;;(debug "Point max")
                (skip-chars-forward " \t")
                (skip-chars-forward "A-Z")
                (skip-chars-forward " \t")
                (cbrow--skip-word "class")
                (skip-chars-forward " \t")
                ;;(debug "Hot tamale")
                ;;(if (string= (buffer-name) "string.hh")
                ;;    (debug "Plaster board"))
                (let ((*class* (buffer-substring-no-properties
                                   (point) (save-excursion
                                             (skip-chars-forward (concat cbrow--identifier--chars ":"))
                                             (point))))
                      (template (buffer-substring-no-properties
                                 (save-excursion
                                   (forward-line -1)
                                   (beginning-of-line)
                                   (point))
                                 (save-excursion
                                   (forward-line -1)
                                   (end-of-line)
                                   (point)))))
                  ;;(if (string-match "Vector" *class*)
                  ;;    (debug "found Vector_2d_Cartesian<T>"))
                  (if (string-match "template<class \\(_*[a-zA-Z][a-zA-Z0-9_]*\\)>" template)
                      (progn
                        ;;(debug "Found template")
                        (setq template (concat *class*
                                               "<"
                                               (substring template (match-beginning 1) (match-end 1))
                                               ">")))
                    (setq template nil))
                  (setq cbrow--template-list (cons (list *class* template) cbrow--template-list))
                  ;;(debug "Splatter gun")
                  (setq class-list (cons (concat (if *namespace* (concat *namespace* "::"))
                                                 *class*) class-list))))))
        ;; END WHILE!
        (goto-char (point-min))
        (while (re-search-forward "^\\([A-Z]+[ \t]+\\)?class" nil t)
          (when (progn
                  (forward-line 1)
                  (looking-at "^{"))
            (forward-line -1)
            (skip-chars-forward "A-Z")
            (skip-chars-forward " \t")
            (cbrow--skip-word "class")
            (skip-chars-forward " \t")
            (let ((class-only (buffer-substring-no-properties
                               (point) (save-excursion
                                         (skip-chars-forward (concat cbrow--identifier--chars ":"))
                                         (point))))
                  (template (buffer-substring-no-properties
                             (save-excursion
                               (forward-line -1)
                               (beginning-of-line)
                               (point))
                             (save-excursion
                               (forward-line -1)
                               (end-of-line)
                               (point)))))
                  ;;(if (string-match "Vector" class-only)
                  ;;    (debug "found Vector_2d_Cartesian<T>"))
                  (if (string-match "template<class \\(_*[a-zA-Z][a-zA-Z0-9_]*\\)>" template)
                      (progn
                        ;;(debug "Found template")
                        (setq template (concat class-only
                                               "<"
                                               (substring template (match-beginning 1) (match-end 1))
                                               ">")))
                    (setq template nil))
                  (setq cbrow--template-list (cons (list class-only template) cbrow--template-list))

                  ;;(if (not (string-match "_*[a-zA-Z][a-zA-Z0-9_]*\\(::_*[a-zA-Z][a-zA-Z0-9_]*\\)" *class*))
                  ;;    (setq *class* (concat "::" *class*)))
                  ;;(setq *class* (substring *class* (match-beginning 1) (match-end 1))))
                  ;;(debug "Zip skip")
                  (setq class-list (cons class-only class-list))
                  )))
        ;; END WHILE!
        ;;(setq class-list (reverse class-list))
        (let ((ptr2 class-list))
          (setq ptr2 class-list)
          (while ptr2
            (setq cbrow--header-alist (cons (list (car ptr2) (car ptr)) cbrow--header-alist))
            ;; (assoc "A1" cbrow--header-alist)
            (setq ptr2 (cdr ptr2)))))
      ;;(setq class-list (delete-duplicates class-list :test 'string=))
      (kill-buffer (find-file (car ptr)))
      (setq ptr (cdr ptr)))
    cbrow--header-alist)
  )
;;(cbrow--init--header-alist)

;;(cbrow--init--footer-alist)
(defun cbrow--init--footer-alist ()
  ;;(setq ptr cbrow--header-alist)
  ;;(setq header-file (cadar ptr))
  ;;(setq footer-file (concat (substring header-file (match-beginning 1) (match-end 1)) cbrow--footer-regexp))
  (let ((ptr cbrow--header-alist))
    (setq cbrow--footer-alist nil)
    (while ptr
      (let ((*class*       (caar ptr))
            (header-file (cadar ptr)))
        (if (string-match "^\\(.*\\)\\.hh$" header-file)
          (let ((footer-file (concat (substring header-file (match-beginning 1) (match-end 1)) cbrow--footer)))
            (setq cbrow--footer-alist (cons (list *class* footer-file) cbrow--footer-alist))))
        ;;(insert (prin1-to-string (car ptr)))
        (setq ptr (cdr ptr))))
    (setq cbrow--footer-alist (reverse cbrow--footer-alist))
    )
  )
;; (cbrow--init--footer-alist)
;; (cbrow--split-string (setq string " public A1 , A2 "))
;; (cbrow--split-string (setq string " public A1 , A2"))
;; (cbrow--split-string (setq string "public A1 , A2"))
;; (cbrow--split-string (setq string "abc def , hif"))
;; (cbrow--split-string (setq string "abc , def"))
;; (cbrow--split-string (setq string " public A1 , A2 , private A3, A4"))
;; (cbrow--split-string (setq string "public Public1 , Public2, private Private1, Private2"))

(defun cbrow--split-string (string)
  (let* ((string      (format "%s%c" string ? ))
         (len         (length string))
         (i           0)
         (buf         "")
         (answer-list nil))
    (while (< i len)
      (let ((ch (aref string i)))
        (if (and (not (= ch ? ))
                 (not (= ch ?\t))
                 (not (= ch ?,)))
            (setq buf (format "%s%c" buf ch))
          (setq answer-list (cons buf answer-list))
          (setq buf "")))
      (incf i))
    ;; NOTE: remove crud from list
    ;; (setq answer-list '("public" "abc" "" "def"))
    (setq answer-list (delete "" answer-list))
    (setq answer-list (delete "public" answer-list))
    (setq answer-list (delete "private" answer-list))
    (setq answer-list (delete "protected" answer-list))
    (reverse answer-list)
    )
  )

;; (setq ptr (list (assoc "A" cbrow--header-alist)))
;; cbrow--superclass-alist
;; (cbrow--init--superclass-alist)
(defun cbrow--init--superclass-alist ()
  (let ((ptr cbrow--header-alist))
    (setq cbrow--superclass-alist nil)
    (setq cbrow--rest-alist nil)
    (while ptr
      (let ((*class*      (caar ptr))
            (file         (cadar ptr))
            (rest         nil)
            (superclasses nil)
            (class-only   nil))
        (if (string-match "\\(<[a-zA-Z0-9]+>\\)" *class*)
            (setq *class* (substring *class* 0 (match-beginning 0))))
        (if (string-match "^[a-zA-Z0-9_]*::\\(_*[a-zA-Z][a-zA-Z0-9_]*\\)$" *class*)
            (setq class-only (substring *class* (match-beginning 1) (match-end 1)))
          (setq class-only *class*))
        (save-excursion
          (let ((auto-mode-alist (cons '("" . fundamental-mode) auto-mode-alist)))
            (save-buffer (find-file-read-only file))) ;;; allows us to safely kill the buffer
          (goto-char (point-min))
          ;;(debug "Viagra")
          (cond
           ;;((re-search-forward (concat "^\\([A-Z]+[ \t]+\\)*class[ \t]+" class-only "\\($\\|[ \t]*$\\)") nil t)
           ;; (beginning-of-line)
           ;; (forward-line 1)
           ;; (assert (looking-at "^[ \t]*{"))
           ;; (forward-line -1)
           ;; )
           ((re-search-forward (concat "^\\([A-Z]+[ \t]+\\)?class[ \t]+" class-only "\\($\\|[ \t][^;\n\r]*$\\)") nil t)
            (beginning-of-line)
            (forward-line 1)
            (assert (looking-at "{"))
            (forward-line -1))
           ((re-search-forward (concat "^   \\([A-Z]+[ \t]+\\)?class[ \t]+" class-only "\\($\\|[ \t][^\n\r;]*$\\)") nil t)
            (beginning-of-line)
            (forward-line 1)
            (skip-chars-forward " \t")
            (if 123 (assert (looking-at "{")))
            (forward-line -1)
            (beginning-of-line)
            ;;(Debug "Everest")
            )
           ((re-search-forward (concat "^\\([A-Z]+[ \t]+\\)?class[ \t]+" *class* "\\($\\|[ \t][^;\n\r]*$\\)") nil t)
            (beginning-of-line)
            (forward-line 1)
            (assert (looking-at "{"))
            (forward-line -1))
           ((re-search-forward (concat "^   \\([A-Z]+[ \t]+\\)?class[ \t]+" *class* "\\($\\|[ \t][^\n\r;]*$\\)") nil t)
            (beginning-of-line)
            (forward-line 1)
            (skip-chars-forward " \t")
            (if 123 (assert (looking-at "{")))
            (forward-line -1)
            (beginning-of-line)
            ;;(Debug "Everest")
            )
           (t
            (error "(123) Class %s not found in file %s" *class* file)))
          (skip-chars-forward " \t")
          (skip-chars-forward "A-Z")
          (skip-chars-forward " \t")

          ;;(if (string= *class* "Writer")
          ;;    (debug "Smegulator"))

          (assert (looking-at "class"))
          (cbrow--skip-word "class")
          (skip-chars-forward " \t")
          (assert (looking-at "\\(\\(_*[a-zA-Z][a-zA-Z0-9_]*::\\)?\\(_*[a-zA-Z][a-zA-Z0-9_]*\\)\\)"))
          ;;(setq *class* (buffer-substring-no-properties (match-beginning 1) (match-end 1)))
          (skip-chars-forward "a-zA-Z0-9_:")
          (if (re-search-forward ":" (point-at-eol) t)
              (progn
                (setq *namespace* (cbrow--inside-namespace))
                (skip-chars-forward " \t")
                (let* ((rest         (buffer-substring-no-properties (point) (point-at-eol)))
                       (superclasses (cbrow--split-string rest)))

                  ;;(debug "Spagetti")
                  (defun add-prefix (x)
                    (concat (if *namespace* (concat *namespace* "::")) x))
                  (setq superclasses (mapcar 'add-prefix superclasses))

                  ;;(if (string-match "public" rest) (debug "Watermelon"))

                  ;;                  (while (string-match "\\(public\\|private\\|protected\\) " rest)
                  ;;                    (setq rest (concat (substring rest 0 (match-beginning 1))
                  ;;                                       (substring rest (match-beginning 1) (match-end 1))
                  ;;                                       (if *namespace* (concat *namespace* "::"))
                  ;;                                       (substring rest (match-end 0)))))
                  ;;
                  ;;                  (while (string-match (concat "\\(public\\|private\\|protected\\)"
                  ;;                                               (if *namespace*
                  ;;                                                   (concat "\\(" *namespace* "::\\)")
                  ;;                                                 "\\([a-zA-Z0-9_]\\)")) rest)
                  ;;                    (setq rest (concat (substring rest 0 (match-end 1))
                  ;;                                       " ";; (if *namespace* (concat *namespace* "::"))
                  ;;                                       (substring rest (match-beginning 2)))))
                  (setq cbrow--superclass-alist (cons (cons *class* superclasses) cbrow--superclass-alist))
                  ;;(debug)
                  (setq cbrow--rest-alist (cons (list *class* rest) cbrow--rest-alist))
                  ;;(if (or (string= "Reader" *class*) (string= "Reader" class-only))
                  ;;(if (string-match "^::_*[a-zA-Z][a-zA-Z0-9_]*" *class*)
                  ;;(if (string-match "dmp::string" rest)
                  ;;  (debug "Cactus"))
                  )
                )
            ;;(setq cbrow--rest-alist (cons (list *class* "") cbrow--rest-alist))
            )
          (kill-buffer (find-file file))
          ))
      (setq ptr (cdr ptr))))
  )

;;; Cbrow--subclass-alist
;;; (cbrow--init--subclass-alist)
(defun cbrow--init--subclass-alist ()
  (let ((ptr cbrow--superclass-alist))
    (setq cbrow--subclass-alist nil)
    (while ptr
      (let ((ptr2     nil)
            (subclass nil))
        (setq ptr2 (car ptr))      ;;; set first element
        (setq subclass (car ptr2))
        (setq ptr2 (cdr ptr2))     ;;; skip over first element
        (while ptr2
          (let* ((superclass (car ptr2))
                 (a          (assoc superclass cbrow--subclass-alist)))
            ;;(insert superclass " has subclass " subclass "\n")
            ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
            (if (not a)
                (setq cbrow--subclass-alist (cons (list superclass subclass)
                                                  cbrow--subclass-alist))
              (setcdr (last a) (list subclass))))
            ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
          (setq ptr2 (cdr ptr2))))
      (setq ptr (cdr ptr))))
  )

(defvar cbrow--footer ".cc")
(defvar cbrow--init-done nil)

(defun cbrow--init ()
  (interactive)
  (let (list1 list2 list3 list4 list5)
    (setq list1 (directory-files "~/lisp++-projects/2006/Tritus-II/"      t "\\.hh$"))
    (setq list2 (directory-files "~/lisp++-projects/2006/Tritus-II/level-editor/" t "\\.hh$"))
    (setq list3 (directory-files "~/lisp++-projects/2006/gui-menus/"      t "\\.hh$"))
    (setq list4 (directory-files "~/lisp++-projects/2006/gui-widgets/"    t "\\.hh$"))
    (setq list5 (directory-files "~/lisp++-projects/2006/libd/"           t "\\.hh$"))
    (setq cbrow--headers (append list1 list2 list3 list4 list5)))

  (cbrow--init--header-alist)     ;;; cbrow--header-alist
  (cbrow--init--footer-alist)     ;;; cbrow--footer-alist
  (cbrow--init--superclass-alist) ;;; cbrow--superclass-alist
  (cbrow--init--subclass-alist)   ;;; cbrow--subclass-alist
  (setq cbrow--init-done t)
  (message "cbrow--init done")
  )

;;(cbrow--init)

(provide 'cbrow)
;;; cbrow.el ends here
