;;; uko-ii.el -- initialization and setup of UKO-II

;; Copyright (C) 2003 Michael Kuehn, Universität Koblenz-Landau

;; Author: Michael Kuehn <kuehn@uni-koblenz.de>
;; Maintainer: Michael Kuehn <kuehn@uni-koblenz.de>
;; Created: March 2003
;; 
;; $Id: uko-ii.el,v 1.33 2004/08/04 12:15:09 rriipp Exp $


;; uko-ii was formerly named uko-interface,
;; uko-keyboards was split into uko-keymaps and uko-buttons


;; define a default face
(defvar uko-default-face nil "default face")
;; a face is generated with the following atributes
(make-face 'uko-default-face)
(set-face-background 'uko-default-face "red" nil)
(set-face-foreground 'uko-default-face "white" nil)


;;"To become" customizable variables


;;---------- GERMAN KEYBOARD LAYOUTS ------------------------------------------------

(defvar uko-german-keyboard-layout 
  (list
    (string-to-list "agjlmqrwzä.?")
    (string-to-list "cfhkostuvxyüß,!")
    (string-to-list "bdeinpö:-")
  )
  "German kayboard-layout."
)

;; german keyboard to begin with in UKO-SELECT mode
(defvar uko-select-german-keyboard-1 
  (list
    (string-to-list "acfhjpqsuzäß")
    (string-to-list "bdilnrvwx.,:")
    (string-to-list "egkmotyöü?!-")
  )
  "First german keyboard layout for UKO-SELECT"
 )

;; second keyboard
(defvar uko-select-german-keyboard-2 
  (list
    (string-to-list "adgijqtvyz.!:")
    (string-to-list "bckmupswäü,-")
    (string-to-list "efhlornxöß?")
  )
 )

;; third keyboard
(defvar uko-select-german-keyboard-3 
  (list
    (string-to-list "adfkmosvxzü:")
    (string-to-list "behijptwöß.!")
    (string-to-list "cgluqrnyä?,-")
  )
 )

;; last keyboard
(defvar uko-select-german-keyboard-4 
  (list
    (string-to-list "aeilmpqxzü?-")
    (string-to-list "bdfjnotuöä,!:")
    (string-to-list "cghkrsvwyß.")
  )
 )


;;---------- ENGLISH KEYBOARD LAYOUTS ------------------------------------------------

(defvar uko-english-keyboard-layout
  (list
    (string-to-list "bjknosuvwx")
    (string-to-list "adfpqrt'-")
    (string-to-list "ceghilmyz")
  )
  "English keyboard-layout."
) 

;; english keyboard to begin with in UKO-SELECT mode
(defvar uko-select-english-keyboard-1 
  (list
    (string-to-list "acfhjpqsuz'")
    (string-to-list "bdilnrvwx.,:")
    (string-to-list "egkmoty?!-")
  )
  "First english keyboard layout for UKO-SELECT"
 )

;; second keyboard
(defvar uko-select-english-keyboard-2 
  (list
    (string-to-list "adgijqtvyz.!:")
    (string-to-list "bckmupsw,-")
    (string-to-list "efhlornx?'")
  )
 )

;; third keyboard
(defvar uko-select-english-keyboard-3 
  (list
    (string-to-list "adfkmosvxz:'")
    (string-to-list "behijptw.!")
    (string-to-list "cgluqrny?,-")
  )
 )

;; last keyboard
(defvar uko-select-english-keyboard-4 
  (list
    (string-to-list "aeilmpqxz?-")
    (string-to-list "bdfjnotu,!:")
    (string-to-list "cghkrsvwy.'")
  )
 )


;;----- Non-customizable global variables ----------------------------------

(defvar uko-last-proposal-code ""
  "Proposal code typed so far for this word. Used if the partial completion is enabled.") 

(defvar uko-expand-extent nil
  "Active region in text buffer for ambiguous text input.") 

(defvar uko-letter-input ""
  "Letters which have been input so far.") 

(defvar uko-write-buffer nil
  "Buffer into which the user writes.") 

(defvar uko-proposal-buffer-name "*UKO Output*"
  "Name of the buffer where the input from the UKO server is stored.") 

(defvar uko-proposal-buffer nil
  "Buffer containing the matches that are retrieved from the server.")

(defvar uko-proposal-buffer-extent nil
  "Extent used for highlighting the current match in UKO-PROPOSAL-BUFFER.")

(defvar uko-prop-last-block-size nil)

(defvar uko-prop-last-retrieval-size-0-p nil)

(defvar uko-noclient-dictionary-buffer (get-buffer-create "*UKO Dictionary*")
  "Buffer which contains the dictionary if uko-client is not used.")

(defvar uko-capsword-flag t
  "Capitalize current letter.")

(defvar uko-code-extent ""
  "Extent of the current code.")

(defvar uko-initialized nil
  "True if UKO initialization is complete.")

(defvar uko-keyboard-layout uko-german-keyboard-layout)

(defvar uko-keylog-buffer nil
  "The buffer containing all keys pressed in the current session")

;;(defvar uko-timestamp-old (current-time))
;;  This variable holds the last uko-timestamp (used for logging)

(defvar uko-german-button-labels
  (list
   '(letter (append (mapcar 'uko-keyboard-layout-button uko-keyboard-layout)
	    (list "  Word / Text") ))
   '(word "Abbrechen" "Rücktaste" "Trefferliste" "Auswählen")
   '(text "Abbrechen" "Wort löschen" "Navigation" "Makro")
   '(delete "Abbrechen" "Wort löschen" "Wort wiederherstellen" "Fertig")
   '(backspace "Abbrechen" "Rücktaste" "Wiederherstellen" "Fertig")
   '(hitlist "Abbrechen" "Treffer eingrenzen" "Nächstes Wort" "Auswählen")
   '(block-mode "Abbrechen" "Vorheriger Block" "Nächster Block" "Auswählen")
   '(hit-in-block "Abbrechen" "Vorheriges Wort" "Nächstes Wort" "Auswählen")
   '(navigation "Abbrechen" "Wort zurück" "Wort vorwärts" "Fertig")
   '(macro-command "Abbrechen" "Rücktaste/\n vorheriges Makro" "Nächstes Makro" "Ausführen")

   ;; uko-select:
   '(select-command "Abbrechen" "Treffer eingrenzen" "Nächster Treffer" "Auswählen")
   '(select-command-backspace "Abbrechen" "Rücktaste" "Nächster Treffer" "Auswählen")
   '(select-command-previous "Abbrechen" "Vorheriger Treffer" "Nächster Treffer" "Auswählen")
     
   )

   "German button labels."
  )


(defvar uko-english-button-labels
  (list
   '(letter (append (mapcar 'uko-keyboard-layout-button uko-keyboard-layout)
		    (list "  Word / Text") ))
   '(word "Cancel" "Backspace" "Hit List" "Select")
   '(text "Cancel" "Delete Word" "Navigation" "Macro")
   '(delete "Cancel" "Delete Word" "UnDelete Word" "Done")
   '(backspace "Cancel" "Delete" "UnDelete" "Done")
   '(hitlist "Cancel" "Previous" "Next" "Select")
   '(block-mode "Cancel" "Previous" "Next" "Select")
   '(hit-in-block "Cancel" "Previous" "Next" "Select")
   '(navigation "Cancel" "Backward Word" "Forward Word" "Done")

   ;; uko-select:
   '(select-command "cancel" "focus matches" "next match" "accept")
   '(select-command-backspace "cancel" "backspace" "next match" "accept")
   '(select-command-previous "cancel" "previous match" "next match" "accept")

   )
  
   "English button labels."
  )
 
(defvar uko-button-labels uko-german-button-labels)

;; local variables from uko-ii.el

(defvar uko-delete-stack '())

(defvar uko-move-point nil)

(defvar uko-spell-next-letter-list '())

(defvar uko-spell-prev-letter-list '())




;; ***************************
;;      UKO-SELECT-ACTIVE
;; ***************************

(defvar uko-select-active nil
  "TRUE if the special UKO-SELECT-MODE should be usable")

;; ***************************




;; the uko-emacs-directory should be defined in your ~/.emacs file
;; load all modules which are listed below
(load (concat uko-emacs-directory "lisp/uko-predict.el"))
(load (concat uko-emacs-directory "lisp/uko-editing.el"))
(load (concat uko-emacs-directory "lisp/uko-buttons.el"))
(load (concat uko-emacs-directory "lisp/uko-keymaps.el"))
(load (concat uko-emacs-directory "lisp/uko-macros.el"))
(load (concat uko-emacs-directory "lisp/uko-speak.el"))
(load (concat uko-emacs-directory "lisp/uko-search.el"))
(load (concat uko-emacs-directory "lisp/uko-scanning.el"))
(load (concat uko-emacs-directory "lisp/uko-dual-select.el"))
(load (concat uko-emacs-directory "lisp/uko-custom.el"))
(load (concat uko-emacs-directory "lisp/uko-select.el"))



;; Fill the dictionary buffer with the entries of the english dictionary
(defun uko-set-english-dictionary ()
  "Fill the dictionary buffer with the entries of the english dictionary."
  (save-current-buffer
    (set-buffer uko-noclient-dictionary-buffer)	; Set current buffer
    
    (goto-char (point-min))		; Set point to the beginning of the buffer
    (delete-region (point-min) (point-max))
    (insert-file (concat uko-emacs-directory "dict/ukodict-e.txt"))
    )
  )

;; Fill the dictionary buffer with the entries of the german dictionary
(defun uko-set-german-dictionary ()
  "Fill the dictionary buffer with the entries of the german dictionary"
  (save-current-buffer
    (set-buffer uko-noclient-dictionary-buffer)	; Set current buffer
    
    (goto-char (point-min))		; Set point to the beginning of the buffer
    (delete-region (point-min) (point-max))
    (insert-file (concat uko-emacs-directory "dict/ukodict.txt"))
    )
  )



(defun uko-init-language ()
  "Reinitialize all language-dependent settings using UKO-LANGUAGE"
  (progn 
   
    (if (= uko-language 1)
	(progn
	  (setq uko-dictionary-file "dict/ukodict.txt")
	  (setq uko-keyboard-layout uko-german-keyboard-layout)
	  (setq uko-button-labels uko-german-button-labels)
	  (uko-set-german-dictionary)
	  ) )

    (if (= uko-language 2)
	(progn
	  (setq uko-dictionary-file "dict/ukodict-e.txt")
	  (setq uko-keyboard-layout uko-english-keyboard-layout)
	  (setq uko-button-labels uko-english-button-labels)
	  (uko-set-english-dictionary)
	  ) )

    (uko-set-default-state) 
    
    ) )


 
(defun uko-set-german ()
  "Set UKO-II interface for use of german language."
  (interactive)
  (setq uko-language 1)
  (uko-init-language)
  )

(defun uko-set-english ()
  "Set UKO-II interface for use of english language."
  (interactive)
  (setq uko-language 2)
  (uko-init-language)
  )


;;; doc
(defun uko-init ()
 "Initialize window-arrangements, text buffer and an extent in it.
the buttons, the proposal window and buffers and logox. After that it calls `uko-enter'";
;;; enddoc
  (interactive)

  ;; [TS] Warum unten nochmal?
  (when uko-use-logox
    (uko-connect)			; [TS] Warum unten nochmal?
    (uko-speak-init-logox)
    (uko-connect)
    )

  (set-buffer (get-buffer-create "*UKO Text*"))
  (delete-region (point-min) (point-max))
  (setq uko-expand-extent (make-extent (point) (point)))

  (uko-keyboard-init-buttons)

  (setq uko-proposal-buffer (get-buffer-create uko-proposal-buffer-name))
  (uko-proposal-init)

  (global-set-key uko-physical-switch-0 'uko-enter)

  ;;Vieleicht besser customizable? Sonst: warum nicht am Anfang der Datei?
  (setq uko-capsword-flag t)

  (when uko-use-logox 
    (uko-connect)
    (uko-speak-init-logox)
    (uko-connect)
    )

  (when uko-scanning
    (uko-scanning-initialize)
    )

  (setq uko-last-proposal-code "")

  ; select german language setting
  (uko-set-german)

  ;; create and initialize the buffer for the logging-mechanism
  (setq uko-keylog-buffer (get-buffer-create "*UKO Log*"))
  (delete-region (point-min uko-keylog-buffer) (point-max uko-keylog-buffer) uko-keylog-buffer) ; clear log-buffer
  (insert-string (concat "UKO-II keylog\n" (format-time-string "%D %T" (current-time)) "\n\n") uko-keylog-buffer)

  (setq uko-initialized t)
  (uko-enter)
 )

(defun uko-enter ()
  "Enter UKO mode for highly ambiguous typing input expansion.
Change the keyboard-layout from the normal to the UKO-mode."

  (interactive)

  ;; Switch to the text buffer and create it before if nescesary
  (setq uko-write-buffer (get-buffer "*UKO Text*"))
  (switch-to-buffer (get-buffer "*UKO Text*"))

  (uko-connect)

  (uko-macro-initialize)

  (when uko-use-logox 
    (uko-speak-connect)
    )

;; (uko-init-proposals)

  (let ((start (point)))
    ;;Insert whitespace to ensure that the extent will not be empty
    (insert " ") 
    (setq uko-expand-extent (make-extent start (point)))
    (setq uko-letter-input "")
    ;;Highlight the extend
    (set-extent-face uko-expand-extent 'highlight)
    (goto-char start)
    )

  (uko-init-keymap)
  (uko-set-default-state)
  )

(defun uko-leave ()
  "Leave UKO mode, change the Keyboard-layout back to the normal."
  (interactive)
  (delete-extent uko-expand-extent)
  (uko-disconnect)
  )

;;The functions for the input keys
(defun uko-letter-key-1 () ""
  (interactive) (uko-letter-key 1))
(defun uko-letter-key-2 ()  ""
  (interactive) (uko-letter-key 2))
(defun uko-letter-key-3 () ""
  (interactive) (uko-letter-key 3))
(defun uko-letter-key-4 () ""
  (interactive) (uko-letter-key 4))

;; Handle input keypad numbers.
;; Insert typed number into text-buffer or
;; Expand after each letter if uko-expand-after-each-letter is true.
;; Insert best guess (accepts word longer than input code) if uko-insert-best-guess is true.
(defun uko-letter-key (k)
  "Insert typed number into text-buffer or expand after each letter.
Expand best guess if uko-insert-best-guess is true."
  (insert (int-to-string k))
  (setq uko-letter-input (concat uko-letter-input (int-to-string k)))
  (when uko-partial-complete 
    (setq uko-insert-best-guess t)
    )
  (when uko-insert-best-guess		; uko-best-guess activated?
    (setq uko-last-proposal-code (concat uko-last-proposal-code (int-to-string k)))
    (uko-insert-proposal uko-last-proposal-code)
    (uko-retrieve uko-last-proposal-code uko-partial-complete))
    (let ((prop (uko-get-proposal)))
      (if prop (uko-insert-proposal prop)
	(beep)
	) )
  (when uko-expand-after-each-letter
    (uko-proposals uko-letter-input)
    (uko-proposal-show-buffer)
    )
  (uko-set-default-state)
  )

;; Select a highlighted proposal from the list in the proposal window.
;; If uko-use-logo and uko-speak-each-word are true then speak word.
;; Capitalize first letter of the selected word if uko-capsword-flag is true.
(defun uko-select (prop)
  "Select a highlighted proposal 'prop'.
If uko-use-logo and uko-speak-each-word are true then speak word.
Capitalize first letter of word if uko-capsword-flag is true."
;; (interactive)
  (setq uko-last-proposal-code "")	; delete last-proposal-code
 (when (and uko-speak-each-word uko-use-logox) ; speak word if uko-speak-each-word and uko-use-logox is true
    (uko-speak-clear)
    (uko-speak-send-string prop)
    (uko-speak-start)
    )
  (when uko-capsword-flag		; capitalize first letter of word if uko-capsword-flag is true
    (capitalize-word -1)
    (setq uko-capsword-flag nil)
    )
  (goto-char (extent-end-position uko-expand-extent)) ; put cursor behind word with one backspace inbetween
  (set-extent-endpoints uko-expand-extent (point) (point)) ; set the new extent endpoints
  (uko-enter)				; insert input field
  )



;; Start prediction of input code
(defun uko-expand ()
  "Start decoding process of the input code.";
  (interactive)
  (uko-proposals uko-last-proposal-code)
  (if (eolp uko-proposal-buffer)
      (progn
	(beep)
	(uko-set-default-state)
	)
    (if (zerop uko-proposal-preview-num)
	(uko-set-proposal-block-state)
      (uko-set-proposal-preview-state)
      ) ) )


(defun uko-command ()
  "Change to the command mode.";
  (interactive)
  (setq uko-code-extent (substring (extent-string uko-expand-extent) 0 -1))
  (if (equal (extent-string uko-expand-extent) " ")
      (uko-set-empty-command-state)
    (uko-set-command-state)
  ) )


;;***change name to uko-command-cancel ? ***
(defun uko-command-undo ()
  "Discard changes.";
  (interactive)
  (uko-insert-proposal uko-code-extent)
  (uko-proposal-delete-window)
  (when uko-insert-best-guess
    (uko-insert-proposal uko-last-proposal-code)
    (uko-expand)
    )
  (uko-set-default-state)
  )


;; Confirm prediction of input code and insert it to text-input field.
(defun uko-insert-proposal (prop)
  "Insert expanded code into the text if it is not empty.";
  (when prop
    (goto-char (extent-start-position uko-expand-extent))
    (insert prop)
    (insert " ")    
    (delete-region (point) (extent-end-position uko-expand-extent))
    (goto-char (+ (extent-start-position uko-expand-extent) (length uko-last-proposal-code)))
    )
  prop
  )




