
(require 'find-in-files (elisp-start-file "find-in-files"))
;; Make some code for switching between a .c and .h file
(defvar c-header-extensions (list "hpp" "h" "hh" "hx" "hxx" "H"))
(defvar c-code-extensions (list "c" "C" "cc" "cpp" "cxx" "tcc"))

(defun c-file-without-extension (file-name)
  (let ((index (string-match "\\(.*\\)\\.[^\\.]*$" file-name)))
    (if index
        (match-string 1 file-name)
      nil)))
(defun c-file-others-extensions (file-name)
  (let ((noext (c-file-without-extension file-name))
        (type (c-guess-file-type file-name)))
    (let ((extlist (cond 
                    ((eq type 'code) c-header-extensions)
                    ((eq type 'header) c-code-extensions)
                    (t nil))))
      (mapcar (lambda (e) (concat noext "." e)) extlist))))

(defun c-guess-file-type (file-name)
  (let ((file-type nil))
    (mapcar 
     (lambda (e)
       (if (string-match (concat "\\." e "\\'") file-name)
           (setq file-type 'header)))
     c-header-extensions)
    (mapcar 
     (lambda (e)
       (if (string-match (concat "\\." e "\\'") file-name)
           (setq file-type 'code)))
     c-code-extensions)
    file-type))

(defun c-file-open-other (&optional other-window buffer)
  "Opens the .c or .h (calculated from c-header-extensions and c-code-extensions) corresponding to the BUFFER (or current buffer)"
  (interactive)
  (let ((file-name (buffer-file-name buffer)))
    (let ((candidates (c-file-others-extensions file-name))
          (selected nil))
      (mapcar
       (lambda (e)
         (if (file-exists-p e)
             (setq selected e)))
       (nreverse candidates))
      (if selected
          (if other-window
              (find-file-other-window selected)
            (find-file selected))
        (progn 
          (message "No file corresponds to %s" file-name)
          nil)))))

(defun c-file-buffer-other (&optional other-window file-name)
  "Try to find a buffer corresponding to this one"
  (interactive)
  (let ((file-name (file-name-nondirectory (buffer-file-name))))
    (let ((candidates (c-file-others-extensions file-name))
          (selected nil))
      (save-excursion
        (mapcar
         (lambda (e)
           (let ((buffer (get-buffer e)))
             (if buffer 
                 (setq selected e))))
         (nreverse candidates)))
      (if selected
          (if other-window
              (switch-to-buffer-other-window selected)
            (switch-to-buffer selected))
        nil))))

(defun c-open-other (&optional other-window file-name)
  (interactive)
  (or (c-file-buffer-other other-window file-name)
      (c-file-open-other other-window file-name)))

(defun c-list-file-type (type dir)
  (let ((files (directory-files dir))
        (result nil))
    (while files
      (let* ((f (car files))
             (path (concat dir "/" f)))
        (message "guess %s: %s" path (c-guess-file-type path))
        (if (and (file-readable-p path)
                 (eq (c-guess-file-type path) type))
            (setq result (cons (concat dir "/" f) result))))
      (setq files (cdr files)))
    (nreverse result)))
(defun c-insert-type (type dir-name)
  (mapcar 
   (lambda (f) (insert (concat "  " f " \\\n")))
   (c-list-file-type 'code dir-name)))
(defun c-insert-sources (dir-name)
  (interactive "*D")
  (c-insert-type 'code (or dir-name ".")))
(defun c-insert-headers (dir-name)
  (interactive "*D")
  (c-insert-type 'header (or dir-name ".")))
(defun c-list-headers (&optional dir-name)
  (interactive "*D")
  (c-list-file-type 'header (or dir-name ".")))

(eval-after-load
    "cc-mode"
  '(progn
     (define-key c-mode-base-map [C-f6] 'c-open-other)
     (define-key c-mode-base-map [C-S-f6] 
       '(lambda nil (interactive) (c-open-other t)))))
(mapcar 
 (lambda (ext)
   (add-to-list 'auto-mode-alist `(,(concat "\\." ext "\\'") . c++-mode)))
 (append c-header-extensions c-code-extensions))

