RandomAccessLoggable =
  (require './RandomAccessLoggable.coffee').RandomAccessLoggable
ExodusError = (require '../util/ExodusVersion.coffee').ExodusError

# This class provides an ability to create various loggables of the same type.
class LoggableFactory
  # @private
  @MAXIMUM_LOGGABLE_TYPE = 128
  # @private
  @FACTORY: new Array LoggableFactory.MAXIMUM_LOGGABLE_TYPE

  # @protected
  # Constructor.
  @create: (o) ->
    if !o? then o = new LoggableFactory
    return o

  # Register new factory.
  #
  # @param type loggable type.
  # @param loggableFactory new factory.
  @registerLoggable$int$LoggableFactory: (type, loggableFactory) ->
    prevLoggableFactory = LoggableFactory.FACTORY[type]
    if prevLoggableFactory? && prevLoggableFactory != loggableFactory
       throw new ExodusError("Loggable type is already registered: " +
       type.toString())
    LoggableFactory.FACTORY[type] = loggableFactory

  # Clears all prototypes.
  @clear: () ->
    for i in [0..LoggableFactory.FACTORY.length - 1]
      LoggableFactory.FACTORY[i] = null

  # Creates new instance of loggable.
  #
  # @param address address of result in the log.
  # @param type type of loggable.
  # @param length length of the loggable.
  # @param data loggable data.
  # @param dataLength length of the loggable data.
  # @param structureId structure id of loggable.
  # @return new loggable instance.
  @create$Addr64$int$int$RandomAccessByteIterable$int$int: (address, type, length, data, dataLength, structureId) ->
    prototype = LoggableFactory.FACTORY[type]
    if prototype?
      return prototype.create address, length, data, dataLength, structureId
    return RandomAccessLoggable.
    create$Addr64$int$int$RandomAccessByteIterable$int$int address, type,
            length, data, dataLength, structureId

  # @protected
  # Creates new instance of loggable.
  #
  # @param address address of result in the log.
  # @param length length of the loggable.
  # @param data loggable data.
  # @param dataLength length of the loggable data.
  # @param structureId structure id of loggable.
  # @return new loggable instance.
  create$Addr64$int$RandomAccessByteIterable$int$int: (address, length, data, dataLength, structureId) ->
    # Overload in child classes.

exports.LoggableFactory = LoggableFactory