For reference see 3.3 in http://unicode.org/reports/tr9/
function _computeLevels(chars, levels, params) {
      var action,
          condition,
          i,
          index,
          newLevel,
          prevState,
          condPos = -1,
          len = chars.length,
          newState = 0,
          resolvedTypes = [],
          stateTable = _dir ? _STATE_TABLE_RTL : _STATE_TABLE_LTR,
          types = [];
      _lastArabic = false;
      _hasUbatB = false;
      _hasUbatS = false;

      for (i = 0; i < len; i++) {
        types[i] = _getCharType(chars[i]);
      }

      for (index = 0; index < len; index++) {
        prevState = newState;
        resolvedTypes[index] = _resolveCharType(chars, types, resolvedTypes, index);
        newState = stateTable[prevState][_TYPE_NAMES_MAP[resolvedTypes[index]]];
        action = newState & 0xF0;
        newState &= 0x0F;
        levels[index] = newLevel = stateTable[newState][5];

        if (action > 0) {
          if (action === 0x10) {
            for (i = condPos; i < index; i++) {
              levels[i] = 1;
            }

            condPos = -1;
          } else {
            condPos = -1;
          }
        }

        condition = stateTable[newState][6];

        if (condition) {
          if (condPos === -1) {
            condPos = index;
          }
        } else {
          if (condPos > -1) {
            for (i = condPos; i < index; i++) {
              levels[i] = newLevel;
            }

            condPos = -1;
          }
        }

        if (types[index] === "B") {
          levels[index] = 0;
        }

        params.hiLevel |= newLevel;
      }

      if (_hasUbatS) {
        _handleUbatS(types, levels, len);
      }
    }