---
#default rules shared among several speech rules
- name: default
  tag: math
  match: "."
  replace:
  - with:
      variables:
      - ClearSpeak_Fractions: "IfThenElse($Verbosity='Verbose' and $ClearSpeak_Fractions='Auto', 'EndFrac', $ClearSpeak_Fractions)"
      - ClearSpeak_AbsoluteValue: "IfThenElse($Verbosity='Verbose' and $ClearSpeak_AbsoluteValue='Auto', 'AbsEnd', $ClearSpeak_AbsoluteValue)"
      - ClearSpeak_Roots: "IfThenElse($Verbosity='Verbose' and $ClearSpeak_Roots='Auto', 'RootEnd', $ClearSpeak_Roots)"
      - ClearSpeak_Matrix: "IfThenElse($Verbosity='Verbose' and $ClearSpeak_Matrix='Auto', 'EndMatrix', $ClearSpeak_Matrix)"
      # should be set at mtable level, but unknown intents make that impossible to know
      - IsColumnSilent: false()
      replace:
      - test:
          if: "$MathRate = 100"
          then: [x: "*"]
          else:
          - rate:
              value: "$MathRate"
              replace: [x: "*"]

- name: empty-mrow
  tag: mrow
  match: "not(*)"
  replace:
  - T: ' ' # say nothing -- placeholder

- name: default
  tag: mrow
  match: "."
  replace:
  - insert:
      nodes: "*"
      replace: [pause: auto]

- name: default
  tag: mn
  match: "."
  replace:
  - bookmark: "@id"
  - x: "translate(., $BlockSeparators, '')"   # remove digit block separators

- name: default
  tag: [mo, mtext]
  match: "."
  replace:
  - bookmark: "@id"
  - x: "text()"

- name: default
  tag: mi
  match: "."
  replace:
  - bookmark: "@id"
  - test:
      if: "string-length(.) = 1"       # need unicode.tdl to kick in for single letter tokens
      then: [x: "text()"]
      else: [x: "translate(., '-_\u00A0', '  ')" ]   # from intent literals

- name: default
  tag: ms
  match: "."
  replace:
  - T: 'string'
  - pause: short
  - x: "text()"

- name: default
  tag: mstyle
  match: "."
  replace: [x: "*"]

- name: simple-sub
  tag: indexed-by
  # invisible comma -- want "x 1 when subscript is an integer"
  match: "count(*)=2 and $Verbosity='Terse' and *[2][self::m:mn and translate(., '.,', '')=.]"
  replace:
  - x: "*[1]"
  - x: "*[2]"
  - pause: short

- name: no-end-sub
  tag: indexed-by
  match: "IsNode(*[2], 'leaf') or *[2][self::m:mrow][*[2][.='⁣']]"
  replace:
  - x: "*[1]"
  - test:
      if: "$Verbosity!='Terse' or not(*[2][self::m:mn])" # just say "x 1" for terse vs "x sub 1"
      then: [T: 'indeks']
  - x: "*[2]"

- name: default
  tag: msubsup
  match: "."
  replace:
  - x: "*[1]"
  - T: "indeks"
  - x: "*[2]"
  - T: "pangkat"
  - x: "*[3]"
  - T: "baris basis"

- name: default
  tag: munder
  match: "."
  replace:
  - test:
      if: "not(IsNode(*[1], 'leaf'))"
      then: [T: 'diubah']
  - x: "*[1]"
  - T: 'dengan'
  - x: "*[2]"
  - T: di bawah

- name: default
  tag: mover
  match: "."
  replace:
  - test:
      if: "not(IsNode(*[1], 'leaf'))"
      then: [T: 'diubah']
  - x: "*[1]"
  - T: 'dengan'
  - x: "*[2]"
  - T: 'di atas'

- name: default
  tag: munderover
  match: "."
  replace:
  - test:
      if: "not(IsNode(*[1], 'leaf'))"
      then: [T: 'diubah']
  - T: 'dengan'
  - x: "*[1]"
  - pause: medium
  - T: 'di bawah'
  - x: "*[2]"
  - T: 'dan di atas'
  - x: "*[3]"

- name: default
  #   Here we support up to 2 prescripts and up to 4 postscripts -- that should cover all reasonable cases
  #   If there are more, we just dump them out without regard to sup/super :-(
  # FIX: this could use more special cases 
  # There is (currently) no way in MathCAT to deal with n-ary arguments other than "all" ('*') or an individual entry ('*[1]').
  tag: mmultiscripts
  match: "."
  variables:
  # computing the number of postscripts is messy because of <mprescripts> being optionally present -- we use "mod" to get the count right
  - Prescripts: "m:mprescripts/following-sibling::*"
  - NumChildren: "count(*)" # need to stash this since the count is wrong inside '*[...]' below
  - Postscripts: "*[position()>1 and position() < (last() + ($NumChildren mod 2) -count($Prescripts))]"
  replace:
  - x: "*[1]"
  - test:
      if: "$Prescripts" # more common case
      then:
      - with:
          variables:
          - PreSubscript: "IfThenElse($Verbosity='Verbose', 'pre subscript', 'pre sub')"
          - PreSuperscript: "IfThenElse($Verbosity='Verbose', 'pre superscript', 'pre super')"
          replace:
          - test: # only bother announcing if there is more than one prescript
              if: "count($Prescripts) > 2"
              then:
              - T: "dengan"
              - x: "count($Prescripts) div 2"
              - T: "pra-superskrip"
              - pause: short
          - test:
              if: "not($Prescripts[1][self::m:none])"
              then:
              - x: "$PreSubscript"
              - x: "$Prescripts[1]"
          - test:
              if: "not($Prescripts[1][self::m:none] or $Prescripts[2][self::m:none])"
              then: [T: "dan"]
          - test:
              if: "not($Prescripts[2][self::m:none])"
              then:
              - x: "$PreSuperscript"
              - x: "$Prescripts[2]"
          - pause: short
          - test:
              if: "count($Prescripts) > 2" # more common case
              then:
              - test:
                  if: "not($Prescripts[3][self::m:none])"
                  then:
                  - x: "$PreSubscript"
                  - x: "$Prescripts[3]"
              - test:
                  if: "not($Prescripts[3][self::m:none] or $Prescripts[4][self::m:none])"
                  then: [T: "dan"]
              - test:
                  if: "not($Prescripts[4][self::m:none])"
                  then:
                  - x: "$PreSuperscript"
                  - x: "$Prescripts[4]"
              - test:
                  if: "count($Prescripts) > 4" # give up and just dump them out so at least the content is there
                  then:
                  - T: "dan bergantian pra-superskrip"
                  - x: "$Prescripts[position() > 4]"
                  - T: "akhir pra-superskrip"
  - test:
      if: "$Postscripts"
      then:
      - with:
          variables:
          - PostSubscript: "IfThenElse($Verbosity='Verbose', 'subscript', 'sub')"
          - PostSuperscript: "IfThenElse($Verbosity='Verbose', 'superscript', 'super')"
          replace:
          - test: # only bother announcing if there is more than one postscript
              if: "count($Postscripts) > 2"
              then:
              - test:
                  if: "$Prescripts"
                  then: [T: "dan"]
              - T: "dengan"
              - x: "count($Postscripts) div 2"
              - T: "postskrip"
              - pause: short
          - test:
              if: "not($Postscripts[1][self::m:none])"
              then:
              - x: "$PostSubscript"
              - x: "$Postscripts[1]"
          - test:
              if: "not($Postscripts[1][self::m:none] or $Postscripts[2][self::m:none])"
              then: [T: "dan"]
          - test:
              if: "not($Postscripts[2][self::m:none])"
              then:
              - x: "$PostSuperscript"
              - x: "$Postscripts[2]"
          - test:
              if: "count($Postscripts) > 2"
              then:
              - test:
                  if: "not($Postscripts[3][self::m:none])"
                  then:
                  - x: "$PostSubscript"
                  - x: "$Postscripts[3]"
              - test:
                  if: "not($Postscripts[3][self::m:none] or $Postscripts[4][self::m:none])"
                  then: [T: "dan"]
              - test:
                  if: "not($Postscripts[4][self::m:none])"
                  then:
                  - x: "$PostSuperscript"
                  - x: "$Postscripts[4]"
              - test:
                  if: "count($Postscripts) > 4"
                  then:
                  - test:
                      if: "not($Postscripts[5][self::m:none])"
                      then:
                      - x: "$PostSubscript"
                      - x: "$Postscripts[5]"
                  - test:
                      if: "not($Postscripts[5][self::m:none] or $Postscripts[6][self::m:none])"
                      then: [T: "dan"]
                  - test:
                      if: "not($Postscripts[6][self::m:none])"
                      then:
                      - x: "$PostSuperscript"
                      - x: "$Postscripts[6]"
                  - test:
                      if: "count($Postscripts) > 6"
                      then:
                      - test:
                          if: "not($Postscripts[7][self::m:none])"
                          then:
                          - x: "$PostSubscript"
                          - x: "$Postscripts[7]"
                      - test:
                          if: "not($Postscripts[7][self::m:none] or $Postscripts[8][self::m:none])"
                          then: [T: "dan"]
                      - test:
                          if: "not($Postscripts[8][self::m:none])"
                          then:
                          - x: "$PostSuperscript"
                          - x: "$Postscripts[8]"
                      - test:
                          if: "count($Postscripts) > 8" # give up and just dump them out so at least the content is there
                          then:
                          - T: "dan skrip bergantian"
                          - x: "$Postscripts[position() > 8]"
                          - T: "akhir skrip"

- name: default
  tag: mtable
  variables:
  - IsColumnSilent: "false()"
  - NumColumns: "count(*[1]/*) - IfThenElse(*/self::m:mlabeledtr, 1, 0)"
  match: "."
  replace:
  - T: 'tabel dengan'
  - x: count(*)
  - test:
      if: count(*)=1
      then: [T: 'baris']
      else: [T: 'baris']
  - T: dan
  - x: "$NumColumns"
  - test:
      if: "$NumColumns"
      then: [T: 'kolom']
      else: [T: 'kolom']
  - pause: long
  - x: "*"

- # this may get called from navigation -- in that case, there is no context to speak the row #, so don't do it
  # callers/context should do that.
  name: default
  tag: mtr
  match: "."
  replace:
  - x: "*"

- name: default
  tag: mtd
  match: "."
  replace:
  - T: 'kolom'
  - x: "count(preceding-sibling::*)+1"
  - pause: medium
  - x: "*" # speak the entry
  - pause: long

- # Note: @notation can contain more than one value
  # The ordering below is the order in which words come out when there is more than one value
  name: default
  tag: menclose
  match: "."
  replace:
  - test:
      if: ".[contains(concat(' ', normalize-space(@notation), ' '), ' box ')]"
      then: [T: kotak, pause: short]
  - test:
      if: ".[contains(@notation,'roundedbox')]"
      then: [T: kotak bulat, pause: short]
  - test:
      if: ".[contains(@notation,'circle')]"
      then: [T: lingkaran, pause: short]
  - test:
      if: ".[ contains(concat(' ', normalize-space(@notation), ' '), ' left ') or contains(concat(' ', normalize-space(@notation), ' '), ' right ') or contains(@notation,'top') or contains(@notation,'bottom') ]"
      then:
      - T: baris aktif
      - test:
          if: ".[contains(concat(' ', normalize-space(@notation), ' '), ' left ')]"
          then: [T: kiri, pause: short]
      - test:
          if: ".[contains(concat(' ', normalize-space(@notation), ' '), ' right ')]"
          then: [T: kanan, pause: short]
      - test:
          if: ".[contains(@notation,'top')]"
          then: [T: atas, pause: short]
      - test:
          if: ".[contains(@notation,'bottom')]"
          then: [T: bawah, pause: short]
  - test:
      if: ".[ contains(@notation,'updiagonalstrike') or contains(@notation,'downdiagonalstrike') or contains(@notation,'verticalstrike') or contains(@notation,'horizontalstrike') ]"
      then:
      - test:
          if: ".[contains(@notation,'updiagonalstrike') and contains(@notation,'downdiagonalstrike')]"
          then: [spell: x, pause: short] # seems better to say 'x cross out' than 'up diagonal, down diagonal cross out'
          else:
          - test:
              if: ".[contains(@notation,'updiagonalstrike')]"
              then: [T: diagonal ke atas, pause: short]
          - test:
              if: ".[contains(@notation,'downdiagonalstrike')]"
              then: [T: diagonal ke bawah, pause: short]
      - test:
          if: ".[contains(@notation,'verticalstrike')]"
          then: [T: vertikal, pause: short]
      - test:
          if: ".[contains(@notation,'horizontalstrike')]"
          then: [T: horizontal, pause: short]
      - T: mencoret
      - pause: short
  - test:
      if: ".[contains(@notation,'uparrow')]"
      then: [T: panah atas, pause: short]
  - test:
      if: ".[contains(concat(' ', normalize-space(@notation), ' '), ' downarrow ')]"
      then: [T: panah bawah, pause: short]
  - test:
      if: ".[contains(@notation,'leftarrow')]"
      then: [T: panah kiri, pause: short]
  - test:
      if: ".[contains(concat(' ', normalize-space(@notation), ' '), ' rightarrow ')]"
      then: [T: panah kanan, pause: short]
  - test:
      if: ".[contains(@notation,'northeastarrow')]"
      then: [T: panah timur laut, pause: short]
  - test:
      if: ".[contains(concat(' ', normalize-space(@notation), ' '), ' southeastarrow ')]"
      then: [T: panah tenggara, pause: short]
  - test:
      if: ".[contains(concat(' ', normalize-space(@notation), ' '), ' southwestarrow ')]"
      then: [T: panah barat daya, pause: short]
  - test:
      if: ".[contains(@notation,'northwestarrow')]"
      then: [T: panah barat laut, pause: short]
  - test:
      if: ".[contains(@notation,'updownarrow')]"
      then: [T: panah vertikal ujung ganda, pause: short]
  - test:
      if: ".[contains(@notation,'leftrightarrow')]"
      then: [T: panah horizontal ujung ganda, pause: short]
  - test:
      if: ".[contains(@notation,'northeastsouthwestarrow')]"
      then: [T: panah diagonal atas ujung ganda, pause: short]
  - test:
      if: ".[contains(@notation,'northwestsoutheastarrow')]"
      then: [T: panah diagonal bawah ujung ganda, pause: short]
  - test:
      if: ".[contains(@notation,'actuarial')]"
      then: [T: simbol aktuaria, pause: short]
  - test:
      if: ".[contains(@notation,'madrub')]"
      then: [T: simbol faktorial arab, pause: short]
  - test:
      if: ".[contains(@notation,'phasorangle')]"
      then: [T: sudut fasor, pause: short]
  - test:
      if: ".[contains(@notation,'longdiv') or not(@notation) or normalize-space(@notation) ='']" # default
      then: [T: simbol pembagian panjang, pause: short]
  - test:
      if: ".[contains(@notation,'radical')]"
      then: [T: akar pangkat dua, pause: short]
  - T: melampirkan
  - test:
      if: "*[self::m:mtext and .=' ']"
      then: [T: "beberapa ruang"]     # (en: "some space") otherwise there is complete silence
      else: [x: "*"]
  - test:
      if: "$Impairment = 'Blindness' and ( $SpeechStyle != 'SimpleSpeak' or not(IsNode(*[1], 'leaf')) )"
      then: [T: penutup akhir]
  - pause: short

- name: semantics
  tag: "semantics"
  match: "*[@encoding='MathML-Presentation']"
  replace:
  - x: "*[@encoding='MathML-Presentation']/*[1]"

- name: semantics-default
  tag: "semantics"
  match: .
  replace:
  - x: "*[1]"

# Here are the intent hints that need to be handled: 'prefix' | 'infix' | 'postfix' | 'function' | 'silent'
- name: silent-intent
  # uncaught intent -- the args have been inserted in the order of speech 
  tag: "*"
  match: "count(*)>0 and (contains(@data-intent-property, ':silent:') or translate(name(.), '-_', '')='')"
  replace:
  - x: "*"
  - test:
      if: "IsNode(., '2D')"
      then: [pause: short]
      else: [pause: auto]

- name: prefix-intent
  # uncaught intent -- the args have been inserted in the order of speech 
  tag: "*"
  match: "count(*)>0 and contains(@data-intent-property, ':prefix:')"
  replace:
  - x: "SpeakIntentName(name(.), $Verbosity, 'prefix')"
  - x: "*"
  - test:
      if: "not( IsBracketed(., '', '') or IsNode(*[last()], 'simple') )"
      then: [x: "GetBracketingIntentName(name(.), $Verbosity, 'prefix', 'end')"]
  - test:
      if: "IsNode(., '2D')"
      then: [pause: short]
      else: [pause: auto]

- name: postfix-intent
  # uncaught intent -- the args have been inserted in the order of speech 
  tag: "*"
  match: "count(*)>0 and contains(@data-intent-property, ':postfix:')"
  replace:
  - test:
      if: "$Impairment = 'Blindness' and not( IsBracketed(., '', '') or IsNode(*[1], 'simple') )"
      then: [x: "GetBracketingIntentName(name(.), $Verbosity, 'postfix', 'start')"]
  - x: "*"
  - x: "SpeakIntentName(name(.), $Verbosity, 'postfix')"

- name: infix-intent
  # uncaught intent -- the args have been inserted in the order of speech 
  tag: "*"
  match: "count(*)>0 and contains(@data-intent-property, ':infix:')"
  replace:
  - test:
      if: "$Impairment = 'Blindness' and not( IsBracketed(., '', '') or IsNode(*[1], 'simple') )"
      then: [x: "GetBracketingIntentName(name(.), $Verbosity, 'infix', 'start')"]
  - test:
      if: "count(*) = 1"  # in cases such as continued-row, plus/minus might have just one child
      then:
      - x: "SpeakIntentName(name(.), $Verbosity, 'infix')"
      - pause: auto
      - x: "*[1]"
      else:
      - insert:
          nodes: "*"
          replace: [x: "SpeakIntentName(name(.), $Verbosity, 'infix')", pause: auto]
  - test:
      if: "$Impairment = 'Blindness' and not( IsBracketed(., '', '') or IsNode(*[last()], 'simple') )"
      then: [x: "GetBracketingIntentName(name(.), $Verbosity, 'infix', 'end')"]
  - test:
      if: "IsNode(., '2D')"   # add (probably) a slightly longer pause if this came from a 2D node
      then: [pause: short]
      else: [pause: auto]

- name: function-intent
  # uncaught intent -- speak as foo of arg1 comma arg2 .... The MathML spec requires arguments to functions
  tag: "*"
  match: "count(*)>0"
  replace:
  - x: "SpeakIntentName(name(.), $Verbosity, 'function')"
  - test:
      if: "not(contains(@data-intent-property, ':literal:')) and
           not(count(*)=2 and (IsInDefinition(*[1], 'TrigFunctionNames') or IsInDefinition(name(.), 'TerseFunctionNames')) and IsNode(*[2], 'simple'))"
      then: [T: "", pause: auto]      # phrase(sine 'of' 5)
  - insert:
      nodes: "*"
      replace:
      - test:
          if: "not(contains(@data-intent-property, ':literal:'))"
          then: [x: "','"]
      - pause: auto
  - test:
      if: "$Impairment = 'Blindness' and not(*[last()][IsBracketed(., '', '') or IsNode(., 'simple')] )"
      then: [x: "GetBracketingIntentName(name(.), $Verbosity, 'function', 'end')"]
  - test:
      if: "IsNode(., '2D')"
      then: [pause: short]
      else: [pause: auto]


- name: default-text
  # unknown leaf -- just speak the text -- could be a literal intent
  tag: "*"
  match: "."
  replace:
  - x: "translate(name(), '-', ' ')"
