fcf.module({
  name: "fcf:NFSQL/NDetails/AutomateSelect.js",
  dependencies: ["fcf:NFSQL/NDetails/AutomateWhere.js", "fcf:NFSQL/NDetails/AutomateFieldEx.js", "fcf:NFSQL/NDetails/AutomateLanguageItem.js"],
  module: function(AutomateWhere, AutomateFieldEx, AutomateLanguageItem) {
    var Automate = fcf.prepareObject(fcf, "NFSQL.NDetails.Automate");


    Automate.StepSelect_StartSkipSpace = function(a_state){
      Automate.BaseStep.call(this, a_state);
      this.delimeter = "";
      this.map[""] = {
                        factory:    Automate.StepFieldEx,
                        name:       "StepFieldEx",
                        skipFirst:  false,
                        enableAs:   true,
                        enableList: true,
                        enableAll:  true,
                        path:       `fields[${a_state.fields.length}]`,
                        exitMap: {
                          "from": { factory: Automate.StepSelect_From_SkipStartSpace, name:  "StepSelect_From_SkipStartSpace", skipFirst: false}
                        }
                     };
    }


    Automate.StepSelect_From_SkipStartSpace = function(a_state) {
      Automate.BaseStep.call(this, a_state);
      this.delimeter = "";
      this.map["^{nm}"] = { factory: Automate.StepSelect_From_readTable, name:  "StepSelect_From_readTable", skipFirst: false};
      this.map["\""]    = { factory: Automate.StepSelect_From_ReadTableDQuotes, name:  "StepSelect_From_ReadTableDQuotes", skipFirst: true};
      this.map["^{s}"]  = null;
    }

    Automate.StepSelect_From_readTable = function(a_state) {
      Automate.BaseStep.call(this, a_state);
      this.delimeter = "";
      this.map["^{nm}"] = null;
      this.map["^{s}"] = { factory: Automate.StepSelect_From_SkipPostSpace, name:  "StepSelect_From_SkipPostSpace", skipFirst: false};

      this.actionSwitch = function() {
        this.state.from = this.buffer;
      }
    }

    Automate.StepSelect_From_ReadTableDQuotes = function(a_state) {
      Automate.BaseStep.call(this, a_state);
      this.delimeter = "";
      this.map[""] = null;
      this.map["\""] = { factory: Automate.StepSelect_From_SkipPostSpace, name:  "StepSelect_From_SkipPostSpace", skipFirst: true};

      this.actionSwitch = function() {
        this.state.from = this.buffer;
      }
    }

    Automate.StepSelect_From_SkipPostSpace = function(a_state) {
      Automate.BaseStep.call(this, a_state);
      this.delimeter = "";
      this.map["^{s}"] = null;
      this.map["^{nm}"] = { factory: Automate.StepSelect_InputCommands, name:  "StepSelect_InputCommands", skipFirst: false};
    }

    Automate.StepSelect_InputCommands = function(a_state) {
      Automate.BaseStep.call(this, a_state);
      this.delimeter = "";
      this.map["^{nm}"] = null;
      this.map[""] = {
        map: {
          "where":    { factory: Automate.StepSelect_GoToWhere, name:  "StepSelect_GoToWhere", skipFirst: false},
          "group":    { factory: Automate.StepSelect_GoToGroup, name:  "StepSelect_GoToGroup", skipFirst: false},
          "join":     { factory: Automate.StepSelect_PrepareJoin, name:  "StepSelect_PrepareJoin", skipFirst: false},
          "left":     { factory: Automate.StepSelect_LeftJoin, name:  "StepSelect_LeftJoin", skipFirst: false},
          "right":    { factory: Automate.StepSelect_RightJoin, name:  "StepSelect_RightJoin", skipFirst: false},
          "limit":    { factory: Automate.StepSelect_Limit_SkipSpaces, name:  "StepSelect_Limit_SkipSpaces", skipFirst: false},
          "order":    { factory: Automate.StepSelect_Order_SkipSpaces, name:  "StepSelect_Order_SkipSpaces", skipFirst: false},
          "language": { factory: Automate.LanguageItem_SkipSpaces, name:  "LanguageItem_SkipSpaces", skipFirst: false},
        }
      };
    }

    Automate.StepSelect_GoToWhere = function(a_state) {
      Automate.BaseStep.call(this, a_state);
      this.delimeter = "";
      this.map[""] = { factory: Automate.StepWhere, name:  "StepWhere", skipFirst: false};
      this.actionSwitch = function() {
        this.state.details.whereContainer = this.state.where;
        this.state.details.wherePath = "where";
      }
    }

    Automate.StepSelect_LeftJoin = function(a_state) {
      Automate.BaseStep.call(this, a_state);
      this.delimeter = "";
      this.map["^{s}"] = null;
      this.map["^{nm}"] = { factory: Automate.StepSelect_LeftJoin_Read, name:  "StepSelect_LeftJoin_Read", skipFirst: false};
    }

    Automate.StepSelect_LeftJoin_Read = function(a_state) {
      Automate.BaseStep.call(this, a_state);
      this.delimeter = "";
      this.map["^{nm}"] = null;
      this.map["^{nnm}"] = { map: {
          "join": { factory: Automate.StepSelect_Join, name:  "StepSelect_Join", skipFirst: false }
      } };

      this.actionSwitch = function() {
        this.state.join.push({join: "left"});
      }
    }


    Automate.StepSelect_RightJoin = function(a_state) {
      Automate.BaseStep.call(this, a_state);
      this.delimeter = "";
      this.map["^{s}"] = null;
      this.map["^{nm}"] = { factory: Automate.StepSelect_RightJoin_Read, name:  "StepSelect_LeftJoin_Read", skipFirst: false};
    }

    Automate.StepSelect_RightJoin_Read = function(a_state) {
      Automate.BaseStep.call(this, a_state);
      this.delimeter = "";
      this.map["^{nm}"] = null;
      this.map["^{nnm}"] = { map: {
          "join": { factory: Automate.StepSelect_Join, name:  "StepSelect_Join", skipFirst: false }
      } };

      this.actionSwitch = function() {
        this.state.join.push({join: "right"});
      }
    }

    Automate.StepSelect_GoToGroup = function(a_state) {
      Automate.BaseStep.call(this, a_state);
      this.delimeter = "";
      this.map[""] = "^{s}";
      this.map[""] = { factory: Automate.StepSelect_GoToGroup_SkipSpaces, name: "StepSelect_GoToGroup_SkipSpaces", skipFirst: false};
    }

    Automate.StepSelect_GoToGroup_SkipSpaces = function(a_state) {
      Automate.BaseStep.call(this, a_state);
      this.delimeter = "";
      this.map["^{nm}"] = null;
      this.map["^{nnm}"] = { map: {
          "by": { factory: Automate.StepSelect_GoToGroup_ReadField_SkipSpaces, name:  "StepSelect_GoToGroup_ReadField_SkipSpaces", skipFirst: false }
      } };
    }

    Automate.StepSelect_GoToGroup_ReadField_SkipSpaces = function(a_state) {
      Automate.BaseStep.call(this, a_state);
      this.delimeter = "";
      this.map["^{s}"]  = null;
      this.map["\""]    = { factory: Automate.StepSelect_GoToGroup_ReadField_DQuotes, name: "StepSelect_GoToGroup_ReadField_DQuotes", skipFirst: true};
      this.map["^{nm}"] = { factory: Automate.StepSelect_GoToGroup_ReadField, name: "StepSelect_GoToGroup_ReadField", skipFirst: false};
    }

    Automate.StepSelect_GoToGroup_ReadField = function(a_state) {
      Automate.BaseStep.call(this, a_state);
      this.delimeter = "";
      this.map["^{nm}"] = null;
      this.map["."] = null;
      this.map[""] = { factory: Automate.StepSelect_GoToGroup_ReadField_SwitchSkipSpaces, name: "StepSelect_GoToGroup_ReadField_SwitchSkipSpaces", skipFirst: false};

      this.actionSwitch = function() {
        this.state.group.push(this.buffer);
      }
    }

    Automate.StepSelect_GoToGroup_ReadField_DQuotes = function(a_state) {
      Automate.BaseStep.call(this, a_state);
      this.delimeter = "";
      this.map[""] = null;
      this.map["\""] = { factory: Automate.StepSelect_GoToGroup_ReadField_SwitchSkipSpaces, name: "StepSelect_GoToGroup_ReadField_SwitchSkipSpaces", skipFirst: true};

      this.actionSwitch = function() {
        this.state.group.push(this.buffer);
      }
    }

    Automate.StepSelect_GoToGroup_ReadField_SwitchSkipSpaces = function(a_state) {
      Automate.BaseStep.call(this, a_state);
      this.delimeter = "";
      this.map["^{s}"] = null;
      this.map[""]     = { factory: Automate.StepSelect_GoToGroup_ReadField_Switch, name: "StepSelect_GoToGroup_ReadField_Switch", skipFirst: false };
    }

    Automate.StepSelect_GoToGroup_ReadField_Switch = function(a_state) {
      Automate.BaseStep.call(this, a_state);
      this.delimeter = "";
      this.map[","] = { factory: Automate.StepSelect_GoToGroup_ReadField_SkipSpaces, name: "StepSelect_GoToGroup_ReadField_SkipSpaces", skipFirst: true };
      this.map[""]  = { factory: Automate.StepSelect_GoToGroup_ReadField_SwitchCommand, name: "StepSelect_GoToGroup_ReadField_SwitchCommand", skipFirst: false };
    }


    Automate.StepSelect_GoToGroup_ReadField_SwitchCommand = function(a_state) {
      Automate.BaseStep.call(this, a_state);
      this.delimeter = "";
      this.map["^{nm}"] = null;
      this.map[""] = {
        map: {
          "limit": { factory: Automate.StepSelect_Limit_SkipSpaces, name:  "StepSelect_Limit_SkipSpaces", skipFirst: false },
          "order": { factory: Automate.StepSelect_Order_SkipSpaces, name:  "StepSelect_Order_SkipSpaces", skipFirst: false },
          "language": { factory: Automate.LanguageItem_SkipSpaces, name:  "LanguageItem_SkipSpaces", skipFirst: false},
        }
      };
    }


    Automate.StepSelect_PrepareJoin = function(a_state) {
      Automate.BaseStep.call(this, a_state);
      this.delimeter = "";
      this.map[""] = { factory: Automate.StepSelect_Join, name:  "StepSelect_Join", skipFirst: false};

      this.actionSwitch = function() {
        this.state.join.push({join: undefined});
      }
    }

    Automate.StepSelect_Join = function(a_state) {
      Automate.BaseStep.call(this, a_state);
      this.delimeter = "";
      this.map["^{s}"] = null;
      this.map["^{nm}"] = { factory: Automate.StepSelect_Join_ReadProjection, name:  "StepSelect_Join_ReadProjection", skipFirst: false};
      this.map["\""]    = { factory: Automate.StepSelect_Join_ReadProjectionQuotes, name:  "StepSelect_Join_ReadProjectionQuotes", skipFirst: true};
      this.map["("] = { factory: Automate.StepSelect_Join_ReadSubQuery, name:  "StepSelect_Join_ReadSubQuery", skipFirst: true};
    }

    Automate.StepSelect_Join_ReadSubQuery = function(a_state) {
      Automate.BaseStep.call(this, a_state);
      this.delimeter = "";
      this.map[""] = null;
      this.map[")"] = { factory: Automate.StepSelect_Join_PostProjectionCommand, name:  "StepSelect_Join_PostProjectionCommand", skipFirst: true};

      var bracketOpenCount = 0;
      var bracketCloseCount = 0;
      var startPosition = a_state.count+1;
      var position = startPosition;
      var subqueryContext = undefined;
      var skip = false;
      var slashCounter = 0;
      // Вычленяем подзапрос
      for(; position < a_state.content.length; ++position){
        var char = a_state.content[position];
        if (!skip) {
          if (char == "(") {
            ++bracketOpenCount;
          } else if (char == ")") {
            ++bracketCloseCount;
          } else if (char == "\"") {
            skip = true;
            continue;
          }
          if (char == ")" && (bracketCloseCount == (bracketOpenCount + 1))){
            subqueryContext = a_state.content.substr(startPosition, position - startPosition);
            break;
          }
        } else {
          if (char == "\\") {
            ++slashCounter;
          }

          if (char == "\"" && !slashCounter) {
            slashCounter = 0;
            skip = false;
            continue;
          }

          if (char != "\\") {
            slashCounter = 0;
          }
        }
      }

      a_state.count = position-1;
      var parser = new fcf.NFSQL.NDetails.SingleParser();
      var subquery = parser.parse(subqueryContext, this.state.details.args);
      this.state.join[this.state.join.length-1].query = subquery;
      for(let path in subquery.args)
        this.state.args[`join[${this.state.join.length-1}].query.${path}`] = subquery.args[path];
      delete subquery.args;
    }

    Automate.StepSelect_Join_ReadProjection = function(a_state) {
      Automate.BaseStep.call(this, a_state);
      this.delimeter = "";
      this.map["^{nm}"] = null;
      this.map["^{s}"] = { factory: Automate.StepSelect_Join_PostProjectionCommand, name:  "StepSelect_Join_PostProjectionCommand", skipFirst: false};

      this.actionSwitch = function() {
        this.state.join[this.state.join.length-1].from = this.buffer;
      }
    }

    Automate.StepSelect_Join_ReadProjectionQuotes = function(a_state) {
      Automate.BaseStep.call(this, a_state);
      this.delimeter = "";
      this.map[""] = null;
      this.map["\""] = { factory: Automate.StepSelect_Join_PostProjectionCommand, name:  "StepSelect_Join_PostProjectionCommand", skipFirst: true};

      this.actionSwitch = function() {
        this.state.join[this.state.join.length-1].from = this.buffer;
      }
    }

    Automate.StepSelect_Join_PostProjectionCommand = function(a_state) {
      Automate.BaseStep.call(this, a_state);
      this.delimeter = "";
      this.map["^{s}"] = null;
      this.map["^{nm}"] = { factory: Automate.StepSelect_Join_AsOrOn, name:  "StepSelect_Join_AsOrOn", skipFirst: false};
    }

    Automate.StepSelect_Join_AsOrOn = function(a_state) {
      Automate.BaseStep.call(this, a_state);
      this.delimeter = "";
      this.map["^{nm}"] = null;
      this.map["^{nnm}"] = { map: {
        "on": {factory: Automate.StepSelect_Join_On, name:  "StepSelect_Join_On", skipFirst: false},
        "as": {factory: Automate.StepSelect_Join_As, name:  "StepSelect_Join_As", skipFirst: false},
      } };
    }

    Automate.StepSelect_Join_As = function(a_state) {
      Automate.BaseStep.call(this, a_state);
      this.delimeter = "";
      this.map["^{s}"] = null;
      this.map["^{nm}"] = { factory: Automate.StepSelect_Join_ReadAs, name:  "StepSelect_Join_ReadAs", skipFirst: false};
      this.map["\""] = { factory: Automate.StepSelect_Join_ReadAsQuotes, name:  "StepSelect_Join_ReadAsQuotes", skipFirst: true};
    }

    Automate.StepSelect_Join_ReadAs = function(a_state) {
      Automate.BaseStep.call(this, a_state);
      this.delimeter = "";
      this.map["^{nm}"] = null;
      this.map["^{s}"]  = { factory: Automate.StepSelect_Join_WaitOn, name:  "StepSelect_Join_WaitOn", skipFirst: false };
      this.actionSwitch = function() {
        var join = this.state.join[this.state.join.length-1];
        join.as = this.buffer;
      }
    }

    Automate.StepSelect_Join_ReadAsQuotes = function(a_state) {
      Automate.BaseStep.call(this, a_state);
      this.delimeter = "";
      this.map[""] = null;
      this.map["\""]  = { factory: Automate.StepSelect_Join_WaitOn, name:  "StepSelect_Join_WaitOn", skipFirst: true };
      this.actionSwitch = function() {
        var join = this.state.join[this.state.join.length-1];
        join.as = this.buffer;
      }
    }

    Automate.StepSelect_Join_WaitOn = function(a_state) {
      Automate.BaseStep.call(this, a_state);
      this.delimeter = "";
      this.map["^{s}"] = null;
      this.map["^{nm}"]  = { factory: Automate.StepSelect_Join_WaitOnRead, name:  "StepSelect_Join_WaitOnRead", skipFirst: false};
    }

    Automate.StepSelect_Join_WaitOnRead = function(a_state) {
      Automate.BaseStep.call(this, a_state);
      this.delimeter = "";
      this.map["^{nm}"] = null;
      this.map["^{nnm}"]  = { map: {
        "on": { factory: Automate.StepSelect_Join_On, name:  "StepSelect_Join_On", skipFirst: false}
      } };
    }

    Automate.StepSelect_Join_On = function(a_state) {
      Automate.BaseStep.call(this, a_state);
      this.delimeter = "";
      this.map[""] = {factory: Automate.StepWhere, name:  "StepWhere", skipFirst: false};
      this.actionSwitch = function() {
        var join = this.state.join[this.state.join.length-1];
        join.on = [];
        this.state.details.whereContainer = join.on;
        this.state.details.wherePath = `join[${this.state.join.length-1}].on`;
      }
    }

    Automate.StepSelect_PostWhere = function(a_state) {
      Automate.BaseStep.call(this, a_state);
      this.delimeter = "";
      this.map[""] = {
        map: {
          "group": { factory: Automate.StepSelect_GoToGroup, name: "StepSelect_GoToGroup", skipFirst: false},
          "limit": { factory: Automate.StepSelect_Limit_SkipSpaces, name:  "StepSelect_Limit_SkipSpaces", skipFirst: false},
          "order": { factory: Automate.StepSelect_Order_SkipSpaces, name:  "StepSelect_Order_SkipSpaces", skipFirst: false},
          "language": { factory: Automate.LanguageItem_SkipSpaces, name:  "LanguageItem_SkipSpaces", skipFirst: false},
        }
      };
    }


    Automate.StepSelect_Order_SkipSpaces = function(a_state) {
      Automate.BaseStep.call(this, a_state);
      this.delimeter = "";
      this.map["^{s}"] = null;
      this.map[""]  = { factory: Automate.StepSelect_Order_By, name:  "StepSelect_Order_By", skipFirst: false};
    }

    Automate.StepSelect_Order_By = function(a_state) {
      Automate.BaseStep.call(this, a_state);
      this.delimeter = "";
      this.map["^{nm}"] = null;
      this.map["^{nnm}"]  = { map: {
        "by": { factory: Automate.StepSelect_Order_ReadField_SkipStartSpaces, name:  "StepSelect_Order_ReadField_SkipStartSpaces", skipFirst: false},
        }
      }
    }

    Automate.StepSelect_Order_ReadField_SkipStartSpaces = function(a_state) {
      Automate.BaseStep.call(this, a_state);
      this.delimeter = "";
      this.map["^{s}"] = null;
      this.map[""]  = { factory: Automate.StepSelect_Order_ReadField, name:  "StepSelect_Order_ReadField", skipFirst: false};
      this.map["\""]  = { factory: Automate.StepSelect_Order_ReadFieldQuotes, name:  "StepSelect_Order_ReadFieldQuotes", skipFirst: true};

    }

    Automate.StepSelect_Order_ReadField = function(a_state) {
      Automate.BaseStep.call(this, a_state);
      this.delimeter = "";
      this.map["^{nm}"] = null;
      this.map[""] = { factory: Automate.StepSelect_Order_PostField, name:  "StepSelect_Order_PostField", skipFirst: false};

      this.actionSwitch = function() {
        this.state.order.push({field: this.buffer, order: "asc"});
      }
    }


    Automate.StepSelect_Order_ReadFieldQuotes = function(a_state) {
      Automate.BaseStep.call(this, a_state);
      this.delimeter = "";
      this.map[""] = null;
      this.map["\""] = { factory: Automate.StepSelect_Order_PostField, name:  "StepSelect_Order_PostField", skipFirst: true};

      this.actionSwitch = function() {
        this.state.order.push({field: this.buffer, order: "asc"});
      }
    }

    Automate.StepSelect_Order_PostField = function(a_state) {
      Automate.BaseStep.call(this, a_state);
      this.delimeter = "";
      this.map["^{s}"] = null;
      this.map["."]     = { factory: Automate.StepSelect_Order_ReadField_SecondPartSkipSpaces, name:  "StepSelect_Order_ReadField_SecondPartSkipSpaces", skipFirst: true};
      this.map[","]     = { factory: Automate.StepSelect_Order_ReadField_SkipStartSpaces, name:  "StepSelect_Order_ReadField_SkipStartSpaces", skipFirst: true};
      this.map[""] = { factory: Automate.StepSelect_Order_ReadOrder, name:  "StepSelect_Order_ReadOrder", skipFirst: false};
    }

    Automate.StepSelect_Order_ReadField_SecondPartSkipSpaces = function(a_state) {
      Automate.BaseStep.call(this, a_state);
      this.delimeter = "";
      this.map["^{s}"] = null;
      this.map["^{nm}"]     = { factory: Automate.StepSelect_Order_ReadField_SecondPart, name:  "StepSelect_Order_ReadField_SecondPart", skipFirst: false};
      this.map["\""]     = { factory: Automate.StepSelect_Order_ReadField_SecondPartQuotes, name:  "StepSelect_Order_ReadField_SecondPartQuotes", skipFirst: true};
    }

    Automate.StepSelect_Order_ReadField_SecondPart = function(a_state) {
      Automate.BaseStep.call(this, a_state);
      this.delimeter = "";
      this.map["^{nm}"] = null;
      this.map[""] = { factory: Automate.StepSelect_Order_PostFieldSecondPart, name:  "StepSelect_Order_PostField", skipFirst: false};

      this.actionSwitch = function() {
        var item = this.state.order[this.state.order.length-1];
        item.projection = item.field;
        item.field = this.buffer;
      }
    }

    Automate.StepSelect_Order_ReadField_SecondPartQuotes = function(a_state) {
      Automate.BaseStep.call(this, a_state);
      this.delimeter = "";
      this.map[""] = null;
      this.map["\""] = { factory: Automate.StepSelect_Order_PostFieldSecondPart, name:  "StepSelect_Order_PostField", skipFirst: true};

      this.actionSwitch = function() {
        var item = this.state.order[this.state.order.length-1];
        item.from = item.field;
        item.field = this.buffer;
      }
    }

    Automate.StepSelect_Order_PostFieldSecondPart = function(a_state) {
      Automate.BaseStep.call(this, a_state);
      this.delimeter = "";
      this.map["^{s}"] = null;
      this.map[","]     = { factory: Automate.StepSelect_Order_ReadField_SkipStartSpaces, name:  "StepSelect_Order_ReadField_SkipStartSpaces", skipFirst: true};
      this.map[""] = { factory: Automate.StepSelect_Order_ReadOrder, name:  "StepSelect_Order_ReadOrder", skipFirst: false};
    }


    Automate.StepSelect_Order_ReadOrder = function(a_state) {
      Automate.BaseStep.call(this, a_state);
      this.delimeter = "";
      this.map["^{nm}"] = null;
      this.map[""] = {
        map: {
          "limit": { factory: Automate.StepSelect_Limit_SkipSpaces, name:  "StepSelect_Limit_SkipSpaces", skipFirst: false},
          "asc":   { factory: Automate.StepSelect_Order_SetAsc, name:  "StepSelect_Order_SetAsc", skipFirst: false},
          "desc":  { factory: Automate.StepSelect_Order_SetDesc, name:  "StepSelect_Order_SetDesc", skipFirst: false},
          "language": { factory: Automate.LanguageItem_SkipSpaces, name:  "LanguageItem_SkipSpaces", skipFirst: false},
        }
      };

    }

    Automate.StepSelect_Order_SetAsc = function(a_state) {
      Automate.BaseStep.call(this, a_state);
      this.delimeter = "";
      this.map["^{s}"]   = null;
      this.map[""]      = { factory: Automate.StepSelect_Order_Next, name:  "StepSelect_Order_Next", skipFirst: false};

      this.actionSwitch = function() {
        this.state.order[this.state.order.length-1].order = "asc";
      }
    }

    Automate.StepSelect_Order_SetDesc = function(a_state) {
      Automate.BaseStep.call(this, a_state);
      this.delimeter = "";
      this.map["^{s}"]   = null;
      this.map[""]      = { factory: Automate.StepSelect_Order_Next, name:  "StepSelect_Order_Next", skipFirst: false};

      this.actionSwitch = function() {
        this.state.order[this.state.order.length-1].order = "desc";
      }
    }

    Automate.StepSelect_Order_Next = function(a_state) {
      Automate.BaseStep.call(this, a_state);
      this.delimeter = "";
      this.map["^{nm}"]  = null;
      this.map[","]      = { factory: Automate.StepSelect_Order_ReadField_SkipStartSpaces, name:  "StepSelect_Order_ReadField_SkipStartSpaces", skipFirst: true};
      this.map["^{nnm}"]  = { map : {
        "limit":    {factory: Automate.StepSelect_Limit_SkipSpaces, name:  "StepSelect_Limit_SkipSpaces", skipFirst: false},
        "language": { factory: Automate.LanguageItem_SkipSpaces, name:  "LanguageItem_SkipSpaces", skipFirst: false},
      } };

    }



    Automate.StepSelect_Limit_Close = function(a_state) {
      Automate.BaseStep.call(this, a_state);
      this.delimeter = "^{s}";
      this.map["limit"] = { factory: Automate.StepSelect_Limit_SkipSpaces, name:  "StepSelect_Limit_SkipSpaces", skipFirst: false};
      this.map["language"] = { factory: Automate.LanguageItem_SkipSpaces, name:  "LanguageItem_SkipSpaces", skipFirst: false};
    }


    Automate.StepSelect_Limit_SkipSpaces = function(a_state) {
      Automate.BaseStep.call(this, a_state);
      this.delimeter = "";
      this.map["^{s}"] = null;
      this.map["$"]  = { factory: Automate.StepSelect_Limit_PreReadArg, name:  "StepSelect_Limit_ReadArg", skipFirst: true};
    }

    Automate.StepSelect_Limit_PreReadArg = function(a_state) {
      Automate.BaseStep.call(this, a_state);
      this.delimeter = "";
      this.map["{"] = { factory: Automate.StepSelect_Limit_ReadArg, name:  "StepSelect_Limit_ReadArg", skipFirst: true};
    }

    Automate.StepSelect_Limit_ReadArg = function(a_state) {
      Automate.BaseStep.call(this, a_state);
      this.delimeter = "";
      this.map["^{nm}"] = null;
      this.map["}"]  = { factory: Automate.StepSelect_Limit_PostSkipSpaces, name:  "StepSelect_Limit_PostSkipSpaces", skipFirst: true};

      this.actionSwitch = function() {
        var number = parseInt(this.buffer);
        if (isNaN(number))
          throw "Incorrect value";
        a_state.limit  = this.state.details.args[number-1];
        a_state.args["limit"] = number;
      }
    }


    Automate.StepSelect_Limit_PostSkipSpaces = function(a_state) {
      Automate.BaseStep.call(this, a_state);
      this.delimeter = "";
      this.map["^{s}"] = null;
      this.map[""] = { factory: Automate.StepSelect_Limit_Post, name:  "StepSelect_Limit_Post", skipFirst: false};
    }

    Automate.StepSelect_Limit_Post = function(a_state) {
      Automate.BaseStep.call(this, a_state);
      this.delimeter = "";
      this.map["^{nm}"] = null;
      this.map["^{s}"] = { map: {
        "offset":   { factory: Automate.StepSelect_Offset_SkipSpaces, name:  "StepSelect_Offset_SkipSpaces", skipFirst: false},
        "language": { factory: Automate.LanguageItem_SkipSpaces, name:  "LanguageItem_SkipSpaces", skipFirst: false},
      }};;
    }

    Automate.StepSelect_Offset_SkipSpaces = function(a_state) {
      Automate.BaseStep.call(this, a_state);
      this.delimeter = "";
      this.map["^{s}"] = null;
      this.map["$"]  = { factory: Automate.StepSelect_Offset_PreRead, name:  "StepSelect_Offset_PreRead", skipFirst: true};
    }

    Automate.StepSelect_Offset_PreRead = function(a_state) {
      Automate.BaseStep.call(this, a_state);
      this.delimeter = "";
      this.map["{"]  = { factory: Automate.StepSelect_Offset_Read, name:  "StepSelect_Offset_Read", skipFirst: true};
    }

    Automate.StepSelect_Offset_Read = function(a_state) {
      Automate.BaseStep.call(this, a_state);
      this.delimeter = "";
      this.map["^{n}"] = null;
      this.map["}"] = { factory: Automate.StepSelect_Offset_PostSkipSpaces, name:  "StepSelect_Offset_PostSkipSpaces", skipFirst: true};
      this.actionSwitch = function() {
        var number = parseInt(this.buffer);
        if (isNaN(number))
          throw "Incorrect value";
        a_state.offset  = this.state.details.args[number-1];
        a_state.args["offset"] = number;
      }
    }

    Automate.StepSelect_Offset_PostSkipSpaces = function(a_state) {
      Automate.BaseStep.call(this, a_state);
      this.delimeter = "";
      this.map["^{s}"]  = null;
      this.map["^{nm}"] = { factory: "LanguageItem_Start", skipFirst: false};
    }


    return Automate;
  }
});
