
(defvar etex-input nil)
(defvar etex-output nil)
(defvar etex-line nil)
(defvar etex-left-margin nil)
(defvar etex-parindent nil)

(setq etex-parindent '((skip 5)))
(setq etex-parskip "\n\n")
(setq etex-left-margin "  ")
(setq etex-hsize 70)

(defun etex-buffer ()
  (interactive)
  (etex-region (point-min) (point-max)))

(defun etex-region (start end)
  (interactive "r")
  (save-restriction
    (narrow-to-region start end)
    (goto-char (point-min))
    (setq etex-input (current-buffer))
    (setq etex-output (generate-new-buffer (concat "etex-" (buffer-name (current-buffer)))))
    (setq etex-line nil)
    (display-buffer etex-output)
    (while (not (eobp))
      (etex-vertically))))

(defun etex-vertically ()
  (while (not (eobp))
    (let ((ch (char-after (point))))
      (cond
       ((or (eq ch ? )
	    (eq ch ?\n)
	    (eq ch ?\t))       
	(forward-char 1))
       ((eq ch ?{)
	(forward-char 1)
	(etex-command))
       (t
	(etex-end-paragraph)
	(etex-add etex-parindent)
	(etex-horizontally)))))
  (etex-end-paragraph))

(defun etex-add (items)
  (setq etex-line
	(append etex-line items)))

(defun etex-end-paragraph ()
  (if etex-line
      (progn
	(etex-output-line)
	(etex-output etex-parskip)))
  (setq etex-line nil))

(defun etex-horizontally ()
  (while (and (not (eobp))
	      (not (looking-at "[ \t]*\n[ \t]*\n")))
    (skip-chars-forward " \t\n")
    (cond
     ((looking-at "[^ \t\n]+")
      (etex-add (list (list 'word (buffer-substring (match-beginning 0) (match-end 0)))))
      (goto-char (match-end 0)))
     (t (or (eobp) (error "I'm confused in horizontal mode")))))
  (etex-end-paragraph))

(defun etex-output-line ()
  (save-excursion
    (set-buffer etex-output)
    (insert etex-left-margin)
    (let ((right (+ (current-column) etex-hsize)))
      (while etex-line 
	(let* ((item (car etex-line))
	       (action (car item))
	       (arg (car (cdr item))))
	  (cond
	   ((eq action 'skip)
	    (insert (make-string arg ? )))
	   ((eq action 'word)
	    (insert arg)
	    (insert (if (string-match "[.!?]$" arg) "  " " "))))
	  (if (> (current-column) right)
	      (progn
		(backward-word 1)
		(insert "\n")
		(insert etex-left-margin)
		(end-of-line))))
	(setq etex-line (cdr etex-line))))))


(defun etex-output (stuff)
  (save-excursion
    (set-buffer etex-output)
    (insert stuff)))

(defun etex-command ()
  (skip-chars-forward " \t\n")
  (if (not (looking-at "[^ \t\n{}]+"))
      (error "No command sequence specified"))
  (let ((command (buffer-substring (match-beginning 0) (match-end 0))))
    (goto-char (match-end 0))
    (skip-chars-forward " \t\n")
    (if (not (looking-at "[^}]*"))
	(error "Unterminated arg for command"))
    (let ((arg (buffer-substring (match-beginning 0) (match-end 0))))
      (goto-char (match-end 0))
      (forward-char 1)
      (cond
       ((string-equal command "hline")
	(etex-output "----------------------------------------------------------------------\n"))
       ((string-equal command "center")
	(etex-output (concat (make-string (/ (- 72 (length arg)) 2) ? ) arg "\n")))
       ((string-equal command "skip")
	(etex-output "\n"))
       (t
	(etex-output (format "Command: (%s %s)\n" command arg)))))))
