EventEmitter = (require 'events').EventEmitter
List = (require '../list/List.coffee').List
Cursor = (require './Cursor.coffee').Cursor

class Store extends EventEmitter
  # @private
  env: undefined
  # @private
  name: undefined
  # @private
  structureId: undefined
  # @private
  config: undefined
  # @private
  log: undefined
  # @private
  list: undefined

  @EMITTER: new EventEmitter()

  # Constructor.
  #
  # @param env
  # @param name
  # @param structureId
  # @param config
  @create$Environment$String$int$StoreConfiguration: (env, name, structureId, config, o) ->
    if !o? then o = new Store
    o.env = env
    o.name = name
    o.structureId = structureId
    o.config = config
    log = env.getLog$String name
    List.EMITTER.once 'create', (list) =>
      o.list = list
      Store.EMITTER.emit 'create', o
    List.create$Log$Boolean$int log, config.dublicates, structureId

  getName: () ->
    return @name

  getList: () ->
    return @list

  getConfig: () ->
    return @config

  get$TransactionDescriptor$ByteIterable$emit: (txn, key) ->
    list = txn.getCurrentList$String @name
    list.once 'get', (node) =>
      if node?
        @emit 'get', node.value
      else
        @emit 'get', undefined
    list.get$ByteIterable$emit key

  exists$TransactionDescriptor$ByteIterable$ByteIterable$emit: (txn, key, data) ->
    list = txn.getCurrentList$String @name
    list.once 'get', (node) =>
      if node?
        value = node.value
        value.once 'compare', (res) =>
          @emit 'exists', res
        res = value.compare$int$int$ByteIterable$emit(0, value.getLength(), data)
        if res?
          value.removeAllListeners 'compare'
          @emit 'exists', res
      else
        @emit 'exists', false
    list.get$ByteIterable$emit key

  # <p>If tree supports duplicates, then add key/value pair.</p>
  # <p>If tree doesn't support duplicates and key already exists,
  # then overwrite value.</p>
  # <p>If tree doesn't support duplicates and key doesn't exists,
  # then add key/value pair.</p>
  # <table border=1>
  # <tr><td/><th>Dup</th><th>No Dup</ th > < /tr>
  # <tr><th>Exists</th><td>add</ td > < td > overwrite < /td></ tr >
  # tr > < th > Not Exists < /th><td>add</ td > < td > add < /td></ tr >
  # < /table>
  #
  # @param txn   transaction or null to automatically commit
  # @param key   not null store key
  # @param value not null store value
  put$TransactionDescriptor$ByteIterable$ByteIterable$emit: (txn, key, value) ->
    list = txn.getCurrentList$String @name
    list.once 'push', (node) =>
      @emit 'put'
    list.push$ByteIterable$ByteIterable$emit key, value

  putRight$TransactionDescriptor$ByteIterable$ByteIterable$emit: (txn, key, value) ->
    list = txn.getCurrentList$String @name
    list.once 'push', (node) =>
      @emit 'put'
    list.push$ByteIterable$ByteIterable$emit key, value

  # <p>If tree support duplicates and key already exists, then return false.</p>
  # <p>If tree support duplicates and key doesn't exists, then add key/value
  # pair, return true.</p>
  # <p>If tree doesn't support duplicates and key already exists, then return
  # false.</p>
  # <p>If tree doesn't support duplicates and key doesn't exists, then add
  # key/value pair, return true.</p>
  # <table border=1>
  # <tr><td/><th>Dup</th><th>No Dup</ th > < /tr>
  # <tr><th>Exists</th><td>ret false</ td > < td > ret false < /td></ tr >
  # < tr > < th > Not Exists < /th><td>add, ret true</ td > < td > add, ret
  # true < /td></ tr >
  # < /table>
  #
  # @param txn   transaction or null to automatically commit
  # @param key   not null store key
  # @param value not null store value
  # @return true if key/value pair was added
  add$TransactionDescriptor$ByteIterable$ByteIterable$emit: (txn, key, value) ->
    list = txn.getCurrentList$String @name
    list.once 'add', (isAdded) ->
      @emit 'add', isAdded
    list.add$ByteIterable$ByteIterable$emit key, value

  # Delete key/value pair for given key. If duplicate values exists for given
  # key, all them will be removed.
  #
  # @param txn
  # @param key
  # @return false if key wasn't found
  delete$TransactionDescriptor$ByteIterable$emit: (txn, key) ->
    list = txn.getCurrentList$String @name
    list.once 'delete', (key) ->
      @emit 'delete', key
    list.delete$ByteIterable$emit key

  count: () ->
    list = @env.getCurrentTransaction().getCurrentList$String @name
    return list.getLength()

  openCursor$TransactionDescriptor: (txn) ->
    return Cursor.create$Store$TransactionDescriptor this, txn

  close$emit: () ->
    @list.once 'close', () =>
      @emit 'close'
    @list.close$emit()

  getName: () ->
    return @name

  getConfig: () ->
    return @config

exports.Store = Store
