---
# Documentation:
#
# The general form for many rules is:
# 1. Say the command if this is first rule to fire (MatchCounter) and depending upon "NavVerbosity"s value
# 2. Say info about moving into/out of 2D structures
# 3. Set some variables and possibly recurse.
#    If recursing, "MatchCounter" should be incremented.
#    If stopping, "NavNode" should be set.
#
# The meaning of NavVerbosity:
# * Verbose -- always echo the command and end points (e.g., "can't move right")
# * Medium -- only echo the command for obscure commands like the placemarker commands; also say end points
# * Terse -- no echo of commands or end points
# 
# For the second item, a common set of rules is used. These rules require the variable "Move2D"
# to be set along with "Child2D", where "Move2D" is either 'in' or 'out'.
#
# In addition, the navigation rules make use of two functions:
#
# int DistanceFromLeaf(node, leftSide, treat2DElementsAsTokens)
#   Returns the distance (number of children) until a leaf is reached by traversing the leftmost/rightmost child
#   If 'treat2DElementsAsTokens' is true, then 2D notations such as fractions are treated like leaves 
#   A leaf has distance == 0
#
# EdgeNode(node, "left"/"right", stopNodeName)
#   Returns the stopNode if at left/right edge of named ancestor node. 'stopNodeName' can also be "2D"
#   If the stopNode isn't found, the original node is returned
#  Note: if stopNodeName=="math", then punctuation is taken into account since it isn't really part of the math
#
# A few other variables are of importance to Navigation
# NavMode -- Enhanced, Simple, Character
# ReadZoomLevel -- -1 for Enhanced, otherwise the distance from leaf the rules should maintain
# PlaceMarkerIndex

# Rules for announcing the command
- name: say-command
  tag: "!*"
  match: "$SayCommand != ''"   # value should be '', 'true', or 'false'
  variables: [Prefix: "''"]
  replace:
  - test:
    - if: "$MatchCounter = 0 and $SayCommand = 'true'"
      then_test:
      - if: "self::m:math and starts-with($NavCommand, 'ZoomOut')"
        then: [T: "zoomet helt ut", pause: "medium"]
      - else_if: "IsNode(., 'leaf') and starts-with($NavCommand, 'ZoomIn')"
        then:
        - test:
          - if: "string-length(.) = 1"
            then: [T: "zoomet helt inn"]       # phrase('zoomed in all of the way')
          - else_if: "$NavNodeOffset = 0"
            then: [T: "zoomet inn til første tegn"]   # phrase('zoomed in to first character')
            else: [T: "zoomet inn til tegn"]          # phrase('zoomed in to character')
        - pause: "medium"
        else:
        - test:
          - if: "starts-with($NavCommand, 'Zoom')"
            then: [set_variables: [Prefix: "'zoom'", CommandOffset: "5"]]          # phrase('zoom' in to see more details)     
          - else_if: "starts-with($NavCommand, 'Move')"
            then: [set_variables: [Prefix: "'gå'", CommandOffset: "5"]]          # phrase('move' to next entry in table)     
          - else_if: "starts-with($NavCommand, 'Read')"
            then: [set_variables: [Prefix: "'les'", CommandOffset: "5"]]          # phrase('read' to next entry in table)     
          - else_if: "starts-with($NavCommand, 'Describe')"
            then: [set_variables: [Prefix: "'beskriv'", CommandOffset: "9"]]      # phrase('describe' to next entry in table)
        - test:
            if: "$Prefix != ''"
            then:
            - x: "$Prefix"
            - test:
              - if: "substring($NavCommand, $CommandOffset) = 'In'"
                then: [T: "inn"]                                  # phrase(zoom 'in' to see more details)
              - else_if: "substring($NavCommand, $CommandOffset) = 'InAll'"
                # HACK: '\uF8FE' is used internally for the concatenation char by 'ct' -- this gets "ed" concatenated to "zoom"
                then: [T: "\uF8FEet helt inn"]                     # phrase(zoom 'out all of the way' to see more details)
              - else_if: "substring($NavCommand, $CommandOffset) = 'Out'"
                then: [T: "ut"]                                 # phrase(zoom 'out' to see more details)
              - else_if: "substring($NavCommand, $CommandOffset) = 'OutAll'"
                # HACK: '\uF8FE' is used internally for the concatenation char by 'ct' -- this gets "ed" concatenated to "zoom"
                then: [T: "\uF8FEet helt ut"]                     # phrase(zoom 'out all of the way' to see more details)
              - else_if: "substring($NavCommand, $CommandOffset) = 'Next'"
                then: [T: "høyre"]                               # phrase(move to the 'right')
              - else_if: "substring($NavCommand, $CommandOffset) = 'Previous'"
                then: [T: "venstre"]                                # phrase(move to the 'left')
              - else_if: "substring($NavCommand, $CommandOffset) = 'Current'"
                then: [T: "nåværende"]                                 # phrase(who is the 'current' president)
              - else_if: "substring($NavCommand, $CommandOffset) = 'LineStart'"
                then: [T: "til starten av raden"]                                 # phrase(move 'to start of line')
              - else_if: "substring($NavCommand, $CommandOffset) = 'LineEnd'"
                then: [T: "til slutten av raden"]                                 # phrase(move 'to end of line')
            - pause: "medium"
  - set_variables: [MatchCounter: "$MatchCounter + 1"]

- name: into-or-out-of-silent
  tag: "*"
  # saying "out of row n" is not very useful, so skip it
  match: "$Move2D != '' and (not(@data-from-mathml) or @data-from-mathml = name(.)) and
          (name(.)='mrow' or name(.) = 'mtr' or name(.) = 'mlabeledtr' or @data-from-mathml = 'mtable')"
  replace: []

- name: into-or-out-of-minus-silent-on-zoom-out
  tag: "*"
  match: "$Move2D != '' and name(.)='minus' and count(*)=1 and ($NavCommand = 'ZoomOut' or $NavCommand = 'ZoomOutAll')"
  replace: []

- name: into-or-out-of-mtr
  tag: [mtr, mlabeledtr]
  match: "$Move2D = 'i'" # Navigate into a 2D structure.
  replace:
  - T: "kolonne"
  - x: "count($Child2D/preceding-sibling::*)+1" # Count number of sibling nodes before Child2D (the node being navigated into) and add 1 to get the column number.
  - pause: "medium"

- name: into-or-out-of-mmultiscripts
  tag: "*"
  match: "$Move2D != '' and (@data-from-mathml='mmultiscripts' or self::m:mmultiscripts)" # Navigate into a 2D structure that is a mmultiscripts.
  replace:
  - test:
      if: "name($Child2D)!='none'" # Check that the child being navigated into is not empty.
      then:
      - with:
          variables:
          - NumPrecedingSiblings: "count($Child2D/preceding-sibling::*)" # Store the number of siblings before the target node.
          replace:
          - x: "$Move2D" # Say the direction (into/out of)
          - test:
            - if: "$NumPrecedingSiblings=0" # No siblings before the target node
              then: [T: "base"]                 # phrase(the 'base' of the power)
            - else_if: "$Child2D/preceding-sibling::*[self::m:mprescripts]" # Are we after the <mprescripts> tag? If so, we are in the prescripts.
              then:
              - test:   # in postscripts -- base shifts by one
                  if: "$NumPrecedingSiblings mod 2 = 0" 
                  then: [T: "nedre venstre indeks"]       # phrase(x with 'subscript' 2)
                  else: [T: "øvre venstre indeks"]     # phrase(x with 'superscript' 2)
              else:
              - test:
                  if: "$NumPrecedingSiblings mod 2 = 0"
                  then: [T: "øvre indeks"]    # phrase(x with 'pre-superscript' 2)
                  else: [T: "nedre indeks"]      # phrase(x with 'pre-subscript' 2)
          - pause: "medium"

# Rules for speaking what happens when moving into or out of a notation
- name: into-or-out-of-default
  tag: "*"
  # saying "out of row n" is not very useful, so skip it
  # match: "$Move2D != '' and @data-from-mathml and @data-from-mathml != name(.) and count(*)>1 and @data-from-mathml != 'mtable'"
  match: "$Move2D != '' and not(self::m:math or @data-from-mathml = 'mtable' or  @data-from-mathml = 'mtd') "
  replace:
  - with:
      variables:
      - PartNumber: "count($Child2D/preceding-sibling::*)"  # Count the number of siblings before the target node
      - PartName: "GetNavigationPartName(name(.), $PartNumber)" # Find the name of the part. E.g., numerator/denominator, base/exponent
      replace:
      - x: "$Move2D"   # into/out of
      - test:
        - if: "$PartName != ''" # if a name for the part exists
          then: [x: "$PartName"]
        - else_if: "count(*) = 1" # if the node has one child
          then_test:
            if: "$NavVerbosity = 'Verbose'"
            then: [x: "translate(name(.), '-_', ' ')"]      # e.g., "in absolute value"
          else:
          - T: "del"         # phrase(the 'part' of the expression)
          - x: "count($Child2D/preceding-sibling::*) + 1"
      - pause: "medium"

- name: default-move
  # nothing to do (not 2D) -- need to catch $Move2D though so rules based on NavCommand don't trigger
  tag: "*"
  match: "$Move2D != ''"
  replace: []

# ********* Go back to last position ***************
# This is first since start/end position shouldn't matter
- name: move-last-location


  tag: "*"
  match: "$NavCommand = 'MoveLastLocation'"
  replace:
  - test:
      if: "$NavVerbosity != 'Terse'"
      then:
      - test:
        - if: "$PreviousNavCommand = 'ZoomIn'"
          then: [T: "angre zoom inn"]                       # phrase('undo zoom in')
        - else_if: "$PreviousNavCommand = 'ZoomOut'"
          then: [T: "angre zoom ut"]                      # phrase('undo zoom out')
        - else_if: "$PreviousNavCommand = 'ZoomInAll'"
          then: [T: "angre zooming helt inn"]        # phrase('undo zooming in all of the way')
        - else_if: "$PreviousNavCommand = 'ZoomOutAll'"
          then: [T: "angre zooming helt ut"]       # phrase('undo zooming out all of the way')
        - else_if: "$PreviousNavCommand = 'MovePrevious' or $PreviousNavCommand = 'MovePreviousZoom'"
          then: [T: "angre gå venstre"]                     # phrase('undo move left')
        - else_if: "$PreviousNavCommand = 'MoveNext' or $PreviousNavCommand = 'MoveNextZoom'"
          then: [T: "angre gå høyre"]                    # phrase('undo move right')
        - else_if: "$PreviousNavCommand = 'None'"
          then: [T: "ingen tidligere kommandoer"]                # phrase('no previous command')
      - pause: "medium"
  - set_variables: [NavNode: "@id"]

# many times, for typographic reasons, people include punctuation at the end of a math expr
# these rules detect that and skip speaking it (should be similar regular rule)
- name: skip-punct-at-end-zoom-in
  tag: mrow
  match:
  - "($NavCommand = 'ZoomIn' or $NavCommand = 'ZoomInAll' or $NavCommand = 'MoveNextZoom' or $NavCommand = 'MovePreviousZoom') and"
  - " parent::m:math and count(*)=2 and"
  - " *[2][translate(.,'.,;:?', '')='']"
  replace:
  - x: "*[1]"

# ********* ZoomIn  ***************
- name: zoom-in-leaf
  tag: "*"
  match: "($NavCommand = 'ZoomIn' or $NavCommand = 'ZoomInAll') and IsNode(., 'leaf')"
  replace:
  - with:
      variables: [SayCommand: "string($NavVerbosity != 'Terse')"]
      replace: [x: "."]
  - test:
      if: "$ReadZoomLevel !=-1"
      then:
      - set_variables: [ReadZoomLevel: "0"]
  - set_variables:
      - NavNode: "@id"
      - NavNodeOffset: "IfThenElse(string-length(.) > 1 and $MatchCounter = 1 and $NavNodeOffset = 0, '1', '0')"

# special case of zooming into a table -- move to the first row (if only one row, first column)
- name: zoom-in-table
  tag: "*"
  match: "$NavCommand = 'ZoomIn' and (name(.) = 'mtable' or (count(*)=1 and *[1][@data-from-mathml='mtable']))"
  replace:
  - with:
      variables: [SayCommand: "string($NavVerbosity = 'Verbose')"]
      replace: [x: "."]
  - set_variables: [NavNode: "IfThenElse(count(*)=1, (*[1]/*[1]/@id), (*[1]/@id))"]

- name: zoom-in-mrow-in-math
  # zooming in only once is meaningless because 'math' has only a single child and it was spoken at the math level -- dig inside and do it again 
  tag: math
  match: "$NavCommand = 'ZoomIn' or $NavCommand = 'MoveNextZoom' or $NavCommand = 'MovePreviousZoom'"
  replace:
  - test:
      if: "$NavCommand = 'MovePreviousZoom'"
      then: [x: "*[last()]"]
      else: [x: "*[1]"]

- # For msqrt and menclose, if the single child isn't an mrow, don't zoom in
  # Norwegian: Not sure if the word "in" should be translated or not.
  name: zoom-in-again
  tag: "*"
  match:
  - "($NavCommand = 'ZoomIn' or "
  - "  ($NavCommand = 'MoveNextZoom' or $NavCommand = 'MovePreviousZoom') and $NavMode='Enhanced') and "
  - "count(*)=1 and
     (*[1][self::m:mrow or @data-from-mathml='mrow'] and
      not(@data-from-mathml='msqrt' or self::m:msqrt or @data-from-mathml='menclose' or self::m:menclose))" # current node has one child that is an <mrow>. The current node is not msqrt or menclose.
  replace:
  - with:
      variables: [SayCommand: "string($NavVerbosity = 'Verbose')"] # if verbosity is verbose, SayCommand is set to true, otherwise false
      replace: [x: "."] # continue with the current node
  - test:
      if: "not(*[1][self::m:mrow or @data-from-mathml='mrow'])"
      then:
      - with:
      # Set Move2D to "i".
      # Set Child2D to the last child if the command is "MovePreviousZoom", otherwise the first child.
          variables: [Move2D: "'i'", Child2D: "IfThenElse($NavCommand = 'MovePreviousZoom', (*[last()]), (*[1]))"]   # phrase('in' the denominator) 
          replace: [x: "IfThenElse($NavCommand = 'MovePreviousZoom', 1, $Child2D)"]
  - test:
      if: "$NavCommand = 'MovePreviousZoom'"
      then: [x: "*[last()]"]
      else: [x: "*[1]"]

- name: zoom-in-enhanced
  tag: "*"
  match: "$NavCommand = 'ZoomIn' and $NavMode='Enhanced'"
  replace:
  - with:
      variables: [SayCommand: "string($NavVerbosity = 'Verbose')"]
      replace: [x: "."]
  - test:
    - if: "self::m:mtr or self::m:mlabeledtr"
      then:
      - with:
          variables: [Move2D: "'i'", Child2D: "*[1]/*[1]"]   # phrase('in' the denominator)
          replace: [x: "."]
      - set_variables: [NavNode: "*[1]/*[1]/@id"] # skip mtd
    - else_if: "*[1][self::m:mrow and (IsBracketed(., '(', ')', false) or IsBracketed(., '[', ']', false))]" # auto zoom
      then:
      - with:
          variables: [Move2D: "'i'", Child2D: "*[1]"]   # phrase('in' the denominator)
          replace: [x: "."]
      - set_variables: [NavNode: "*[1]/*[2]/@id"]        # skip parens/brackets
      else:
      - with:
          variables: [Move2D: "'i'", Child2D: "*[1]"]        # phrase('in' the denominator)
          replace: [x: "."]
      # "(...)" to get around some weird parse bug"
      - set_variables: 
          - NavNode: "*[1]/@id"
          - NavNodeOffset: "IfThenElse(*[1]/@data-id-offset, (*[1]/@data-id-offset), '0')"

- name: zoom-in-simple
  tag: "*"
  match: "$NavCommand = 'ZoomIn' and $NavMode='Simple'"
  replace:
  - with:
      variables: [SayCommand: "string($NavVerbosity = 'Verbose')"]
      replace: [x: "."]
  - test:
      if: "$MatchCounter > 1 and IsNode(., '2D')"
      then:
      - set_variables:       # time to stop, not going "in" to next thing, so before "Move2D"
          - NavNode: "@id"
          - NavNodeOffset: "IfThenElse(@data-id-offset, @data-id-offset, '0')"
      else:
      - with:
          variables: [Move2D: "'i'", Child2D: "*[1]"]        # phrase('in' the denominator)
          replace: [x: "."]
      - x: "*[1]"

  # At this point, we are zooming in on a non-2D element, non-leaf in Character mode
- name: zoom-in-2D-character
  tag: "*"
  match: "$NavCommand = 'ZoomIn' and (IsNode(., '2D') or not(IsNode(., 'mathml')))"
  replace:
  - with:
      variables: [SayCommand: "string($NavVerbosity = 'Verbose')"]
      replace: [x: "."]
  - with:
      variables: [Move2D: "'i'", Child2D: "*[1]"]          # phrase('in' the denominator)
      replace: [x: "."]
  - test:
      if: "$NavMode = 'Simple'"
      then:
      - set_variables: [NavNode: "*[1]/@id"]
      else:
      - with:
          variables: [NavCommand: "'MoveNextZoom'"]
          replace: [x: "*[1]"]

  # At this point, we are zooming in on a non-2D element, non-leaf in Character mode
- name: zoom-in-default
  tag: "*"
  match: "$NavCommand = 'ZoomIn'"
  replace:
  - with:
      variables: [SayCommand: "string($NavVerbosity = 'Verbose')"]
      replace: [x: "."]
  - x: "*[1]"

- name: zoom-in-all-default
  tag: "*"
  match: "$NavCommand = 'ZoomInAll'"
  replace:
  - with:
      variables: [SayCommand: "string($NavVerbosity = 'Verbose')"]
      replace: [x: "."]
  - with:
      variables: [Move2D: "'i'", Child2D: "*[1]"]              # phrase('in' the denominator)
      replace: [x: "."]
  - x: "*[1]"

- name: zoom-out
  tag: math
  match: "$NavCommand = 'ZoomOut' or $NavCommand = 'ZoomOutAll'"
  replace:
  - with:
      variables: [SayCommand: "string($NavVerbosity != 'Terse')"]
      replace: [x: "."]
  - set_variables: [NavNode: "*[1]/@id"] # no-op for $NavCommand = 'ZoomOut'

- name: skip-punct-at-end-zoom-out
  tag: mrow
  match:
  - "($NavCommand = 'ZoomOut' or $NavCommand = 'ZoomOutAll') and"
  - " parent::m:math and count(*)=2 and"
  - " *[2][translate(.,'.,;:?', '')='']"
  replace:
  - x: ".."

- name: zoom-out-top
  tag: "*"
  match:
  - "($NavCommand = 'ZoomOut' or $NavCommand = 'ZoomOutAll') and"
  - "parent::m:math"
  replace:
  - x: ".." # let math rule deal with it

- name: zoom-out-all-default
  tag: "*"
  match: "$NavCommand = 'ZoomOutAll'"
  replace:
  - with:
      variables: [SayCommand: "string($NavVerbosity = 'Verbose')"]
      replace: [x: "."]
  - with:
      variables: [Move2D: "'ut av'", Child2D: "."]
      replace: [x: ".."]
  - x: ".."

# deal with internal zooming: MoveNextZoom and MovePreviousZoom

# start with Enhanced mode
- name: move-zoom-enhanced
  tag: "*"
  match:
  - "($NavCommand = 'MoveNextZoom' or $NavCommand = 'MovePreviousZoom') and "
  - "$NavMode = 'Enhanced'"
  replace:
  - with:
      variables: [Move2D: "'i'", Child2D: "*[1]"]            # phrase('in' the denominator)
      replace: [x: "."]
  - test:
    - if: "count(*)> 1 or IsNode(., 'leaf') or
           @data-from-mathml='msqrt' or self::m:msqrt or @data-from-mathml='menclose' or self::m:menclose"
      then:
      - set_variables:
          - NavNode: "@id"
          - NavNodeOffset: "IfThenElse(@data-id-offset, @data-id-offset, '0')"
      else: [x: "*[1]"]

- name: move-next-zoom-not-enhanced
  # $ReadZoomLevel must be >= 0
  tag: "*"
  match: "$NavCommand = 'MoveNextZoom'"
  replace:
  #don't bother with MatchCounter since we only get here if > 1
  - test:
      if: "IsNode(., 'leaf') or $ReadZoomLevel >= DistanceFromLeaf(., false, $NavMode!='Character')"
      then:
      # - with:
      #     variables: [Move2D: "'i'", Child2D: "following-sibling::*[1]"]    # phrase('in' the denominator)
      #     replace: [x: ".."]
      - set_variables:
          - NavNode: "@id"
          - NavNodeOffset: "IfThenElse(@data-id-offset, @data-id-offset, '0')"
      else:
      - with:
          variables: [Move2D: "'i'", Child2D: "*[1]"]                        # phrase('in' the denominator)
          replace: [x: "."]
      - x: "*[1]"

- name: move-previous-zoom-not-enhanced
  # $ReadZoomLevel must be >= 0
  tag: "*"
  match: "$NavCommand = 'MovePreviousZoom'"
  replace:
  #don't bother with MatchCounter since we only get here if > 1
  - test:
      if: "$ReadZoomLevel >= DistanceFromLeaf(., true, $NavMode!='Character')"
      then:
      # - with:
      #     variables: [Move2D: "'in'", Child2D: "preceding-sibling::*[1]"]     # phrase('in' the denominator)
      #     replace: [x: ".."]
      - set_variables:
          - NavNode: "@id"
          - NavNodeOffset: "IfThenElse(@data-id-offset, @data-id-offset, '0')"
      else:
      - with:
          variables: [Move2D: "'i'", Child2D: "*[last()]"]                     # phrase('in' the denominator)
          replace: [x: "."]
      - x: "*[last()]"

# ********* ZoomOut  ***************
- name: zoom-out-default
  tag: mtd
  match: "$Move2D = '' and ($NavCommand = 'ZoomOut')"
  replace:
  - with:
      variables: [SayCommand: "string($NavVerbosity = 'Verbose')"]
      replace: [x: "."]
  # we need to speak it here
  # - t: "row"                                                  # phrase(the first 'row' of the matrix)
  #   # if we let the speech rules speak the row, it is given just the MathML for the row, so the row # will always be '1'
  # - x: "count(../preceding-sibling::*)+1"
  # - pause: medium
  - set_variables:
      - NavNode: "../@id"
      - NavNodeOffset: "IfThenElse(../@data-id-offset, ../@data-id-offset, '0')"

- name: zoom-out
  # a row around a single element -- these might duplicate the position/offset, so we jump an extra level here  
  tag: "*"
  match: "$NavCommand = 'ZoomOut'"
  replace:
  - with:
      variables: [SayCommand: "string($NavVerbosity = 'Verbose')"]
      replace: [x: "."]
  - test:
    - if: "$NavNodeOffset > 0 and IsNode(., 'leaf')"  # Inside leaf -- just reset offset, intent offset doesn't change
      then:
      - set_variables: [NavNodeOffset: "0"]
      # NavNode remains the same
    - else_if: "$NavMode='Enhanced' and parent::*[self::m:mrow and (IsBracketed(., '(', ')', false) or IsBracketed(., '[', ']', false))]"
      then: [x: ".."] # auto-zoom: move out a level and retry
      else:
      - with:
          variables: [Move2D: "'ut av'", Child2D: "."]   # phrase('out of' the denominator)
          replace: [x: ".."]
      - test:
          if: "parent::m:mtd"
          then: [x: ".."]
          else:
          - test:
              if: "DEBUG($ReadZoomLevel)!=-1"
              then: [set_variables: [ReadZoomLevel: "DistanceFromLeaf(.., true, $NavMode!='Character')"]]
          - set_variables:
              - NavNode: "../@id"
              - NavNodeOffset: "IfThenElse(../@data-id-offset, ../@data-id-offset, '0')"

# ********* MoveStart/End  ***************
- name: math-move-to-start-or-end
  tag: math
  match: "$NavCommand = 'MoveStart' or $NavCommand = 'MoveLineStart' or $NavCommand = 'MoveEnd' or $NavCommand = 'MoveLineEnd'"
  replace:
  - with:
      variables: [MatchCounter: "$MatchCounter + 1"]
      replace:
      - test:
          if: "$NavVerbosity = 'Verbose'"
          then:
          - test:
            - if: "$NavCommand = 'MoveStart'"
              then: [T: "gå til starten av uttrykket"]                  # phrase('move to start of math')
            - else_if: "$NavCommand = 'MoveLineStart'"
              then: [T: "gå til starten av raden"]                  # phrase('move to start of line')
            - else_if: "$NavCommand = 'MoveEnd'"
              then: [T: "gå til slutten av uttrykket"]                    # phrase('move to end of math')
              else: [T: "gå til slutten av raden"] # "$NavCommand = 'MoveLineEnd'"  # phrase('move to end of line')
          - pause: "medium"
      - test:
          if: "$NavCommand = 'MoveStart' or $NavCommand = 'MoveLineStart'"
          then:
          # move inside of the mrow inside of 'math' or inside the fraction, etc  (hence two levels down)
          # Note: an apparent bug in the xpath code doesn't let me use IfThenElse for the 2 if: then: below
          - with:
              variables: [NavCommand: "'MoveNextZoom'"]
              replace:
              - test:
                  if: "*[1]/*[1]"    # could be a <math><mi>x</mi></math>, so no grandchild
                  then: [x: "*[1]/*[1]"]
                  else: [x: "*[1]"]
          else:
          - with:
              variables: [NavCommand: "'MovePreviousZoom'"]
              replace:
              - test:
                  if: "*[last()]/*[last()]"  # could be a <math><mi>x</mi></math>, so no grandchild
                  then: [x: "*[last()]/*[last()]"]
                  else: [x: "*[last()]"]

# We stop when the parent is 2d (e.g., frac), but not if in leaf base of msub/msup/msubsup/mmultiscripts because that's really on the same line
- name: move-to-start-or-end-2d
  tag: "*"
  match:
  - "($NavCommand = 'MoveLineStart' or $NavCommand = 'MoveLineEnd') and IsNode(.., '2D') and"
  - "not( IsNode(., 'leaf') and"
  - "     parent::*[1][self::m:msub or self::m:msup or self::m:msubsup or self::m:mmultiscripts or"
  - "                 @data-from-mathml and"
  - "                  (@data-from-mathml='msub' or @data-from-mathml='msup' or"
  - "                   @data-from-mathml='msubsup' or @data-from-mathml='mmultiscripts')"
  - "                 ] )"
  replace:
  - test:
      if: "$NavVerbosity = 'Verbose'"
      then:
      - test:
          if: "$NavCommand = 'MoveLineStart'"
          then: [T: "gå til starten av raden"]                                # phrase('move to start of line')
          else: [T: "gå til slutten av raden"] # "$NavCommand = 'MoveLineEnd'"  # phrase('move to end of line')
      - pause: "medium"
  - test:
      if: "self::m:mrow or @data-from-mathml = 'mrow'"
      then_test:
        if: "$NavCommand = 'MoveLineStart'"
        then:
        - with:
            variables: [NavCommand: "'MoveNextZoom'"]
            replace: [x: "*[1]"]
        else:
        - with:
            variables: [NavCommand: "'MovePreviousZoom'"]
            replace: [x: "*[last()]"]
      else: [set_variables: [NavNode: "@id"]]

- name: move-to-start-or-end-default
  tag: "*"
  match: "$NavCommand = 'MoveStart' or $NavCommand = 'MoveLineStart' or $NavCommand = 'MoveEnd' or $NavCommand = 'MoveLineEnd'"
  replace:
  - with:
      variables: [MatchCounter: "$MatchCounter + 1"]
      replace: [x: ".."]

# Table-related movement
# Typically, we need to zoom out to the mtd level, then we move the appropriate direction
- name: not-in-table


  tag: math
  match:
  - "$NavCommand='MoveCellPrevious' or $NavCommand='MoveCellNext' or"
  - "$NavCommand='MoveCellUp' or $NavCommand='MoveCellDown' or"
  - "$NavCommand='MoveColumnStart' or $NavCommand='MoveColumnEnd' or"
  - "$NavCommand='ReadCellCurrent'"
  replace:
  - T: "ikke i tabell"                               # phrase('not in table')
  - pause: long
  - set_variables: [SpeakExpression: "'false'"]

- name: move-cell-previous
  tag: mtd
  match: "$NavCommand='MoveCellPrevious'"
  replace:
  - test:
      if: "preceding-sibling::*"
      then:
      - test:
          if: "$NavVerbosity = 'Verbose'"
          then:
          - T: "gå venstre"                        # phrase('move left')
          - pause: short
      - test:
          if: "$NavVerbosity != 'Terse'"
          then:
          - T: "kolonne"                           # phrase(the first 'column' of the table)
          - x: "count(preceding-sibling::*)"
          - pause: medium
      - test:
          if: "$NavMode='Character'"
          then:
          - with:
              variables: [NavCommand: "'MovePreviousZoom'"]
              replace: [x: "preceding-sibling::*[1]"]
          else:
          - set_variables: [NavNode: "preceding-sibling::*[1]/*[1]/@id"]
      else:
      - T: "ingen foregående kolonner"                 # phrase('no previous column' in the table)
      - set_variables: [SpeakExpression: "'false'"]

- name: move-cell-next
  tag: mtd
  match: "$NavCommand='MoveCellNext'"
  replace:
  - test:
      if: "following-sibling::*"
      then:
      - test:
          if: "$NavVerbosity = 'Verbose'"
          then:
          - T: "gå høyre"                     # phrase('move right')
          - pause: short
      - test:
          if: "$NavVerbosity != 'Terse'"
          then:
          - T: "kolonne"                         # phrase(the first 'column' in the table)
          - x: "count(preceding-sibling::*)+2"
          - pause: medium
      - test:
          if: "$NavMode='Character'"
          then:
          - with:
              variables: [NavCommand: "'MoveNextZoom'"]
              replace: [x: "following-sibling::*[1]"]
          else:
          - set_variables: [NavNode: "following-sibling::*[1]/*[1]/@id"]
      else:
      - T: "ingen flere kolonner"                  # phrase('no next column' in the table)
      - set_variables: [SpeakExpression: "'false'"]

- name: move-cell-up
  tag: mtd
  match: "$NavCommand='MoveCellUp'"
  replace:
  - test:
      if: "../preceding-sibling::*"
      then:
      - with:
          variables: [Column: "count(preceding-sibling::*)+1"] # store this because otherwise the value is used in the wrong context below
          replace:
          - test:
              if: "$NavVerbosity = 'Verbose'"
              then:
              - T: "gå opp"                             # phrase('move up' to previous row in the table)
              - pause: short
          - test:
              if: "$NavVerbosity != 'Terse'"
              then:
              - T: "rad"                                 # phrase(the previous 'row' in the table)
              - x: "count(../preceding-sibling::*)"
              - pause: short
              - T: "kolonne"                              # phrase(the previous 'column' in the table)
              - x: "count(preceding-sibling::*)+1"
              - pause: medium
          - test:
              if: "$NavMode='Character'"
              then:
              - with:
                  variables: [NavCommand: "'MoveNextZoom'"]
                  replace: [x: "../preceding-sibling::*[1]/*[$Column]"]
              else:
              - set_variables: [NavNode: "../preceding-sibling::*[1]/*[$Column]/*[1]/@id"]
      else:
      - T: "ingen foregående rader"                            # phrase('no previous row' in the table)
      - set_variables: [SpeakExpression: "'false'"]

- name: move-cell-down
  tag: mtd
  match: "$NavCommand='MoveCellDown'"
  replace:
  - test:
      if: "../following-sibling::*"
      then:
      - with:
          variables: [Column: "count(preceding-sibling::*)+1"] # store this because otherwise the value is used in the wrong context below
          replace:
          - test:
              if: "$NavVerbosity = 'Verbose'"
              then:
              - T: "gå ned"                          # phrase('move down' to the next row in the table)
              - pause: short
          - test:
              if: "$NavVerbosity != 'Terse'"
              then:
              - T: "rad"                                # phrase(the next 'row' in the table)
              - x: "count(../preceding-sibling::*)+2"
              - pause: short
              - T: "kolonne"                             # phrase(the next 'column' in the table)
              - x: "count(preceding-sibling::*)+1"
              - pause: medium
          - test:
              if: "$NavMode='Character'"
              then:
              - with:
                  variables: [NavCommand: "'MoveNextZoom'"]
                  replace: [x: "../following-sibling::*[1]/*[$Column]"]
              else:
              - set_variables: [NavNode: "../following-sibling::*[1]/*[$Column]/*[1]/@id"]
      else:
      - T: "ingen flere rader"                                # phrase('no next row' in the table)
      - set_variables: [SpeakExpression: "'false'"]

- name: move-cell-up
  tag: [mtr, mlabeledtr]
  match: "$NavCommand='MoveCellUp'"
  replace:
  - test:
      if: "$NavVerbosity = 'Verbose'"
      then:
      - T: "gå til forrige rad"                              # phrase('move to previous row' in the table)
      - pause: medium
  - test:
      if: "preceding-sibling::*"
      then:
      - test:
          if: "$NavMode='Character'"
          then:
          - with:
              variables: [NavCommand: "'MoveNextZoom'"]
              replace: [x: "preceding-sibling::*[1]"]
          else:
          - set_variables: [NavNode: "preceding-sibling::*[1]/@id"]
      else:
      - T: "ingen foregående rader"                          # phrase('no previous row' in the table)
      - set_variables: [SpeakExpression: "'false'"]

- name: move-cell-down
  tag: [mtr, mlabeledtr]
  match: "$NavCommand='MoveCellDown'"
  replace:
  - test:
      if: "$NavVerbosity = 'Verbose'"
      then:
      - T: "gå til neste rad"                          # phrase('move to next row' in the table)
      - pause: medium
  - test:
      if: "following-sibling::*"
      then:
      - test:
          if: "$NavMode='Character'"
          then:
          - with:
              variables: [NavCommand: "'MoveNextZoom'"]
              replace: [x: "following-sibling::*[1]"]
          else:
          - set_variables: [NavNode: "following-sibling::*[1]/@id"]
      else:
      - T: "ingen flere rader"                          # phrase('no next row' in the table)
      - set_variables: [SpeakExpression: "'false'"]

- name: move-cell-previous
  # if a row is selected, there is no previous/next column, so this is trivial
  tag: [mtr, mlabeledtr]
  match: "$NavCommand='MoveCellPrevious'"
  replace:
  - test:
      if: "$NavVerbosity = 'Verbose'"
      then:
      - T: "gå til forrige kolonne"                              # phrase('move to previous column' in the table)
      - pause: medium
  - T: "ingen foregående kolonner"                          # phrase('no previous column' in the table)
  - set_variables: [SpeakExpression: "'false'"]

- name: move-cell-next
  # if a row is selected, there is no previous/next column, so this is trivial
  tag: [mtr, mlabeledtr]
  match: "$NavCommand='MoveCellNext'"
  replace:
  - test:
      if: "$NavVerbosity = 'Verbose'"
      then:
      - T: "gå til neste kolonne"                              # phrase('move to next column' in the table)
      - pause: medium
  - T: "ingen flere kolonner"                          # phrase('no next row' in the table)
  - set_variables: [SpeakExpression: "'false'"]

- name: default-read-cell
  tag: "*"
  match: "$NavCommand='ReadCellCurrent'"
  replace:
  - with:
      variables: [MTD: "ancestor::m:mtd"]
      replace:
      - test:
          if: "$MTD"
          then:
          - test:
              if: "$NavVerbosity = 'Verbose'"
              then:
              - T: "les nåværende celle"                         # phrase('read current entry' in the table)
              - pause: medium
          - test:
              if: "$NavVerbosity != 'Terse'"
              then:
              - T: "rad"                                        # phrase(the previous 'row' in the table)
              - x: "count($MTD[1]/../preceding-sibling::*)+1"
              - pause: short
              - T: "kolonne"                                     # phrase(the previous 'column' in the table)
              - x: "count($MTD[1]/preceding-sibling::*)+1"
              - pause: short
          - set_variables: [NavNode: "$MTD[1]/*[1]/@id"]
          else:
          - T: "ikke i tabell"                                   # phrase('not in table' or matrix)
          - pause: long
          - set_variables: [SpeakExpression: "'false'"]

- name: default-cell-move

  tag: "*"
  match:
  - "$NavCommand='MoveCellPrevious' or $NavCommand='MoveCellNext' or"
  - "$NavCommand='MoveCellUp' or $NavCommand='MoveCellDown' or"
  - "$NavCommand='MoveColumnStart' or $NavCommand='MoveColumnEnd' or"
  - "$NavCommand='ReadCellCurrent'"
  replace:
  - test:
      if: "ancestor::m:mtd"
      then:
      - x: "ancestor::m:mtd[1]" # try again on an mtd node
      else:
      - T: "ikke i tabell"                                               # phrase('not in table' or matrix)
      - pause: long
      - set_variables: [SpeakExpression: "'false'"]

- name: move-next-character
  tag: [mn, mi, mtext]
  match: 
  - "($NavCommand = 'MoveNext' or $NavCommand = 'ReadNext' or $NavCommand = 'DescribeNext' or $NavCommand = 'MoveNextZoom') and"
  - "$NavNodeOffset > 0 and"
  - "($NavNodeOffset < string-length(.) or name(EdgeNode(., 'right', 'math'))!='math')" # not at edge of math
  replace:
  - test:
      if: "$NavNodeOffset < string-length(.)"
      then:
      - with:
          variables: [SayCommand: "string($NavVerbosity = 'Verbose')"]
          replace: [x: "."]
      - set_variables: [NavNodeOffset: "$NavNodeOffset + 1"]
      else:
      - with:
          variables: [SayCommand: "string($NavVerbosity = 'Verbose')"]
          replace: [x: "."]
      - set_variables: [NavNodeOffset: "0"]
      - x: "."

# skip 'none'
- name: move-next-none
  tag: [none, mprescripts]
  match: 
  - "($NavCommand = 'MoveNext' or $NavCommand = 'ReadNext' or $NavCommand = 'DescribeNext' or $NavCommand = 'DescribePrevious' or $NavCommand = 'MoveNextZoom') and"
  - "parent::*[1][name(.)='mmultiscripts'] and following-sibling::*"
  replace:
  - with:
      variables: [Following: "following-sibling::*[1]"]
      replace:
      # two 'none's in a row -- move over and try again; one 'none', zoom in on next 
      - test:
          if: "$Following[name(.)='none']"
          then: [x: "$Following"]
          else:
          - with:
              variables: [Move2D: "'i'", Child2D: "$Following"]        # phrase('in' the denominator)
              replace: [x: ".."]
          - with:
              variables: [NavCommand: "'MoveNextZoom'"]
              replace: [x: "$Following"]

# skip invisible chars except for Enhanced mode when "times" should be read
- name: move-next-invisible
  tag: "*"
  match:
  - "($NavCommand = 'MoveNext' or $NavCommand = 'ReadNext' or $NavCommand = 'DescribeNext') and"
  - "following-sibling::*[1][name(.)='mo' and translate(., '\u2061\u2062\u2063\u2064', '')='']"
  replace:
  - with:
      variables: [SayCommand: "string($NavVerbosity = 'Verbose')"]
      replace: [x: "."]
  - test:
      if: "following-sibling::*[1][.='\u2062' or .='\u2064'] and
           ($NavMode='Enhanced' or ($NavMode='Simple' and following-sibling::*[2][not(IsNode(., 'mathml'))]))"   # invisible times and plus
      then: [set_variables: [NavNode: "following-sibling::*[1]/@id"]]
      else: [x: "following-sibling::*[1]"]

- name: move-next-no-auto-zoom-at-edge
  # at edge of 2D and in a mode where moving right isn't an option
  tag: "*"
  variables: [EdgeNode: "EdgeNode(., 'right', '2D')"]
  match: "$NavCommand = 'MoveNext' and $NavMode!='Character' and not($AutoZoomOut) and $EdgeNode/@id!=@id"
  replace:
  - test:
      if: "$MatchCounter = 0 and $NavVerbosity = 'Verbose'"
      then:
      - T: "kan ikke gå høyre"                              # phrase('cannot move right')
      - pause: medium
  - with:
      variables:
      - Move2D: "'slutt på'"
      - Child2D: "$EdgeNode/*[last()]"
      - MatchCounter: $MatchCounter + 1
      replace: [x: "$EdgeNode"]
  - pause: long
  - set_variables: [SpeakExpression: "'false'"]

- name: move-next-no-auto-zoom-at-edge-math
  # at edge of math -- no where to go (must be after we rule out being at the edge of 2D) because we want to speak that
  tag: "*"
  match:
  - "($NavCommand = 'MoveNext' or $NavCommand = 'ReadNext' or $NavCommand = 'DescribeNext') and"
  - "(self::m:math or name(EdgeNode(., 'right', 'math'))='math')" # at edge of math
  replace:
  - test:
      if: "$MatchCounter = 0 and $NavVerbosity = 'Verbose'"
      then:
      - T: "kan ikke"                                          # phrase('cannot' move right in expression)
      - test:
        - if: "$NavCommand = 'MoveNext'"
          then: [T: "gå"]                                  # phrase('move' to next entry in table)     
        - else_if: "$NavCommand = 'ReadNext'"
          then: [T: "lese"]                                  # phrase('read' next entry in table)     
          else: [T: "beskrive"]                              # phrase('describe' next entry in table)     
      - T: "høyre"                              # phrase(move 'right')
      - pause: short
  - T: "slutt på uttrykk"                              # phrase(move 'end of math')
  - pause: long
  - set_variables: [SpeakExpression: "'false'"]

- name: move-next-auto-zoom-up-one-level
  # Last child or in auto-zoom'd in-- move up a level and try again 
  # Note: we've already checked the for the case where we are at an edge and should not AutoZoomOut
  tag: "*"
  match:
  - "($NavCommand = 'MoveNext' or $NavCommand = 'ReadNext' or $NavCommand = 'DescribeNext') and"
  - "( not(following-sibling::*) or"
  - "  ( $NavMode='Enhanced' and "
  - "    count(following-sibling::*)=1 and (IsBracketed(.., '(', ')') or IsBracketed(.., '[', ']'))"
  - "  )"
  - ")"
  replace:
  - with:
      variables: [SayCommand: "string($NavVerbosity = 'Verbose')"]
      replace: [x: "."]
  - test:
      if: "following-sibling::*"
      then:
      - with:
          variables: [Move2D: "'i'", Child2D: "."]             # phrase('in' the denominator)
          replace: [x: ".."]
      else:
      - with:
          variables: [Move2D: "'ut av'", Child2D: "."]
          replace: [x: ".."]
  - x: ".."

# At this point, if XXXNext, then we know there is must be a right sibling
- name: move-next-default
  tag: mtd
  match: "$Move2D = '' and ($NavCommand = 'MoveNext' or $NavCommand = 'ReadNext' or $NavCommand = 'DescribeNext')"
  replace:
  - with:
      variables: [SayCommand: "string($NavVerbosity = 'Verbose')"]
      replace: [x: "."]
  - test:
      if: "following-sibling::*"
      then:
      - test:
          if: "$NavVerbosity = 'Verbose'"
          then:
          - T: "kolonne"                                       # phrase(the previous 'column' in the table)
          - x: "count(preceding-sibling::*)+2"
          - pause: short
      - test:
          if: "$NavMode = 'Character'"
          then:
          - with:
              variables: [NavCommand: "'MoveNextZoom'"]
              replace: [x: "following-sibling::*[1]"]
          else: [set_variables: [NavNode: "following-sibling::*[1]/*[1]/@id"]]
      else:
      - x: ".." # try again at the row level

- name: move-next-default
  tag: [mtr, mlabeledtr]
  match: "$Move2D = '' and
          ($NavCommand = 'MoveNext' or $NavCommand = 'ReadNext' or $NavCommand = 'DescribeNext') and
          following-sibling::*"
  replace:
  - with:
      variables: [SayCommand: "string($NavVerbosity = 'Verbose')"]
      replace: [x: "."]
  - test:
      if: "$NavMode = 'Character'"
      then:
      - with:
          variables: [NavCommand: "'MoveNextZoom'"]
          replace: [x: "following-sibling::*[1]"]
      else:
      - set_variables: [NavNode: "following-sibling::*[1]/@id"]

- name: move-next-auto-zoom-parens
  # auto-zoom into next child if next child is parenthesized expr
  tag: "*"
  match:
  - "($NavCommand = 'MoveNext' or $NavCommand = 'ReadNext' or $NavCommand = 'DescribeNext') and"
  - "$NavMode='Enhanced' and"
  - "parent::m:mrow and following-sibling::* and"
  - "following-sibling::*[1][self::m:mrow and count(*)=3 and " #exclude empty parens
  - "                        (IsBracketed(., '(', ')') or IsBracketed(., '[', ']'))"
  - "                       ]"
  replace:
  - with:
      variables: [SayCommand: "string($NavVerbosity = 'Verbose')"]
      replace: [x: "."]
  - set_variables: [NavNode: "following-sibling::*[1]/*[2]/@id"]

# normal cases for MoveNext
- name: move-next-locked-zoom-level
  # locked zoom level
  tag: "*"
  match:
  - "($NavCommand = 'MoveNext' or $NavCommand = 'ReadNext' or $NavCommand = 'DescribeNext') and"
  - "$ReadZoomLevel>=0"
  replace:
  - with:
      variables: [SayCommand: "string($NavVerbosity = 'Verbose')"]
      replace: [x: "."]
  - test:
      # if in base (nothing before), we must be moving to a script, so "in" will be said
      if: "preceding-sibling::* and following-sibling::*[1][name(.)='none']"
      then:
      - with:
          variables: [Move2D: "'ut av'", Child2D: "."]
          replace: [x: ".."]
      - x: "following-sibling::*[1]"
      else:
      - with:
          variables: [Move2D: "'i'", Child2D: "following-sibling::*[1]"]       # phrase('in' the denominator)
          replace: [x: ".."]
      - with:
          variables: [NavCommand: "'MoveNextZoom'"]
          replace: [x: "following-sibling::*[1]"]

- name: move-next-default
  tag: "*"
  match: "$NavCommand = 'MoveNext' or $NavCommand = 'ReadNext' or $NavCommand = 'DescribeNext'"
  replace:
  - with:
      variables: [SayCommand: "string($NavVerbosity = 'Verbose')"]
      replace: [x: "."]
  - test:
      if: "following-sibling::*[1][@data-from-mathml='none' or @data-from-mathml='mprescripts']"
      then: [x: "following-sibling::*[1]"]
      else:
      - test:
          if: "IsNode(.., '2D') or not(IsNode(.., 'mathml'))"
          then:
          - with:
              variables: [Move2D: "'i'", Child2D: "following-sibling::*[1]"]           # phrase('in' the denominator)
              replace: [x: ".."]
      - set_variables: [NavNode: "following-sibling::*[1]/@id"]

# ========  Move/Read/Describe Previous rules =================

# skip 'none'
- name: move-previous-none
  tag: [none, mprescripts]
  match: 
  - "($NavCommand = 'MovePrevious' or $NavCommand = 'ReadPrevious' or $NavCommand = 'DescribePrevious' or $NavCommand = 'MovePreviousZoom') and"
  - "parent::*[1][name(.)='mmultiscripts'] and preceding-sibling::*"
  replace:
  - with:
      variables: [Preceding: "preceding-sibling::*[1]"]
      replace:
      # two 'none's in a row -- move over and try again; one 'none', zoom in on preceding 
      - test:
          if: "$Preceding[name(.)='none']"
          then: [x: "$Preceding"]
          else:
          - with:
              variables: [Move2D: "'i'", Child2D: "$Preceding"]          # phrase('in' the denominator)
              replace: [x: ".."]
          - with:
              variables: [NavCommand: "'MovePreviousZoom'"]
              replace: [x: "$Preceding"]

# skip invisible chars except for Enhanced mode when "times" should be read
- name: move-previous-invisible
  tag: "*"
  match:
  - "($NavCommand = 'MovePrevious' or $NavCommand = 'ReadPrevious' or $NavCommand = 'DescribePrevious') and"
  - "preceding-sibling::*[1][name(.)='mo' and translate(., '\u2061\u2062\u2063\u2064', '')='']"
  replace:
  - with:
      variables: [SayCommand: "string($NavVerbosity = 'Verbose')"]
      replace: [x: "."]
  - test:
      if: "preceding-sibling::*[1][.='\u2062' or .='\u2064'] and $NavMode='Enhanced'"   # invisible times and plus
      then: [set_variables: [NavNode: "preceding-sibling::*[1]/@id"]]
      else: [x: "preceding-sibling::*[1]"]

# two rules for when can't move left
- name: move-previous-no-auto-zoom-at-edge
  # at edge of 2D and in a mode where moving left isn't an option
  tag: "*"
  variables: [EdgeNode: "EdgeNode(., 'left', '2D')"]
  match: "$NavCommand = 'MovePrevious' and $NavMode!='Character' and not($AutoZoomOut) and $EdgeNode/@id!=@id"
  replace:
  - test:
      if: "$MatchCounter = 0 and $NavVerbosity = 'Verbose' and $NavCommand = 'MovePrevious'"
      then:
      - T: "kan ikke gå venstre"                                   # phrase('cannot move left' in expression)
      - pause: medium
  - with:
      variables:
      - Move2D: "'slutt på'"
      - Child2D: "$EdgeNode/*[1]"
      - MatchCounter: $MatchCounter + 1
      replace: [x: "$EdgeNode"]
  - pause: long
  
- name: move-previous-no-auto-zoom-at-edge-of-math
  # at edge of math -- no where to go (must be after we rule out being at the edge of 2D) because we want to speak that
  tag: "*"
  match:
  - "($NavCommand = 'MovePrevious' or $NavCommand = 'ReadPrevious' or $NavCommand = 'DescribePrevious') and"
  - "(self::m:math or name(EdgeNode(., 'left', 'math'))='math')"
  replace:
  - T: "start på uttrykk"                                              # phrase('start of math')
  - pause: long
  - set_variables: [SpeakExpression: "'false'"]

- name: move-previous-at-end
  tag: "*"
  match:
  - "($NavCommand = 'MovePrevious' or $NavCommand = 'ReadPrevious' or $NavCommand = 'DescribePrevious') and"
  - "name(EdgeNode(., 'left', 'math'))='math'" # at edge of math
  replace:
  - test:
      if: "$MatchCounter = 0 and $NavVerbosity = 'Verbose'"
      then:
      - T: "kan ikke gå venstre"                      # phrase('cannot move left')
      - pause: short
  - with:
      variables: [Move2D: "'start på'", Child2D: "."]
      replace: [x: "."]
  - pause: long
  - set_variables: [SpeakExpression: "'false'"]

- name: move-prev-character
  tag: [mn, mi, mtext]
  match: 
  - "($NavCommand = 'MovePrevious' or $NavCommand = 'ReadPrevious' or $NavCommand = 'DescribePrevious' or $NavCommand = 'MovePreviousZoom') and"
  - "$NavNodeOffset > 0 and"
  - "($NavNodeOffset > 1 or name(EdgeNode(., 'left', 'math'))!='math')" # not at edge of math
  replace:
  - test:
      if: "$NavNodeOffset > 1"
      then:
      - with:
          variables: [SayCommand: "string($NavVerbosity = 'Verbose')"]
          replace: [x: "."]
      - set_variables: [NavNodeOffset: "$NavNodeOffset - 1"]
      else:
      - with:
          variables: [SayCommand: "string($NavVerbosity = 'Verbose')"]
          replace: [x: "."]
      - set_variables: [NavNodeOffset: "0"]
      - x: "."

- name: move-previous-auto-zoom-up-one-level
  # Last child or in auto-zoom'd in-- move up a level and try again 
  # Note: we've already checked the for the case where we are at an edge and should not AutoZoomOut
  tag: "*"
  match:
  - "($NavCommand = 'MovePrevious' or $NavCommand = 'ReadPrevious' or $NavCommand = 'DescribePrevious') and"
  - "( not(preceding-sibling::*) or"
  - "  ( $NavMode='Enhanced' and "
  - "    count(preceding-sibling::*)=1 and (IsBracketed(.., '(', ')') or IsBracketed(.., '[', ']'))"
  - "  )"
  - ")"
  replace:
  - with:
      variables: [SayCommand: "string($NavVerbosity = 'Verbose')"]
      replace: [x: "."]
  - test:
      if: "preceding-sibling::*"
      then:
      - with:
          variables: [Move2D: "'i'", Child2D: "."]             # phrase('in' the denominator)
          replace: [x: ".."]
      else:
      - with:
          variables: [Move2D: "'ut av'", Child2D: "."]
          replace: [x: ".."]
  - x: ".."

- name: move-previous-auto-zoom-parens
  # auto-zoom into previous child if previous child is parenthesized expr
  # Note: there is an asymmetry here from MoveNext because the base of a scripted might have parens for grouping, but not true for the script
  tag: "*"
  match:
  - "($NavCommand = 'MovePrevious' or $NavCommand = 'ReadPrevious' or $NavCommand = 'DescribePrevious') and"
  - "$NavMode='Enhanced' and"
  - "preceding-sibling::* and"
  - "(parent::m:mrow or parent::m:msub or parent::m:msup or"
  - " (count(preceding-sibling::*)=1 and (parent::m:msubsup or parent::m:mmultiscripts))"  # make sure moving into base
  - ") and"
  - "preceding-sibling::*[1][self::m:mrow and count(*)=3 and " #exclude empty parens
  - "       (IsBracketed(., '(', ')') or IsBracketed(., '[', ']'))"
  - "   ]"
  replace:
  - with:
      variables: [SayCommand: "string($NavVerbosity = 'Verbose')"]
      replace: [x: "."]
  - test:
      if: "not(parent::m:mrow)"
      then:
      - with:
          variables: [Move2D: "'i'", Child2D: "preceding-sibling::*[1]"]         # phrase('in' the denominator)
          replace: [x: ".."]
  - set_variables: [NavNode: "preceding-sibling::*[1]/*[2]/@id"]

# normal cases for MovePrevious

- name: move-previous-default
  tag: mtd
  match: "$Move2D = '' and
          ($NavCommand = 'MovePrevious' or $NavCommand = 'ReadPrevious' or $NavCommand = 'DescribePrevious') and
          preceding-sibling::*"
  replace:
  - with:
      variables: [SayCommand: "string($NavVerbosity = 'Verbose')"]
      replace: [x: "."]
  - test:
      if: "$NavVerbosity = 'Verbose'"
      then:
      - T: "kolonne"                               # phrase(the first 'column' in the table)
      - x: "count(preceding-sibling::*)"
      - pause: short
  - test:
      if: "$NavMode = 'Character'"
      then:
      - with:
          variables: [NavCommand: "'MovePreviousZoom'"]
          replace: [x: "preceding-sibling::*[1]"]
      else: [set_variables: [NavNode: "preceding-sibling::*[1]/*[last()]/@id"]]

- name: move-previous-default
  tag: [mtr, mlabeledtr]
  match: "$Move2D = '' and ($NavCommand = 'MovePrevious' or $NavCommand = 'ReadPrevious' or $NavCommand = 'DescribePrevious')"
  replace:
  - with:
      variables: [SayCommand: "string($NavVerbosity = 'Verbose')"]
      replace: [x: "."]
  - test:
      if: "preceding-sibling::*"
      then:
      - test:
          if: "$NavMode = 'Character'"
          then:
          - with:
              variables: [NavCommand: "'MovePreviousZoom'"]
              replace: [x: "preceding-sibling::*[1]"]
          else:
          - set_variables: [NavNode: "preceding-sibling::*[1]/@id"]
      else: [x: ".."] # try again for after

- name: move-previous-locked-zoom-level
  # locked zoom level
  tag: "*"
  match:
  - "($NavCommand = 'MovePrevious' or $NavCommand = 'ReadPrevious' or $NavCommand = 'DescribePrevious') and"
  - "$ReadZoomLevel>=0"
  replace:
  - with:
      variables: [SayCommand: "string($NavVerbosity = 'Verbose')"]
      replace: [x: "."]
  - test:
      # if moving into base (nothing before), we must be moving to the base, so "in" will be said
      if: "count(preceding-sibling::*) > 2 and preceding-sibling::*[1][name(.)='none']"
      then:
      - with:
          variables: [Move2D: "'ut av'", Child2D: "."]
          replace: [x: ".."]
      - x: "preceding-sibling::*[1]"          # skip over 'none'
      else:
      - with:
          variables: [Move2D: "'i'", Child2D: "preceding-sibling::*[1]"]               # phrase('in' the denominator)
          replace: [x: ".."]
      - with:
          variables: [NavCommand: "'MovePreviousZoom'"]
          replace: [x: "preceding-sibling::*[1]"]

- name: move-previous-default
  tag: "*"
  match: "$NavCommand = 'MovePrevious' or $NavCommand = 'ReadPrevious' or $NavCommand = 'DescribePrevious'"
  replace:
  - with:
      variables: [SayCommand: "string($NavVerbosity = 'Verbose')"]
      replace: [x: "."]
  - test:
      if: "preceding-sibling::*[1][@data-from-mathml='none' or @data-from-mathml='mprescripts']"
      then: [x: "preceding-sibling::*[1]"]
      else:
      - test:
          if: "IsNode(.., '2D') or not(IsNode(.., 'mathml'))"
          then:
          - with:
              variables: [Move2D: "'i'", Child2D: "preceding-sibling::*[1]"]           # phrase('in' the denominator)
              replace: [x: ".."]
      - set_variables: [NavNode: "preceding-sibling::*[1]/@id"]

# ********* ReadZoomLevel toggle ***************
# These set ::NavMode

- name: toggle-mode-up
  tag: "*"
  match: "$NavCommand = 'ToggleZoomLockUp'"
  replace:
  - test:
    - if: "$NavMode = 'Enhanced'"
      then:
      - T: "symbolmodus"                                                # phrase(a mathematical 'character')
      - set_variables: [NavMode: "'Character'", ReadZoomLevel: "1"]
    - else_if: "$NavMode = 'Character'"
      then:
      - T: "enkelt modus"                                                   # phrase(a 'simple' way to do something)
      - set_variables: [NavMode: "'Simple'", ReadZoomLevel: "1"]
    - else:
      - T: "utvidet modus"                                                 # phrase(an 'enhanced' way to do something)
      - set_variables: [NavMode: "'Enhanced'", ReadZoomLevel: "-1"]
  - pause: long
  - test:
    - if: "$NavMode != 'Enhanced'" # potentially need to zoom to the sibling
      then:
      - with:
          variables: [MatchCounter: "$MatchCounter + 1", NavCommand: "'MoveNextZoom'"]
          replace: [x: "."]

- name: toggle-mode-down
  tag: "*"
  match: "$NavCommand = 'ToggleZoomLockDown'"
  replace:
  - test:
    - if: "$NavMode = 'Enhanced'"
      then:
      - T: "enkelt modus"                                                 # phrase(a 'simple' way to do something)
      - set_variables: [NavMode: "'Simple'", ReadZoomLevel: "1"]
    - else_if: "$NavMode = 'Character'"
      then:
      - T: "utvidet modus"                                               # phrase(an 'enhanced' way to do something)
      - set_variables: [NavMode: "'Enhanced'", ReadZoomLevel: "-1"]
    - else:
      - T: "symbolmodus"                                              # phrase(a mathematical 'character')
      - set_variables: [NavMode: "'Character'", ReadZoomLevel: "1"]
  - pause: long
  - test:
    - if: "$NavMode != 'Enhanced'" # potentially need to zoom to the sibling
      then:
      - with:
          variables: [MatchCounter: "$MatchCounter + 1", NavCommand: "'MoveNextZoom'"]
          replace: [x: "."]

- name: toggle-speech-describe
  tag: "*"
  match: "$NavCommand = 'ToggleSpeakMode'"
  replace:
  - test:
      if: "$Overview = 'true'"
      then:
      - T: "les uttrykk etter navigering"                # phrase('speak expression after move')
      - pause: long
      - set_variables: [Overview: "'false'"]
      else:
      - T: "oversikt over uttrykk etter navigering"          # phrase('overview of expression after move')
      - pause: long
      - set_variables: [Overview: "'true'"]

- name: current
  tag: "*"
  match: "$NavCommand = 'ReadCurrent' or $NavCommand = 'DescribeCurrent'"
  replace:
  - test:
      if: "$NavVerbosity = 'Verbose'"
      then:
      - test:
        - if: "$NavCommand = 'ReadCurrent'"
          then: [T: "les"]                                  # phrase('read' next entry in table) 
          else: [T: "beskriv"]                              # phrase('describe' next entry in table)     
      - T: "nåværende"                                         # phrase('current' entry in table)
      - pause: long
  - set_variables: [NavNode: "@id"]

# this needs to be near the end because we only test for 'Describe', "Read", etc., and we don't want to get 'DescribeNext', etc.
- name: placemarker

  tag: "*"
  match:
  - "starts-with($NavCommand, 'Read') or "
  - "starts-with($NavCommand, 'Describe') or "
  - "starts-with($NavCommand, 'MoveTo')"
  replace:
  - test:
      if: "$NavVerbosity != 'Terse'"
      then:
      - test:
        - if: "starts-with($NavCommand, 'Read')"
          then: [T: "les"]                                  # phrase('read' next entry in table)     
        - else_if: "starts-with($NavCommand, 'Describe')"
          then: [T: "beskriv"]                              # phrase('describe' next entry in table)     
        - else_if: "starts-with($NavCommand, 'MoveTo')"
          then: [T: "gå til "]                              # phrase('move to' the next entry in table) 
          else: [T: "angi"]                                   # phrase('set' the value of the next entry in table) 
      - T: "plassmerker"                                     # phrase('placeholder' for the value)
      - x: "$PlaceMarkerIndex"
      - pause: long
  - set_variables: [NavNode: "$PlaceMarker"]

- name: set-placemarker
  tag: "*"
  match: "starts-with($NavCommand, 'SetPlacemarker')"
  replace:
  - test:
      if: "$NavVerbosity != 'Terse'"
      then:
      - T: "angi plassmerker"                                 # phrase('set placeholder' to the value) 
      - x: "$PlaceMarkerIndex"
      - pause: long
  - set_variables: [NavNode: "@id"]

# ********* WhereAmI  ***************

# FIX: WhereAmI needs support from the Rust code to loop around and do speech at each iteration.
#      Alternatively, it could insert a special token that Rust code does a "replace" on with the speech (e.g. SPEECH_AT{id})
#      or a new command "speak" which takes a node id
- name: where-am-i-start
  tag: "*"
  match: "($NavCommand = 'WhereAmI' or $NavCommand = 'WhereAmIAll') and $MatchCounter = 0"
  replace:
  - translate: "@id"
  - pause: long
  - with:
      variables: [MatchCounter: "$MatchCounter + 1"]
      replace: [x: ".."]

# Marthe
- name: where-am-i-stop
  tag: "*"
  match:
  - "($NavCommand = 'WhereAmI' or $NavCommand = 'WhereAmIAll') and $MatchCounter > 0 and"
  # stopping conditions
  - "(self::m:math or "
  - " parent::*[self::m:math and (count(*)=1 or (count(*)=2 and *[2][.=',' or .='.' or .=';' or .='?']) ) ] "
  - ")"
  replace:
  - test:
      if: "$NavCommand = 'WhereAmI'"
      then:
      - T: "inni ingenting mer"                         # phrase('inside of nothing more') 
      - pause: long
      - set_variables: [SpeakExpression: "'false'"]
      else:
      - T: "inni"                                         # phrase('inside' a big expression) 
      - pause: medium
  - set_variables: [NavNode: "@id"]

- name: where-am-i-middle
  tag: "*"
  match: "$NavCommand = 'WhereAmI' or $NavCommand = 'WhereAmIAll'"
  replace:
  - T: "inni"                                           # phrase('inside' a big expression)
  - pause: medium
  - test:
    - if: "$NavMode='Enhanced' and parent::*[self::m:mrow and (IsBracketed(., '(', ')', false) or IsBracketed(., '[', ']', false))]"
      then: [x: ".."] # auto-zoom up
    - else_if: "$NavCommand = 'WhereAmI'"
      then: [set_variables: [NavNode: "@id"]]
      else:
      - translate: "@id"
      - pause: long
      - x: '..'