;;!emacs
;;
;; FILE:         kimport.el
;; SUMMARY:      Convert and insert other outline file formats into koutlines.
;; USAGE:        GNU Emacs V19 Lisp Library
;; KEYWORDS:     data, outlines, wp
;;
;; AUTHOR:       Bob Weiner & Kellie Clark
;;
;; ORIG-DATE:    15-Nov-93 at 11:57:05
;; LAST-MOD:     25-Jun-95 at 18:42:28 by Bob Weiner
;;
;; This file is part of Hyperbole.
;; Available for use and distribution under the same terms as GNU Emacs.
;;
;; Copyright (C) 1993-1995, Free Software Foundation, Inc.
;; Developed with support from Motorola Inc.
;;
;; DESCRIPTION:  
;; DESCRIP-END.

;;; ************************************************************************
;;; Other required Elisp libraries
;;; ************************************************************************

(mapcar 'require '(kview wrolo))

;;; ************************************************************************
;;; Public functions
;;; ************************************************************************

;;;
;;; Augment right-side numbered files, blank line between cells
;;;

;;;###autoload
(defun kimport:aug-post-outline (import-file insertion-file)
  "Insert Augment outline nodes from IMPORT-FILE into INSERTION-FILE.
Nodes to be imported are delimited by Augment relative ids at cell ends.
\"1\" = level 1, \"1a\" = level 2 in outline and so on."
  (interactive "fAugment post-numbered cells file: \nFFile to insert cells into: ")
  (let* ((kotl-exists-p (file-exists-p insertion-file))
	 (kotl-buffer (find-file-noselect insertion-file))
	 (orig-point (progn (set-buffer kotl-buffer) (point)))
	 kotl-view
	 source-buffer
	 total
	 )
    (if kotl-exists-p
	(error "(kimport:aug-post-outline): Can't import into an existing file.")
      (kotl-mode)
      (setq kotl-view kview)
      (delete-region (point-min) (point-max)))
    (setq source-buffer (set-buffer (find-file-noselect import-file)))
    (show-all)
    (save-excursion
      (goto-char (point-min))
      (setq total (read (count-matches
			 " +\\([0-9][0-9a-z]*\\)\n\\(\n\\|\\'\\)")))
      (kimport:aug-post-cells kotl-view 0 0 total source-buffer)
      (pop-to-buffer (kview:buffer kotl-view))
      (kfile:narrow-to-kcells)
      (goto-char orig-point)
      (kotl-mode:to-valid-position)
      (message "%d cells inserted." total))))

;;;
;;; Emacs outliner style files, leading '*' cell delimiters
;;;

;;;###autoload
(defun kimport:star-outline (import-file insertion-file)
  "Insert star outline nodes from IMPORT-FILE into INSERTION-FILE.
\"* \" = level 1, \"** \" = level 2 in outline and so on."
  (interactive "fStar delimited cells file: \nFFile to insert cells into: ")
  (let* ((kotl-exists-p (file-exists-p insertion-file))
	 (kotl-buffer (find-file-noselect insertion-file))
	 (orig-point (progn (set-buffer kotl-buffer) (point)))
	 kotl-view
	 source-buffer
	 total
	 )
    (if kotl-exists-p
	(error "(kimport:star-outline): Can't import into an existing file.")
      (delete-region (point-min) (point-max)))
    (kotl-mode)
    (setq kotl-view kview)
    (setq source-buffer (set-buffer (find-file-noselect import-file)))
    (show-all)
    (save-excursion
      (goto-char (point-min))
      ;; Total number of top-level cells.
      (setq total (read (count-matches "^[ \t]*\\*[ \t\n]")))
      (kimport:star-cells kotl-view "1" "" -1 total source-buffer)
      (pop-to-buffer (kview:buffer kotl-view))
      (kfile:narrow-to-kcells)
      (goto-char orig-point)
      (kotl-mode:to-valid-position)
      (message "%d cells inserted." total))))

;;; ************************************************************************
;;; Private functions
;;; ************************************************************************

(defun kimport:aug-post-cells (kview prev-level count total source-buffer)
  (let ((cell-end-regexp " +\\([0-9][0-9a-z]*\\)\n\\(\n\\|\\'\\)")
	contents start subtree-p end end-contents cell-level klabel)
    ;; While find cells at a deeper level than prev-level ...
    (while (and (setq start (point))
		(re-search-forward cell-end-regexp nil t)
		(< prev-level
		   (setq cell-level
			 (kimport:aug-label-level
			  (setq klabel
				(buffer-substring
				 (match-beginning 1) (match-end 1)))))))
      (setq end-contents (match-beginning 0)
	    end (match-end 0))
      (goto-char end)
      (setq subtree-p (save-excursion
			(and (re-search-forward cell-end-regexp nil t)
			     (< cell-level
				(kimport:aug-label-level
				 (buffer-substring
				  (match-beginning 1) (match-end 1))))))
	    contents (hypb:replace-match-string
		      "^[ \t]+" (buffer-substring start end-contents) "" t))
      (save-excursion
	(set-buffer (kview:buffer kview))
	(kview:add-cell klabel cell-level contents)
	(message "Cell <%s> inserted; %d of %d cells done..."
		 klabel (setq count (1+ count)) total))
      (set-buffer source-buffer)
      ;;
      ;; Handle each sub-level through recursion.
      (if subtree-p
	  ;; Subtree exists so insert its cells.
	  (setq count
		(kimport:aug-post-cells
		 kview cell-level count total source-buffer))))
    (goto-char start))
  count)

(defun kimport:star-cells (kview klabel prev-level-str count total source-buffer)
  (let ((start (point))
	(rolo-entry-regexp "^[ \t]*\\*+")
	subtree-p end end-contents contents cell-level-str)
    ;; While find cells at a deeper level than prev-level-str ...
    (while (and (re-search-forward rolo-entry-regexp nil t)
		(string-lessp
		 prev-level-str
		 (setq cell-level-str
		       (buffer-substring (match-beginning 0) (match-end 0)))))
      (skip-chars-forward " \t")
      (setq start (point)
	    end (rolo-to-entry-end)
	    subtree-p (and (looking-at rolo-entry-regexp)
			   (string-lessp
			    cell-level-str
			    (buffer-substring
			     (match-beginning 0) (match-end 0))))
	    end-contents (progn (skip-chars-backward "\n\^M") (point))
	    contents (buffer-substring start end-contents))
      (save-excursion
	(set-buffer (kview:buffer kview))
	(kview:add-cell klabel (length cell-level-str) contents)
	(message "Cell <%s> inserted; %d of %d trees done..."
		 klabel
		 (if (= (length cell-level-str) 1)
		     (setq count (1+ count))
		   count)
		 total))
      (set-buffer source-buffer)
      (goto-char end)
      ;;
      ;; Handle each sub-level through recursion.
      (if subtree-p
	  ;; Subtree exists so insert its cells.
	  (setq count
		(kimport:star-cells kview (klabel:child-alpha klabel)
				    cell-level-str count total
				    source-buffer)))
      (setq klabel (klabel:increment klabel)))
    (goto-char start))
  count)

(defun kimport:aug-label-lessp (label1 label2)
  "Return non-nil iff Augment-style LABEL1 is less than LABEL2."
  (< (kimport:aug-label-level label1) (kimport:aug-label-level label2)))

(defun kimport:aug-label-level (label)
  "Return outline level as an integer of Augment-style LABEL.
First visible outline cell is level 1."
  (if (string-equal label "0")
      0
    (let ((i 0)
	  (level 0)
	  (len (length label))
	  (digit-p nil)
	  chr)
      (while (< i len)
	(if (and (>= (setq chr (aref label i)) ?0)
		 (<= chr ?9))
	    (or digit-p (setq level (1+ level)
			      digit-p t))
	  ;; assume chr is alpha
	  (if digit-p (setq level (1+ level)
			    digit-p nil)))
	(setq i (1+ i)))
      level)))

(provide 'kimport)

