-- Auto-generated protocol definition
-- DO NOT EDIT - This file is generated by Morel
local Protocol = {}
Protocol.name = "txse_seed"
Protocol.description = "txse_seed"
-- Enum definitions
Protocol.enums = {}
Protocol.enums.CancelReason = {
  [1] = "REQUESTED_BY_USER",
  [2] = "RELATED_TO_TIME_IN_FORCE",
  [3] = "RELATED_TO_MIN_QTY",
  [4] = "REG_NMS_VIOLATION_NO_SLIDE",
  [5] = "MARKETABLE_RESERVE",
  [6] = "SELF_MATCH_PREVENTION",
  [7] = "REPLENISHMENT_CANCELED_DUE_TO_RESERVE",
  [8] = "RELATED_TO_ORDER_TYPE",
  [9] = "CANCELED_DUE_TO_CROSSED_MARKETS",
  [10] = "CANCELED_DUE_TO_MASS_CANCEL_REQUEST",
  [11] = "EXCHANGE_LOCKED_OR_CROSSED_NO_SLIDE",
  [12] = "REG_SHO_VIOLATION_NO_SLIDE",
}
Protocol.enums.LiquidityIndicator = {
  [0] = "REMOVED_HIDDEN_LIQUIDITY",
  [1] = "REMOVED_DISPLAYED_LIQUIDITY",
  [2] = "ADDED_HIDDEN_LIQUIDITY",
  [3] = "ADDED_DISPLAYED_LIQUIDITY",
}
Protocol.enums.MarketHoursState = {
  [0] = "CLOSED_BEFORE_HOURS",
  [1] = "EARLY_SESSION",
  [2] = "REGULAR_SESSION",
  [3] = "AFTER_HOURS_SESSION",
  [4] = "CLOSED_AFTER_HOURS",
}
Protocol.enums.MassCancelScope = {
  [0] = "BY_MEMBER_OWNED_SENDER_COMPS",
  [1] = "BY_MEMBER_OWNED_MPIDS",
}
Protocol.enums.OperationalHaltReason = {
  [0] = "ADMINISTRATIVE",
}
Protocol.enums.OrderCapacity = {
  [1] = "AGENCY",
  [2] = "PRINCIPAL",
  [3] = "RISKLESS_PRINCIPAL",
}
Protocol.enums.PriceSlideInstruction = {
  [0] = "NO_PRICE_SLIDE",
  [1] = "SINGLE_PRICE_SLIDE_ON_LOCK_AND_CROSS",
  [2] = "MULTIPLE_PRICE_SLIDES_ON_LOCK_AND_CROSS",
  [3] = "SINGLE_PRICE_SLIDE_LOCK_ONLY",
}
Protocol.enums.RegulatoryHaltReason = {
  [0] = "REASON_NOT_AVAILABLE",
  [1] = "NEWS_PENDING",
  [2] = "NEWS_DISSEMINATION",
  [3] = "INFO_REQUESTED",
  [4] = "ORDER_IMBALANCE",
  [5] = "EXTRAORDINARY_MARKET_ACTIVITY",
  [6] = "LULD_PAUSE",
  [7] = "NON_COMPLIANCE",
  [8] = "FILINGS_NOT_CURRENT",
  [9] = "SEC_SUSPENSION",
  [10] = "REGULATORY_CONCERN",
  [11] = "SUB_PENNY_TRADING",
  [12] = "ETF",
  [13] = "IPO_NOT_TRADING",
  [14] = "CORPORATE_ACTION",
  [15] = "CIRCUIT_BREAKER_L1",
  [16] = "CIRCUIT_BREAKER_L2",
  [17] = "CIRCUIT_BREAKER_L3",
}
Protocol.enums.RejectReason = {
  [1] = "INVALID_CLIENT_ORDER_ID",
  [2] = "DUPLICATE_CLIENT_ORDER_ID",
  [3] = "UNKNOWN_ORIGINAL_CLIENT_ORDER_ID",
  [4] = "NO_LONGER_ON_BOOK",
  [5] = "INVALID_SYMBOL",
  [6] = "INVALID_PRICE",
  [7] = "INVALID_ORDER_QUANTITY",
  [8] = "INVALID_REFERENCE_PRICE_TARGET",
  [9] = "INVALID_IS_HIDDEN_FLAG",
  [10] = "INVALID_ORDER_TYPE",
  [11] = "INVALID_SIDE",
  [12] = "INVALID_MAX_FLOOR_QUANTITY",
  [13] = "INVALID_MAX_REPLENISH_QUANTITY_RANGE",
  [14] = "INVALID_MAX_REPLENISH_TIME_RANGE",
  [15] = "INVALID_MINIMUM_QUANTITY",
  [16] = "INVALID_LOCATE_REQUIRED_FLAG",
  [17] = "INVALID_TIME_IN_FORCE",
  [18] = "MODIFICATION_NOT_PERMITTED",
  [19] = "INVALID_MPID",
  [20] = "INVALID_SENDER_COMP",
  [21] = "INVALID_IS_POST_ONLY_FLAG",
  [22] = "INVALID_EXPIRE_TIME",
  [23] = "ORDER_INVALID_FOR_TRADING_SESSION",
  [24] = "ORDER_INVALID_FOR_TRADING_STATUS",
  [25] = "ORDER_INVALID_FOR_SYMBOL_STATUS",
  [26] = "INVALID_IS_ISO_FLAG",
  [27] = "TRADING_DISABLED_FOR_MPID_ON_PORT",
  [28] = "TRADING_DISABLED_FOR_NON_TEST_SYMBOLS",
  [29] = "TRADING_DISABLED_FOR_ORDER_CAPACITY",
  [30] = "TRADING_DISABLED_FOR_ISO",
  [31] = "MAXIMUM_ORDER_QUANTITY_BREACHED",
  [32] = "MAXIMUM_PRICE_BREACHED",
  [33] = "MAXIMUM_NOTIONAL_BREACHED",
  [34] = "INVALID_MASS_CANCEL_REQUEST_ID",
  [35] = "SYMBOL_ON_RESTRICTED_LIST",
}
Protocol.enums.RestatementReason = {
  [1] = "RESERVE_REPLENISHED",
  [2] = "REPRICED",
}
Protocol.enums.SelfMatchInstruction = {
  [0] = "NO_SELF_MATCH_PREVENTION",
  [1] = "CANCEL_NEWEST",
  [2] = "CANCEL_OLDEST",
  [3] = "CANCEL_BOTH",
  [4] = "CANCEL_SMALLEST",
  [5] = "DECREMENT_AND_CANCEL",
}
Protocol.enums.SelfMatchScope = {
  [0] = "BY_MEMBER",
  [1] = "BY_MPID",
  [2] = "BY_MEMBER_GROUP",
  [3] = "BY_MPID_AND_MEMBER_GROUP",
}
Protocol.enums.SessionTradingState = {
  [0] = "CLOSED",
  [1] = "TRADING",
  [2] = "HALTED",
}
Protocol.enums.ShortSaleRestrictionState = {
  [0] = "NONE",
  [1] = "ACTIVATED",
  [2] = "CONTINUED",
}
Protocol.enums.Side = {
  [0] = "BUY",
  [1] = "LONG_SELL",
  [2] = "SHORT_SELL",
  [3] = "SHORT_EXEMPT",
}
Protocol.enums.SymbolTradingState = {
  [1] = "TRADING",
  [2] = "HALTED",
}
Protocol.enums.TimeInForce = {
  [1] = "SYS",
  [2] = "IOC",
  [3] = "GTT",
  [4] = "DAY",
  [5] = "RHO",
}
-- Field definitions
-- Returns a function that creates Fields table given TXSE lib
Protocol.createFields = function(TXSE)
  local Fields = {}
  local Enums = Protocol.enums
  Fields["msgType"] = {
    length = 1,
    abbr = "txse_seed.msgType",
    name = "msgType",
    ftype = ftypes.CHAR,
    encoding = ENC_ASCII,
    value_map = {
      [65] = "MarketOrder",
      [67] = "CancelOrder",
      [68] = "MarketOrderAccepted",
      [69] = "OrderExecuted",
      [70] = "OrderRestated",
      [73] = "LimitOrderAccepted",
      [74] = "OrderReplaced",
      [75] = "ReplaceRejected",
      [76] = "LimitOrder",
      [77] = "ModifyOrder",
      [78] = "ModifyRejected",
      [79] = "MassCancelAccepted",
      [80] = "MassCancelRejected",
      [81] = "MassCancelResult",
      [82] = "ReplaceOrder",
      [84] = "MarketOrderRejected",
      [85] = "LimitOrderRejected",
      [86] = "MassCancel",
      [87] = "CancelRejected",
      [88] = "OrderCanceled",
      [89] = "OrderModified",
      [90] = "SelfMatchPrevented",
      [105] = "TradingSessionStatus",
      [115] = "DefineSymbol",
      [121] = "SymbolStatus",
    },
  }
  Fields["cancelReason"] = {
    length = 1,
    abbr = "txse_seed.cancelReason",
    name = "cancelReason",
    ftype = ftypes.INT8,
    encoding = ENC_NA,
    kotlin_type = "com.txse.exchange.CancelReason",
    value_map = Enums.CancelReason,
  }
  Fields["canceledCount"] = {
    length = 4,
    abbr = "txse_seed.canceledCount",
    name = "canceledCount",
    ftype = ftypes.INT32,
    encoding = ENC_LITTLE_ENDIAN,
    kotlin_type = "kotlin.Int",
  }
  Fields["canceledQty"] = {
    length = 4,
    abbr = "txse_seed.canceledQty",
    name = "canceledQty",
    ftype = ftypes.INT32,
    encoding = ENC_LITTLE_ENDIAN,
    kotlin_type = "com.txse.avail.Quantity",
  }
  Fields["clOrdId"] = {
    length = 8,
    abbr = "txse_seed.clOrdId",
    name = "clOrdId",
    ftype = ftypes.INT64,
    encoding = ENC_LITTLE_ENDIAN,
    kotlin_type = "com.txse.exchange.ClOrdId",
  }
  Fields["com.txse.exchange.specs.shared.define.DefineSymbolBitFields"] = {
    length = 1,
    abbr = "txse_seed.defineSymbolBitFields",
    name = "defineSymbolBitFields",
    ftype = ftypes.INT8,
    encoding = ENC_NA,
    kotlin_type = "com.txse.exchange.specs.shared.define.DefineSymbolBitFields",
    custom_decode = function(buffer, pinfo, tree)
      local numeric = buffer(0, 1):le_uint()
      tree:add(buffer, string.format("isTest: %d", TXSE.extract_bits(numeric, 0)))
      tree:add(buffer, string.format("reserved: %d", TXSE.extract_bits(numeric, 1, 7)))
    end,
  }
  Fields["displayPrice"] = {
    length = 8,
    abbr = "txse_seed.displayPrice",
    name = "displayPrice",
    ftype = ftypes.INT64,
    encoding = ENC_LITTLE_ENDIAN,
    kotlin_type = "com.txse.avail.Price",
  }
  Fields["displayQty"] = {
    length = 4,
    abbr = "txse_seed.displayQty",
    name = "displayQty",
    ftype = ftypes.INT32,
    encoding = ENC_LITTLE_ENDIAN,
    kotlin_type = "com.txse.avail.Quantity",
  }
  Fields["execId"] = {
    length = 8,
    abbr = "txse_seed.execId",
    name = "execId",
    ftype = ftypes.INT64,
    encoding = ENC_LITTLE_ENDIAN,
    kotlin_type = "com.txse.exchange.ExecId",
  }
  Fields["execPrice"] = {
    length = 8,
    abbr = "txse_seed.execPrice",
    name = "execPrice",
    ftype = ftypes.INT64,
    encoding = ENC_LITTLE_ENDIAN,
    kotlin_type = "com.txse.avail.Price",
  }
  Fields["execQty"] = {
    length = 4,
    abbr = "txse_seed.execQty",
    name = "execQty",
    ftype = ftypes.INT32,
    encoding = ENC_LITTLE_ENDIAN,
    kotlin_type = "com.txse.avail.Quantity",
  }
  Fields["expireTime"] = {
    length = 8,
    abbr = "txse_seed.expireTime",
    name = "expireTime",
    ftype = ftypes.INT64,
    encoding = ENC_LITTLE_ENDIAN,
    kotlin_type = "com.txse.avail.TimeStamp",
  }
  Fields["leavesQty"] = {
    length = 4,
    abbr = "txse_seed.leavesQty",
    name = "leavesQty",
    ftype = ftypes.INT32,
    encoding = ENC_LITTLE_ENDIAN,
    kotlin_type = "com.txse.avail.Quantity",
  }
  Fields["com.txse.exchange.specs.seed.define.LimitOrderBitFields"] = {
    length = 4,
    abbr = "txse_seed.limitOrderBitFields",
    name = "limitOrderBitFields",
    ftype = ftypes.INT32,
    encoding = ENC_LITTLE_ENDIAN,
    kotlin_type = "com.txse.exchange.specs.seed.define.LimitOrderBitFields",
    custom_decode = function(buffer, pinfo, tree)
      local numeric = buffer(0, 4):le_uint()
      local side = TXSE.extract_bits(numeric, 0, 3)
      tree:add(buffer, string.format("side: %d (%s)", side, Enums.Side[side] or "Unknown"))
      tree:add(buffer, string.format("isLocateRequired: %d", TXSE.extract_bits(numeric, 3)))
      local timeInForce = TXSE.extract_bits(numeric, 4, 4)
      tree:add(buffer, string.format("timeInForce: %d (%s)", timeInForce, Enums.TimeInForce[timeInForce] or "Unknown"))
      local orderCapacity = TXSE.extract_bits(numeric, 8, 3)
      tree:add(buffer, string.format("orderCapacity: %d (%s)", orderCapacity, Enums.OrderCapacity[orderCapacity] or "Unknown"))
      tree:add(buffer, string.format("isIso: %d", TXSE.extract_bits(numeric, 11)))
      tree:add(buffer, string.format("isHidden: %d", TXSE.extract_bits(numeric, 12)))
      tree:add(buffer, string.format("isPostOnly: %d", TXSE.extract_bits(numeric, 13)))
      tree:add(buffer, string.format("cancelAtEntryIfCrossed: %d", TXSE.extract_bits(numeric, 14)))
      tree:add(buffer, string.format("reserved: %d", TXSE.extract_bits(numeric, 15, 17)))
    end,
  }
  Fields["liquidityIndicator"] = {
    length = 1,
    abbr = "txse_seed.liquidityIndicator",
    name = "liquidityIndicator",
    ftype = ftypes.INT8,
    encoding = ENC_NA,
    kotlin_type = "com.txse.exchange.LiquidityIndicator",
    value_map = Enums.LiquidityIndicator,
  }
  Fields["locateBroker"] = {
    length = 4,
    abbr = "txse_seed.locateBroker",
    name = "locateBroker",
    ftype = ftypes.INT32,
    encoding = ENC_LITTLE_ENDIAN,
    kotlin_type = "com.txse.exchange.LocateBroker",
  }
  Fields["lotSize"] = {
    length = 4,
    abbr = "txse_seed.lotSize",
    name = "lotSize",
    ftype = ftypes.INT32,
    encoding = ENC_LITTLE_ENDIAN,
    kotlin_type = "com.txse.avail.Quantity",
  }
  Fields["marketHoursState"] = {
    length = 1,
    abbr = "txse_seed.marketHoursState",
    name = "marketHoursState",
    ftype = ftypes.INT8,
    encoding = ENC_NA,
    kotlin_type = "com.txse.exchange.MarketHoursState",
    value_map = Enums.MarketHoursState,
  }
  Fields["com.txse.exchange.specs.seed.define.MarketOrderBitFields"] = {
    length = 2,
    abbr = "txse_seed.marketOrderBitFields",
    name = "marketOrderBitFields",
    ftype = ftypes.INT16,
    encoding = ENC_LITTLE_ENDIAN,
    kotlin_type = "com.txse.exchange.specs.seed.define.MarketOrderBitFields",
    custom_decode = function(buffer, pinfo, tree)
      local numeric = buffer(0, 2):le_uint()
      local side = TXSE.extract_bits(numeric, 0, 3)
      tree:add(buffer, string.format("side: %d (%s)", side, Enums.Side[side] or "Unknown"))
      tree:add(buffer, string.format("isLocateRequired: %d", TXSE.extract_bits(numeric, 3)))
      local timeInForce = TXSE.extract_bits(numeric, 4, 4)
      tree:add(buffer, string.format("timeInForce: %d (%s)", timeInForce, Enums.TimeInForce[timeInForce] or "Unknown"))
      local orderCapacity = TXSE.extract_bits(numeric, 8, 3)
      tree:add(buffer, string.format("orderCapacity: %d (%s)", orderCapacity, Enums.OrderCapacity[orderCapacity] or "Unknown"))
      tree:add(buffer, string.format("reserved: %d", TXSE.extract_bits(numeric, 11, 5)))
    end,
  }
  Fields["massCancelId"] = {
    length = 8,
    abbr = "txse_seed.massCancelId",
    name = "massCancelId",
    ftype = ftypes.INT64,
    encoding = ENC_LITTLE_ENDIAN,
    kotlin_type = "com.txse.exchange.MassCancelId",
  }
  Fields["massCancelRequestId"] = {
    length = 8,
    abbr = "txse_seed.massCancelRequestId",
    name = "massCancelRequestId",
    ftype = ftypes.INT64,
    encoding = ENC_LITTLE_ENDIAN,
    kotlin_type = "com.txse.exchange.MassCancelId",
  }
  Fields["massCancelScope"] = {
    length = 1,
    abbr = "txse_seed.massCancelScope",
    name = "massCancelScope",
    ftype = ftypes.INT8,
    encoding = ENC_NA,
    kotlin_type = "com.txse.exchange.MassCancelScope",
    value_map = Enums.MassCancelScope,
  }
  Fields["matchingEngineId"] = {
    length = 1,
    abbr = "txse_seed.matchingEngineId",
    name = "matchingEngineId",
    ftype = ftypes.INT8,
    encoding = ENC_NA,
    kotlin_type = "com.txse.avail.StreamId",
  }
  Fields["maxFloorQty"] = {
    length = 4,
    abbr = "txse_seed.maxFloorQty",
    name = "maxFloorQty",
    ftype = ftypes.INT32,
    encoding = ENC_LITTLE_ENDIAN,
    kotlin_type = "com.txse.avail.Quantity",
  }
  Fields["maxReplenishQtyRange"] = {
    length = 4,
    abbr = "txse_seed.maxReplenishQtyRange",
    name = "maxReplenishQtyRange",
    ftype = ftypes.INT32,
    encoding = ENC_LITTLE_ENDIAN,
    kotlin_type = "com.txse.avail.Quantity",
  }
  Fields["maxReplenishTimeRange"] = {
    length = 8,
    abbr = "txse_seed.maxReplenishTimeRange",
    name = "maxReplenishTimeRange",
    ftype = ftypes.INT64,
    encoding = ENC_LITTLE_ENDIAN,
    kotlin_type = "kotlin.time.Duration",
  }
  Fields["memberGroup"] = {
    length = 2,
    abbr = "txse_seed.memberGroup",
    name = "memberGroup",
    ftype = ftypes.INT16,
    encoding = ENC_LITTLE_ENDIAN,
    kotlin_type = "com.txse.exchange.MemberGroup",
  }
  Fields["minQty"] = {
    length = 4,
    abbr = "txse_seed.minQty",
    name = "minQty",
    ftype = ftypes.INT32,
    encoding = ENC_LITTLE_ENDIAN,
    kotlin_type = "com.txse.avail.Quantity",
  }
  Fields["com.txse.exchange.specs.seed.define.ModifyBitFields"] = {
    length = 1,
    abbr = "txse_seed.modifyBitFields",
    name = "modifyBitFields",
    ftype = ftypes.INT8,
    encoding = ENC_NA,
    kotlin_type = "com.txse.exchange.specs.seed.define.ModifyBitFields",
    custom_decode = function(buffer, pinfo, tree)
      local numeric = buffer(0, 1):le_uint()
      local side = TXSE.extract_bits(numeric, 0, 3)
      tree:add(buffer, string.format("side: %d (%s)", side, Enums.Side[side] or "Unknown"))
      tree:add(buffer, string.format("isLocateRequired: %d", TXSE.extract_bits(numeric, 3)))
      tree:add(buffer, string.format("reserved: %d", TXSE.extract_bits(numeric, 4, 4)))
    end,
  }
  Fields["mpid"] = {
    length = 4,
    abbr = "txse_seed.mpid",
    name = "mpid",
    ftype = ftypes.INT32,
    encoding = ENC_LITTLE_ENDIAN,
    kotlin_type = "com.txse.exchange.MPID",
  }
  Fields["operationalHaltReason"] = {
    length = 1,
    abbr = "txse_seed.operationalHaltReason",
    name = "operationalHaltReason",
    ftype = ftypes.INT8,
    encoding = ENC_NA,
    kotlin_type = "com.txse.exchange.OperationalHaltReason",
    value_map = Enums.OperationalHaltReason,
  }
  Fields["orderId"] = {
    length = 8,
    abbr = "txse_seed.orderId",
    name = "orderId",
    ftype = ftypes.INT64,
    encoding = ENC_LITTLE_ENDIAN,
    kotlin_type = "com.txse.exchange.OrderId",
  }
  Fields["orderQty"] = {
    length = 4,
    abbr = "txse_seed.orderQty",
    name = "orderQty",
    ftype = ftypes.INT32,
    encoding = ENC_LITTLE_ENDIAN,
    kotlin_type = "com.txse.avail.Quantity",
  }
  Fields["origClOrdId"] = {
    length = 8,
    abbr = "txse_seed.origClOrdId",
    name = "origClOrdId",
    ftype = ftypes.INT64,
    encoding = ENC_LITTLE_ENDIAN,
    kotlin_type = "com.txse.exchange.ClOrdId",
  }
  Fields["price"] = {
    length = 8,
    abbr = "txse_seed.price",
    name = "price",
    ftype = ftypes.INT64,
    encoding = ENC_LITTLE_ENDIAN,
    kotlin_type = "com.txse.avail.Price",
  }
  Fields["priceSlideInstruction"] = {
    length = 1,
    abbr = "txse_seed.priceSlideInstruction",
    name = "priceSlideInstruction",
    ftype = ftypes.INT8,
    encoding = ENC_NA,
    kotlin_type = "com.txse.exchange.PriceSlideInstruction",
    value_map = Enums.PriceSlideInstruction,
  }
  Fields["rankPrice"] = {
    length = 8,
    abbr = "txse_seed.rankPrice",
    name = "rankPrice",
    ftype = ftypes.INT64,
    encoding = ENC_LITTLE_ENDIAN,
    kotlin_type = "com.txse.avail.Price",
  }
  Fields["referencePriceTarget"] = {
    length = 2,
    abbr = "txse_seed.referencePriceTarget",
    name = "referencePriceTarget",
    ftype = ftypes.INT16,
    encoding = ENC_LITTLE_ENDIAN,
    kotlin_type = "com.txse.avail.BasisPoints",
  }
  Fields["regulatoryHaltReason"] = {
    length = 1,
    abbr = "txse_seed.regulatoryHaltReason",
    name = "regulatoryHaltReason",
    ftype = ftypes.INT8,
    encoding = ENC_NA,
    kotlin_type = "com.txse.exchange.RegulatoryHaltReason",
    value_map = Enums.RegulatoryHaltReason,
  }
  Fields["rejectReason"] = {
    length = 1,
    abbr = "txse_seed.rejectReason",
    name = "rejectReason",
    ftype = ftypes.INT8,
    encoding = ENC_NA,
    kotlin_type = "com.txse.exchange.RejectReason",
    value_map = Enums.RejectReason,
  }
  Fields["com.txse.exchange.specs.seed.define.ReplaceBitFields"] = {
    length = 2,
    abbr = "txse_seed.replaceBitFields",
    name = "replaceBitFields",
    ftype = ftypes.INT16,
    encoding = ENC_LITTLE_ENDIAN,
    kotlin_type = "com.txse.exchange.specs.seed.define.ReplaceBitFields",
    custom_decode = function(buffer, pinfo, tree)
      local numeric = buffer(0, 2):le_uint()
      local side = TXSE.extract_bits(numeric, 0, 3)
      tree:add(buffer, string.format("side: %d (%s)", side, Enums.Side[side] or "Unknown"))
      tree:add(buffer, string.format("isLocateRequired: %d", TXSE.extract_bits(numeric, 3)))
      tree:add(buffer, string.format("isIso: %d", TXSE.extract_bits(numeric, 4)))
      tree:add(buffer, string.format("isPostOnly: %d", TXSE.extract_bits(numeric, 5)))
      tree:add(buffer, string.format("cancelAtEntryIfCrossed: %d", TXSE.extract_bits(numeric, 6)))
      tree:add(buffer, string.format("reserved: %d", TXSE.extract_bits(numeric, 7, 9)))
    end,
  }
  Fields["restatementReason"] = {
    length = 1,
    abbr = "txse_seed.restatementReason",
    name = "restatementReason",
    ftype = ftypes.INT8,
    encoding = ENC_NA,
    kotlin_type = "com.txse.exchange.RestatementReason",
    value_map = Enums.RestatementReason,
  }
  Fields["selfMatchInstruction"] = {
    length = 1,
    abbr = "txse_seed.selfMatchInstruction",
    name = "selfMatchInstruction",
    ftype = ftypes.INT8,
    encoding = ENC_NA,
    kotlin_type = "com.txse.exchange.SelfMatchInstruction",
    value_map = Enums.SelfMatchInstruction,
  }
  Fields["selfMatchScope"] = {
    length = 1,
    abbr = "txse_seed.selfMatchScope",
    name = "selfMatchScope",
    ftype = ftypes.INT8,
    encoding = ENC_NA,
    kotlin_type = "com.txse.exchange.SelfMatchScope",
    value_map = Enums.SelfMatchScope,
  }
  Fields["senderComp"] = {
    length = 8,
    abbr = "txse_seed.senderComp",
    name = "senderComp",
    ftype = ftypes.INT64,
    encoding = ENC_LITTLE_ENDIAN,
    kotlin_type = "com.txse.foundation.protocols.rake.morel.define.SenderComp",
  }
  Fields["sessionTradingState"] = {
    length = 1,
    abbr = "txse_seed.sessionTradingState",
    name = "sessionTradingState",
    ftype = ftypes.INT8,
    encoding = ENC_NA,
    kotlin_type = "com.txse.exchange.SessionTradingState",
    value_map = Enums.SessionTradingState,
  }
  Fields["shortSaleRestrictionState"] = {
    length = 1,
    abbr = "txse_seed.shortSaleRestrictionState",
    name = "shortSaleRestrictionState",
    ftype = ftypes.INT8,
    encoding = ENC_NA,
    kotlin_type = "com.txse.exchange.ShortSaleRestrictionState",
    value_map = Enums.ShortSaleRestrictionState,
  }
  Fields["suffix"] = {
    length = 8,
    abbr = "txse_seed.suffix",
    name = "suffix",
    ftype = ftypes.INT64,
    encoding = ENC_LITTLE_ENDIAN,
    kotlin_type = "com.txse.exchange.SymbolSuffix",
  }
  Fields["symbol"] = {
    length = 8,
    abbr = "txse_seed.symbol",
    name = "symbol",
    ftype = ftypes.INT64,
    encoding = ENC_LITTLE_ENDIAN,
    kotlin_type = "com.txse.exchange.SymbolRoot",
  }
  Fields["symbolId"] = {
    length = 2,
    abbr = "txse_seed.symbolId",
    name = "symbolId",
    ftype = ftypes.INT16,
    encoding = ENC_LITTLE_ENDIAN,
    kotlin_type = "com.txse.exchange.SymbolId",
  }
  Fields["symbolTradingState"] = {
    length = 1,
    abbr = "txse_seed.symbolTradingState",
    name = "symbolTradingState",
    ftype = ftypes.INT8,
    encoding = ENC_NA,
    kotlin_type = "com.txse.exchange.SymbolTradingState",
    value_map = Enums.SymbolTradingState,
  }
  Fields["transactTime"] = {
    length = 8,
    abbr = "txse_seed.transactTime",
    name = "transactTime",
    ftype = ftypes.INT64,
    encoding = ENC_LITTLE_ENDIAN,
    kotlin_type = "com.txse.avail.TimeStamp",
  }
  Fields["userData"] = {
    length = 8,
    abbr = "txse_seed.userData",
    name = "userData",
    ftype = ftypes.INT64,
    encoding = ENC_LITTLE_ENDIAN,
    kotlin_type = "kotlin.Long",
  }
  Fields["limitOrderPresence"] = {
    length = 4,
    abbr = "txse_seed.limitOrderPresence",
    name = "limitOrderPresence",
    ftype = ftypes.BYTES,
    encoding = ENC_NA,
    is_presence_field = true,
  }
  Fields["limitOrderAcceptedPresence"] = {
    length = 4,
    abbr = "txse_seed.limitOrderAcceptedPresence",
    name = "limitOrderAcceptedPresence",
    ftype = ftypes.BYTES,
    encoding = ENC_NA,
    is_presence_field = true,
  }
  Fields["limitOrderRejectedPresence"] = {
    length = 4,
    abbr = "txse_seed.limitOrderRejectedPresence",
    name = "limitOrderRejectedPresence",
    ftype = ftypes.BYTES,
    encoding = ENC_NA,
    is_presence_field = true,
  }
  Fields["marketOrderPresence"] = {
    length = 2,
    abbr = "txse_seed.marketOrderPresence",
    name = "marketOrderPresence",
    ftype = ftypes.BYTES,
    encoding = ENC_NA,
    is_presence_field = true,
  }
  Fields["marketOrderAcceptedPresence"] = {
    length = 2,
    abbr = "txse_seed.marketOrderAcceptedPresence",
    name = "marketOrderAcceptedPresence",
    ftype = ftypes.BYTES,
    encoding = ENC_NA,
    is_presence_field = true,
  }
  Fields["marketOrderRejectedPresence"] = {
    length = 2,
    abbr = "txse_seed.marketOrderRejectedPresence",
    name = "marketOrderRejectedPresence",
    ftype = ftypes.BYTES,
    encoding = ENC_NA,
    is_presence_field = true,
  }
  Fields["massCancelPresence"] = {
    length = 1,
    abbr = "txse_seed.massCancelPresence",
    name = "massCancelPresence",
    ftype = ftypes.BYTES,
    encoding = ENC_NA,
    is_presence_field = true,
  }
  Fields["massCancelAcceptedPresence"] = {
    length = 1,
    abbr = "txse_seed.massCancelAcceptedPresence",
    name = "massCancelAcceptedPresence",
    ftype = ftypes.BYTES,
    encoding = ENC_NA,
    is_presence_field = true,
  }
  Fields["massCancelRejectedPresence"] = {
    length = 1,
    abbr = "txse_seed.massCancelRejectedPresence",
    name = "massCancelRejectedPresence",
    ftype = ftypes.BYTES,
    encoding = ENC_NA,
    is_presence_field = true,
  }
  Fields["modifyOrderPresence"] = {
    length = 1,
    abbr = "txse_seed.modifyOrderPresence",
    name = "modifyOrderPresence",
    ftype = ftypes.BYTES,
    encoding = ENC_NA,
    is_presence_field = true,
  }
  Fields["modifyRejectedPresence"] = {
    length = 1,
    abbr = "txse_seed.modifyRejectedPresence",
    name = "modifyRejectedPresence",
    ftype = ftypes.BYTES,
    encoding = ENC_NA,
    is_presence_field = true,
  }
  Fields["orderModifiedPresence"] = {
    length = 1,
    abbr = "txse_seed.orderModifiedPresence",
    name = "orderModifiedPresence",
    ftype = ftypes.BYTES,
    encoding = ENC_NA,
    is_presence_field = true,
  }
  Fields["orderReplacedPresence"] = {
    length = 2,
    abbr = "txse_seed.orderReplacedPresence",
    name = "orderReplacedPresence",
    ftype = ftypes.BYTES,
    encoding = ENC_NA,
    is_presence_field = true,
  }
  Fields["orderRestatedPresence"] = {
    length = 1,
    abbr = "txse_seed.orderRestatedPresence",
    name = "orderRestatedPresence",
    ftype = ftypes.BYTES,
    encoding = ENC_NA,
    is_presence_field = true,
  }
  Fields["replaceOrderPresence"] = {
    length = 2,
    abbr = "txse_seed.replaceOrderPresence",
    name = "replaceOrderPresence",
    ftype = ftypes.BYTES,
    encoding = ENC_NA,
    is_presence_field = true,
  }
  Fields["replaceRejectedPresence"] = {
    length = 2,
    abbr = "txse_seed.replaceRejectedPresence",
    name = "replaceRejectedPresence",
    ftype = ftypes.BYTES,
    encoding = ENC_NA,
    is_presence_field = true,
  }
  Fields["symbolStatusPresence"] = {
    length = 1,
    abbr = "txse_seed.symbolStatusPresence",
    name = "symbolStatusPresence",
    ftype = ftypes.BYTES,
    encoding = ENC_NA,
    is_presence_field = true,
  }
  Fields["tradingSessionStatusPresence"] = {
    length = 1,
    abbr = "txse_seed.tradingSessionStatusPresence",
    name = "tradingSessionStatusPresence",
    ftype = ftypes.BYTES,
    encoding = ENC_NA,
    is_presence_field = true,
  }
  return Fields
end
-- Message definitions
Protocol.messages = {
  {
    name = "CancelOrder",
    type = "C",
    fields = {
      "msgType",
      "origClOrdId",
    },
  },
  {
    name = "CancelRejected",
    type = "W",
    fields = {
      "msgType",
      "transactTime",
      "origClOrdId",
      "rejectReason",
    },
  },
  {
    name = "DefineSymbol",
    type = "s",
    fields = {
      "msgType",
      "transactTime",
      "symbolId",
      "symbol",
      "suffix",
      "matchingEngineId",
      "com.txse.exchange.specs.shared.define.DefineSymbolBitFields",
      "lotSize",
    },
  },
  {
    name = "LimitOrder",
    type = "L",
    fields = {
      "msgType",
      "limitOrderPresence",
      "clOrdId",
      "orderQty",
      "com.txse.exchange.specs.seed.define.LimitOrderBitFields",
      "symbolId",
      "price",
    },
    presence_fields = {
      "selfMatchScope",
      "selfMatchInstruction",
      "priceSlideInstruction",
      "minQty",
      "maxFloorQty",
      "maxReplenishQtyRange",
      "maxReplenishTimeRange",
      "referencePriceTarget",
      "expireTime",
      "userData",
      "mpid",
      "memberGroup",
      "locateBroker",
    },
  },
  {
    name = "LimitOrderAccepted",
    type = "I",
    fields = {
      "msgType",
      "limitOrderAcceptedPresence",
      "transactTime",
      "orderId",
      "clOrdId",
      "orderQty",
      "com.txse.exchange.specs.seed.define.LimitOrderBitFields",
      "symbolId",
      "price",
    },
    presence_fields = {
      "selfMatchScope",
      "selfMatchInstruction",
      "priceSlideInstruction",
      "minQty",
      "maxFloorQty",
      "maxReplenishQtyRange",
      "maxReplenishTimeRange",
      "referencePriceTarget",
      "expireTime",
      "userData",
      "mpid",
      "memberGroup",
      "locateBroker",
      "rankPrice",
      "displayPrice",
    },
  },
  {
    name = "LimitOrderRejected",
    type = "U",
    fields = {
      "msgType",
      "limitOrderRejectedPresence",
      "transactTime",
      "clOrdId",
      "orderQty",
      "com.txse.exchange.specs.seed.define.LimitOrderBitFields",
      "symbolId",
      "price",
      "rejectReason",
    },
    presence_fields = {
      "selfMatchScope",
      "selfMatchInstruction",
      "priceSlideInstruction",
      "minQty",
      "maxFloorQty",
      "maxReplenishQtyRange",
      "maxReplenishTimeRange",
      "referencePriceTarget",
      "expireTime",
      "userData",
      "mpid",
      "memberGroup",
      "locateBroker",
    },
  },
  {
    name = "MarketOrder",
    type = "A",
    fields = {
      "msgType",
      "marketOrderPresence",
      "clOrdId",
      "orderQty",
      "com.txse.exchange.specs.seed.define.MarketOrderBitFields",
      "symbolId",
    },
    presence_fields = {
      "selfMatchScope",
      "selfMatchInstruction",
      "userData",
      "mpid",
      "memberGroup",
      "locateBroker",
    },
  },
  {
    name = "MarketOrderAccepted",
    type = "D",
    fields = {
      "msgType",
      "marketOrderAcceptedPresence",
      "transactTime",
      "orderId",
      "clOrdId",
      "orderQty",
      "com.txse.exchange.specs.seed.define.MarketOrderBitFields",
      "symbolId",
    },
    presence_fields = {
      "selfMatchScope",
      "selfMatchInstruction",
      "userData",
      "mpid",
      "memberGroup",
      "locateBroker",
    },
  },
  {
    name = "MarketOrderRejected",
    type = "T",
    fields = {
      "msgType",
      "marketOrderRejectedPresence",
      "transactTime",
      "clOrdId",
      "orderQty",
      "com.txse.exchange.specs.seed.define.MarketOrderBitFields",
      "symbolId",
      "rejectReason",
    },
    presence_fields = {
      "selfMatchScope",
      "selfMatchInstruction",
      "userData",
      "mpid",
      "memberGroup",
      "locateBroker",
    },
  },
  {
    name = "MassCancel",
    type = "V",
    fields = {
      "msgType",
      "massCancelPresence",
      "massCancelRequestId",
      "massCancelScope",
    },
    presence_fields = {
      "mpid",
      "senderComp",
      "memberGroup",
      "clOrdId",
    },
  },
  {
    name = "MassCancelAccepted",
    type = "O",
    fields = {
      "msgType",
      "massCancelAcceptedPresence",
      "transactTime",
      "massCancelRequestId",
      "massCancelScope",
      "massCancelId",
    },
    presence_fields = {
      "mpid",
      "senderComp",
      "memberGroup",
      "clOrdId",
    },
  },
  {
    name = "MassCancelRejected",
    type = "P",
    fields = {
      "msgType",
      "massCancelRejectedPresence",
      "transactTime",
      "massCancelRequestId",
      "massCancelScope",
      "rejectReason",
    },
    presence_fields = {
      "mpid",
      "senderComp",
      "memberGroup",
      "clOrdId",
    },
  },
  {
    name = "MassCancelResult",
    type = "Q",
    fields = {
      "msgType",
      "transactTime",
      "massCancelRequestId",
      "massCancelId",
      "canceledCount",
    },
  },
  {
    name = "ModifyOrder",
    type = "M",
    fields = {
      "msgType",
      "modifyOrderPresence",
      "clOrdId",
      "origClOrdId",
    },
    presence_fields = {
      "orderQty",
      "com.txse.exchange.specs.seed.define.ModifyBitFields",
      "locateBroker",
    },
  },
  {
    name = "ModifyRejected",
    type = "N",
    fields = {
      "msgType",
      "modifyRejectedPresence",
      "transactTime",
      "clOrdId",
      "origClOrdId",
      "rejectReason",
    },
    presence_fields = {
      "orderQty",
      "com.txse.exchange.specs.seed.define.ModifyBitFields",
      "locateBroker",
    },
  },
  {
    name = "OrderCanceled",
    type = "X",
    fields = {
      "msgType",
      "transactTime",
      "orderId",
      "origClOrdId",
      "cancelReason",
    },
  },
  {
    name = "OrderExecuted",
    type = "E",
    fields = {
      "msgType",
      "transactTime",
      "orderId",
      "clOrdId",
      "execPrice",
      "execId",
      "execQty",
      "leavesQty",
      "liquidityIndicator",
    },
  },
  {
    name = "OrderModified",
    type = "Y",
    fields = {
      "msgType",
      "orderModifiedPresence",
      "transactTime",
      "orderId",
      "clOrdId",
      "origClOrdId",
      "leavesQty",
    },
    presence_fields = {
      "orderQty",
      "com.txse.exchange.specs.seed.define.ModifyBitFields",
      "locateBroker",
    },
  },
  {
    name = "OrderReplaced",
    type = "J",
    fields = {
      "msgType",
      "orderReplacedPresence",
      "transactTime",
      "orderId",
      "clOrdId",
      "origClOrdId",
      "com.txse.exchange.specs.seed.define.ReplaceBitFields",
      "leavesQty",
    },
    presence_fields = {
      "price",
      "orderQty",
      "maxFloorQty",
      "selfMatchScope",
      "selfMatchInstruction",
      "priceSlideInstruction",
      "referencePriceTarget",
      "locateBroker",
      "rankPrice",
      "displayPrice",
    },
  },
  {
    name = "OrderRestated",
    type = "F",
    fields = {
      "msgType",
      "orderRestatedPresence",
      "transactTime",
      "orderId",
      "clOrdId",
      "restatementReason",
    },
    presence_fields = {
      "rankPrice",
      "displayPrice",
      "displayQty",
    },
  },
  {
    name = "ReplaceOrder",
    type = "R",
    fields = {
      "msgType",
      "replaceOrderPresence",
      "clOrdId",
      "origClOrdId",
      "com.txse.exchange.specs.seed.define.ReplaceBitFields",
    },
    presence_fields = {
      "price",
      "orderQty",
      "maxFloorQty",
      "selfMatchScope",
      "selfMatchInstruction",
      "priceSlideInstruction",
      "referencePriceTarget",
      "locateBroker",
    },
  },
  {
    name = "ReplaceRejected",
    type = "K",
    fields = {
      "msgType",
      "replaceRejectedPresence",
      "transactTime",
      "clOrdId",
      "origClOrdId",
      "com.txse.exchange.specs.seed.define.ReplaceBitFields",
      "rejectReason",
    },
    presence_fields = {
      "price",
      "orderQty",
      "maxFloorQty",
      "selfMatchScope",
      "selfMatchInstruction",
      "priceSlideInstruction",
      "referencePriceTarget",
      "locateBroker",
    },
  },
  {
    name = "SelfMatchPrevented",
    type = "Z",
    fields = {
      "msgType",
      "transactTime",
      "orderId",
      "clOrdId",
      "execPrice",
      "execId",
      "execQty",
      "canceledQty",
      "leavesQty",
      "liquidityIndicator",
    },
  },
  {
    name = "SymbolStatus",
    type = "y",
    fields = {
      "msgType",
      "symbolStatusPresence",
      "transactTime",
      "symbolId",
      "symbolTradingState",
      "shortSaleRestrictionState",
    },
    presence_fields = {
      "operationalHaltReason",
      "regulatoryHaltReason",
    },
  },
  {
    name = "TradingSessionStatus",
    type = "i",
    fields = {
      "msgType",
      "tradingSessionStatusPresence",
      "transactTime",
      "marketHoursState",
      "sessionTradingState",
    },
    presence_fields = {
      "operationalHaltReason",
      "regulatoryHaltReason",
    },
  },
}
-- Dissector setup
-- opts.payload_decoder: optional function(buffer, pinfo, tree_item) for trailing payload
Protocol.register = function(opts)
  local TXSE = require("txse-lib")
  local proto, messages = TXSE.Proto.new(TXSE.createSpec(Protocol, opts))
  function proto.dissector(buffer, pinfo, tree)
    local length = buffer:len()
    if length < 1 then
      return 0
    end
    local msg_type = buffer(0, 1):uint()
    local msg = messages.mapping[msg_type]
    if not msg then
      return 0
    end
    pinfo.cols.protocol = proto.name
    pinfo.cols.info = msg.name
    local subtree = tree:add(proto, buffer, msg.name)
    msg:parse(buffer, pinfo, subtree)
    return buffer:len()
  end
  return proto
end
return Protocol
