
(defvar pov-mode-syntax-table
  (make-syntax-table c++-mode-syntax-table)
  )
;;    (modify-syntax-entry ?*  "<" pov-mode-syntax-table)
;;    (modify-syntax-entry ?\n  ">" pov-mode-syntax-table)
;;    (setq font-lock-comment-start-regexp "^\\*" pov-mode-syntax-table)
(modify-syntax-entry ?<  "(>" pov-mode-syntax-table)
;;    (modify-syntax-entry ??  "/" pov-mode-syntax-table)
(modify-syntax-entry ?>  ")>" pov-mode-syntax-table)
(defvar pov-mode-map (make-keymap))

(define-key pov-mode-map [f1] 'pov-help)

(define-key pov-mode-map [f9]
  (function
   (lambda () (interactive)
     (save-some-buffers 'NO-QUESTIONS)
     (save-window-excursion
       (goto-char (point-min))
       (re-search-forward "^\\s-*(progn")
       (beginning-of-line)
      (let ((command (buffer-substring-no-properties (point)
                                                     (save-excursion
                                                       (forward-sexp 1)
                                                       (point)))))
        (eval (read command)))))))

(define-key pov-mode-map "\C-y" 'd-povray--yank)
(defun d-povray--yank ()
  (interactive)
  (progn
    (yank)
    (save-excursion
      (goto-char (point-min))
      (while (re-search-forward "\n" nil t)
        (forward-char -1)
        (delete-char 1)
        (insert "\n"))))
  )

(define-key pov-mode-map "\t" 'd-povray-tab-key)
(define-key pov-mode-map [(meta control \\)] 'd-povray--meta-control-backslash)

(define-key pov-mode-map "\C-m" 'd-povray--enter)
(defun d-povray--enter ()
  (interactive)
  (insert "\n")
  (execute-kbd-macro "\t")
)

(defun d-povray-tab-key ()
  (interactive)

  (when (/= (point-at-bol) (point-min))

    (setq d-povray--width-tab-previous (+ (save-excursion
                                             (d-povray--goback-nontrivial)
                                             (d-povray--get-indent))
                                           (* 2 (save-excursion
                                                  (d-povray--goback-nontrivial)
                                                  (d-povray--count-brackets-on-current-line)))))

    (setq d-povray--width-tab-current (d-povray--get-indent))

    (when (/= d-povray--width-tab-previous
              d-povray--width-tab-current)
        (delete-region (point-at-bol)
                       (save-excursion
                         (beginning-of-line)
                         (skip-chars-forward " \t")
                         (point)))
        (beginning-of-line)
        (insert (make-string (max 0 d-povray--width-tab-previous) ?\ )))

    (skip-chars-forward " \t")
    )
  )

(define-key pov-mode-map "\C-l" 'd-povray--goback-nontrivial)
(defun d-povray--goback-nontrivial ()
  (interactive)
  (forward-line -1)
  (while (and (/= (point-min) (point-at-bol))
              (save-excursion
                (beginning-of-line)
                (looking-at "^[ \t]*$")))
    (forward-line -1)
    ))

(defun d-povray--get-indent ()
  (length (buffer-substring-no-properties
           (point-at-bol)
           (save-excursion
             (beginning-of-line)
             (skip-chars-forward " \t")
             (point)))))

(defun d-povray--count-brackets-on-current-line ()
  (setq count 0)
  (save-excursion
    (beginning-of-line)
    (let ((end-point (point-at-eol))
          (com-point (save-excursion (re-search-forward "//" nil 'LIMIT) (point))))
      (when (< com-point end-point)
        ;;(d-foo)
        (setq end-point com-point))

      (while (re-search-forward "[<>(){}]" end-point t)
        (setq str (buffer-substring-no-properties (match-beginning 0) (match-end 0)))
        (when (string-match "[<({]" str)
          ;;(d-foo)
          (incf count))
        (when (string-match "[>)}]" str)
          ;;(d-foo)
          (decf count))
        )

      count)))


(defun d-povray--meta-control-backslash ()
  (interactive)
  (save-excursion
    (goto-char (point-min))
    (while (/= (point) (point-max))
      (forward-line 1)
      (d-povray-tab-key)
;;      (insert "*")
      )))



(defun pov-mode ()
  (interactive)
  (progn
    (fundamental-mode)
    (font-lock-mode 0)
    (setq major-mode 'pov-mode)
    (kill-all-local-variables)
    (setq major-mode 'pov-mode)
    (setq mode-name "Povray")

    (set-syntax-table pov-mode-syntax-table)
    (use-local-map pov-mode-map)

    (setq font-lock-comment-start-regexp "/[/*]")

    (setq pov-mode-font-lock-keywords
          '(
            ("\\<background\\|camera\\|color\\|difference\\|finish\\|light_source\\|pigment\\|plane\\|prism\\|rotate\\|scale\\|texture\\|translate\\|box\\|normal\\|bumps\\|phong\\|union\\|cone\\|sphere\\|text\\>"
             (0 'font-lock-keyword-face nil))
            ("#\\sw*"
             (0 'font-lock-keyword-face nil))
            ("<[^<>]*>"
             (0 'fg:green t))
            ("\\<[A-Z]\\sw*\\>"
             (0 'fg:yellow nil))

            ("//.*$"
             (0 'font-lock-comment-face t))
            ("\\<\\(one\\|two\\|three\\)\\>" . font-lock-keyword-face)
            ("\\<\\(four\\|five\\|six\\)\\>" . font-lock-type-face)
            ("\\<anchor\\>"
             (0 font-lock-reference-face)
             ("\\<\\sw+\\>" nil nil
              (0 font-lock-variable-name-face)))

            ))
    (make-local-variable 'font-lock-defaults)
    (setq font-lock-defaults '(pov-mode-font-lock-keywords nil))

    (font-lock-mode 3)


    ))

(defun pov-help ()
  (interactive)
  (shell-command "start c:/povray/help/povray30.hlp"))

(provide 'd-povray)
;;; d-povray.el ends here
