;; th-kesmanee.mim -- Thai input method with Kesmanee keyboard layout
;; Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009
;;   National Institute of Advanced Industrial Science and Technology (AIST)
;;   Registration Number H15PRO112

;; This file is part of the m17n database; a sub-part of the m17n
;; library.

;; The m17n library is free software; you can redistribute it and/or
;; modify it under the terms of the GNU Lesser General Public License
;; as published by the Free Software Foundation; either version 2.1 of
;; the License, or (at your option) any later version.

;; The m17n library is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
;; Lesser General Public License for more details.

;; You should have received a copy of the GNU Lesser General Public
;; License along with the m17n library; if not, write to the Free
;; Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
;; Boston, MA 02110-1301, USA.

(input-method th kesmanee)

(description "Thai input method simulating the Kesmanee keyboard
with WTT 2.0 input sequence correction.
The correction algorithm follows the one shown in the following 
  <http://linux.thai.net/~thep/th-xim/>
")

(title "ท")

(variable
 (level (_"Acceptance level
The level of character sequence acceptance defined in WTT 2.0.
0 accepts any key sequence.  2 accepts only orthographic ones.
1 is somewhere between.")
	1 0 1 2))

(macro

 ;; input global variables : arg1, arg2
 ;; output global variable : ret
 (cp
  (cond
   ((= level 0)
    (set ret 1))
   (1
    (cp12))))

 ;; input global variables : arg1, arg2
 ;; output global variable : ret
 (ac
  (cond
   ((= level 0)
    (set ret 1))
   ((= level 1)
    (ac1))
   (1
    (ac2))))

 ;; Level 1 & 2 composability
 (cp12
  (set ret 0)
  (cond

   ;; next = BV1|BV2|BD|AD3|AV1|AV2|AV3, previous = CONS
   ((| (= arg2 0x0E31)
       (& (>= arg2 0x0E34) (<= arg2 0x0E3A))
       (= arg2 0x0E4E))
    (cond
     ((| (& (>= arg1 0x0E01) (<= arg1 0x0E23))
	 (= arg1 0x0E25)
	 (& (>= arg1 0x0E27) (<= arg1 0x0E2E)))
      (set ret 1))))

   ;; next = TONE, previous = CONS|BV1|BV2|AV1|AV2|AV3
   ((& (>= arg2 0x0E48) (<= arg2 0x0E4B))
    (cond
     ((| (& (>= arg1 0x0E01) (<= arg1 0x0E23))
	 (= arg1 0x0E25)
	 (& (>= arg1 0x0E27) (<= arg1 0x0E2E))
	 (= arg1 0x0E31)
	 (& (>= arg1 0x0E34) (<= arg1 0x0E39)))
      (set ret 1))))

   ;; next = AD1, previous = CONS|BV1|AV1
   ((& (>= arg2 0x0E4C) (<= arg2 0x0E4D))
    (cond
     ((| (& (>= arg1 0x0E01) (<= arg1 0x0E23))
	 (= arg1 0x0E25)
	 (& (>= arg1 0x0E27) (<= arg1 0x0E2E))
	 (= arg1 0x0E38)
	 (= arg1 0x0E34))
      (set ret 1))))

   ;; next = AD2, previous = TONE| AV3
   ((= arg2 0x0E47)
    (cond
     ((| (& (>= arg1 0x0E01) (<= arg1 0x0E23))
	 (= arg1 0x0E25)
	 (& (>= arg1 0x0E27) (<= arg1 0x0E2E))
	 (= arg1 0x0E35)
	 (= arg1 0x0E37))
      (set ret 1))))))

 ;; Level 1 acceptance
 (ac1
  (set ret 1)
  (cond
   ((| (= arg2 0x0E31)
       (& (>= arg2 0x0E34) (<= arg2 0x0E3A))
       (& (>= arg2 0x0E47) (<= arg2 0x0E4E)))
    (set ret 0))))

 ;; Level 2 acceptance
 (ac2
  (set ret 0)
  (cond

   ;; next = CTRL|CONS, previous = *
   ((| (<= arg2 0x001F)
       (& (>= arg2 0x0080) (<= arg2 0x009F))
       (& (>= arg2 0x0E01) (<= arg2 0x0E23))
       (= arg2 0x0E25)
       (& (>= arg2 0x0E27) (<= arg2 0x0E2E)))
    (set ret 1))

   ;; next = NON|LV, previous = ~LV, 
   ((| (& (>= arg2 0x0020) (<= arg2 0x007E))
       (& (>= arg2 0x00A0) (<= arg2 0x0E00))
       (= arg2 0x0E2F)
       (& (>= arg2 0x0E3F) (<= arg2 0x0E44))
       (= arg2 0x0E46)
       (> arg2 0x0E4E))
    (cond
     ((| (< arg1 0x0E40) (> arg1 0x0E44))
      (set ret 1))))

   ;; next = FV1, previous = CONS|FV1|FV2|BV1|TONE
   ((| (= arg2 0x0E30) (= arg2 0x0E32) (= arg2 0x0E33))
    (cond
     ((| (& (>= arg1 0x0E01) (<= arg1 0x0E23))
	 (= arg1 0x0E25)
	 (& (>= arg1 0x0E27) (<= arg1 0x0E2E))
	 (= arg1 0x0E30)
	 (= arg1 0x0E32)
	 (= arg1 0x0E33)
	 (= arg1 0x0E45)
	 (= arg1 0x0E38)
	 (& (>= arg1 0x0E48) (<= arg1 0x0E4B)))
      (set ret 1))))
   
   ;; next = FV2, previous = FV3|TONE
   ((= arg2 0x0E45)
    (cond
     ((| (= arg1 0x0E24)
	 (= arg1 0x0E26)
	 (& (>= arg1 0x0E48) (<= arg1 0x0E4B)))
      (set ret 1))))

   ;; next = FV3, previous = ~LV~FV3
   ((| (= arg2 0x0E24) (= arg2 0x0E26))
    (cond
     ((& (| (< arg1 0x0E40) (> arg1 0x0E44))
	 (! (= arg1 0x0E24))
	 (! (= arg1 0x0E26)))
      (set ret 1)))))))   

(map
 (map
  ("!" "+")
  ("\"" ".")
  ("#" "๒")
  ("$" "๓")
  ("%" "๔")
  ("&" "฿")
  ("'" "ง")
  ("(" "๖")
  (")" "๗")
  ("*" "๕")
  ("+" "๙")
  ("," "ม")
  ("-" "ข")
  ("." "ใ")
  ("/" "ฝ")
  ("0" "จ")
  ("1" "ๅ")
  ("2" "/")
  ("3" "-")
  ("4" "ภ")
  ("5" "ถ")
  ("6" "ุ")
  ("7" "ึ")
  ("8" "ค")
  ("9" "ต")
  (":" "ซ")
  (";" "ว")
  ("<" "ฒ")
  ("=" "ช")
  (">" "ฬ")
  ("?" "ฦ")
  ("@" "๑")
  ("A" "ฤ")
  ("B" "ฺ")
  ("C" "ฉ")
  ("D" "ฏ")
  ("E" "ฎ")
  ("F" "โ")
  ("G" "ฌ")
  ("H" "็")
  ("I" "ณ")
  ("J" "๋")
  ("K" "ษ")
  ("L" "ศ")
  ("M" "?")
  ("N" "์")
  ("O" "ฯ")
  ("P" "ญ")
  ("Q" "๐")
  ("R" "ฑ")
  ("S" "ฆ")
  ("T" "ธ")
  ("U" "๊")
  ("V" "ฮ")
  ("W" "\"")
  ("X" ")")
  ("Y" "ํ")
  ("Z" "(")
  ("[" "บ")
  ("\\" "ฃ")
  ("]" "ล")
  ("^" "ู")
  ("_" "๘")
  ("`" "_")
  ("a" "ฟ")
  ("b" "ิ")
  ("c" "แ")
  ("d" "ก")
  ("e" "ำ")
  ("f" "ด")
  ("g" "เ")
  ("h" "้")
  ("i" "ร")
  ("j" "่")
  ("k" "า")
  ("l" "ส")
  ("m" "ท")
  ("n" "ื")
  ("o" "น")
  ("p" "ย")
  ("q" "ๆ")
  ("r" "พ")
  ("s" "ห")
  ("t" "ะ")
  ("u" "ี")
  ("v" "อ")
  ("w" "ไ")
  ("x" "ป")
  ("y" "ั")
  ("z" "ผ")
  ("{" "ฐ")
  ("|" "ฅ")
  ("}" ",")
  ("~" "%")))

;; CTRL : 0000..0020, 007F..009F
;; NON  : 0021..007E, 00A0..0E00
;; CONS : 0E01..0E23, 0E25, 0E27..0E2E
;; LV   : 0E40..0E44
;; FV1  : 0E30, 0E32, 0E33
;; FV2  : 0E45
;; FV3  : 0E24, 0E26
;; BV1  : 0E38
;; BV2  : 0E39
;; BD   : 0E3A
;; TONE : 0E48..0E4B
;; AD1  : 0E4C, 0E4D
;; AD2  : 0E47
;; AD3  :
;; AV1  : 0E34
;; AV2  : 0E31, 0E36
;; AV3  : 0E35, 0E37

(state

 (init
  (map
   (delete @<)
   (pushback 1)
   (shift main)))
 
 (main
  (map
   (set x @-3)
   (set y @-2)
   (set z @-1)

   (set arg1 y)
   (set arg2 z)
   (cp)
   (cond
    ((= ret 1)) ;; CP(y,z) succeeded.
    (1
     (ac)
     (cond
      ((= ret 1)) ;; AC(y,z) succeeded.
      (1
       ;; WTT-based input sequence correction starts here.

       ;; begin
       ;; if CP(x,z) then
       (set arg1 x)
       (set arg2 z)
       (cp)
       (cond
	((= ret 1)

	 ;; if CP(z,y) then
	 (set arg1 z)
	 (set arg2 y)
	 (cp)
	 (cond
	  ((= ret 1)

	   ;; reorder(y -> zy)
	   (delete @-2)
	   (insert z)
	   (insert y))

	  ;; elif CP(x,y) then
	  (1
	   (set arg1 x)
	   (set arg2 y)
	   (cp)
	   (cond
	    ((= ret 1)

	     ;; replace(y -> z)
	     (delete @-2)
	     (insert z))

	    ;; elif y is FV1 and z is TONE then
	    ((& (| (= y 0x0E30) (= y 0x0E32) (= y 0x0E33))
		(>= z 0x0E48)
		(<= z 0x0E4B))

	     ;; reorder(y -> zy)
	     (delete @-2)
	     (insert z)
	     (insert y))

	    ;; else
	    ;; reject(z)
	    (1
	     (delete @-1))

	    ;;endif
	    ))))

	;; elif AC(x,z) then
	(1
	 (set arg1 x)
	 (set arg2 z)
	 (ac)
	 (cond
	  ((& (= ret 1)
	      ;; Only Thai characters should be replaced.
	      (& (>= y 0x0E01) (<= y 0x0E5B))
	      (& (>= z 0x0E01) (<= z 0x0E5B)))

	   ;; replace(y -> z)
	   (delete @-2)
	   (insert z))

	  ;; else
	  ;; reject(z)
	  (1
	   (delete @-1))

	  ;; endif
	  )))
       ;; end

       ))))

   ;; Now we commit the preedit chars that are fixed.
   (set w @-1)
   (cond
    ;; If surrounding text is supported, commit the only char in preedit.
    ((> @-0 -2)
     (commit))

    ;; If the last char is CTRL or NON, we can commit everything.
    ((| (& (>= w 0x0000) (<= w 0x0E00))
	(= w 0x0E2F)
	(= w 0x0E3F)
	(= w 0x0E46)
	(>= w 0x0E4F))
     (commit))

    ;; If the last char is CONS, we can commit everything but the last
    ;; unless the second last is FV3.
    ((| (& (>= w 0x0E01) (<= w 0x0E23))
	(= w 0x0E25)
	(& (>= w 0x0E27) (<= w 0x0E2E)))
     (cond
      ((| (= @-2 0x0E24) (= @-2 0x0E26))
       ; not commit yet
       )
      (1
       (delete @-1)
       (commit)
       (insert w))))

    ;; If the last char is LV, FV2 or FV3, we can commit
    ;; everything but the last.
    ((| (& (>= w 0x0E40) (<= w 0x0E45))
	(= w 0x0E24)
	(= w 0x0E26))
     (delete @-1)
     (commit)
     (insert w))

    ;; If the last char is FV1 (excluding AM) and ...
    ((| (= w 0x0E30) (= w 0x0E32))
     (delete @-1)
     (set v @-1)
     (cond

      ;; ... the before last is CONS, we can commit other than the
      ;; last two.
      ((| (& (>= v 0x0E01) (<= v 0x0E23))
	  (= v 0x0E25)
	  (& (>= v 0x0E27) (<= v 0x0E2E)))
       (delete @-1)
       (commit)
       (insert v)
       (insert w))

      ;; ... else if the before last is not CONS, we can commit
      ;; everything but the last.
      (1
       (commit)
       (insert w))))
    ))))

;; Local Variables:
;; coding: utf-8
;; mode: emacs-lisp
;; End:
