
require:
   .util ->
      tuck, fork-identify
      ID, CACHE
      methods, fields
   "./proxy" ->
      setup-proxy, deprox, proxy
   .object-fill ->
      object-clobber-helper

provide:
   Dict

_items = items

class Dict:

   constructor{data = {=}} =
      @data = object with items{data}

   get{key} =
      @data[key]

   set{String? key or Number? key, value} =
      @data[key] = value

   .delete{key} =
      delete @data[key]

   items{} =
      _items{@data}

   [^methods.proxy]{tracks, patch, prevent-dirty-reads} =
      DictProxy{@, tracks, patch, prevent-dirty-reads}

   [^methods.iterate-properties]{} =
      Object.prototype[methods.iterate-properties].call{@data, @}

   [^methods.fork]{dir} =
      rval = Dict{}
      {ID, CACHE} each field ->
         tuck{rval, field, @[field]}
      fork-identify{rval}
      dir.enter{rval, false}
      items{@data} each {key, value} ->
         rval.data[key] = dir.acquire{value}
      rval

   [^methods.patch]{patch, dir} =
      Object.prototype[methods.patch].call{@data, patch, dir, @}

   [^methods.clobber]{new-dict, dir} =
      if not Dict? new-dict:
         return dir.acquire{new-dict}
      dir.exit{@}
      object-clobber-helper{
         @data, new-dict.data, items
         {a, b} -> Object.has-own-property.call{a, b}
      } each
         #delete{k} ->
            delete @data[k]
         #put{k, v} ->
            @data[k] = dir.clobber{@data[k], v}
      tuck{@, ID, new-dict[ID]}
      dir.enter{@}
      @

   [^methods.changed-relevantly]{reads, writes} =
      items{writes or {=}} each
         {name, _} when reads[name] ->
            return true
         when reads["@iter"] ->
            return true
      false



class DictProxy:

   constructor{obj, tracks, patch, prevent-dirty-reads = true} =
      setup-proxy{@, obj, tracks, patch, prevent-dirty-reads}

   get{key} =
      @[methods.check-dirty-read]{key}
      @[methods.register-tracks]{key, -> true}
      proxy{@[fields.obj].get{key}
            @[fields.tracks]
            @[fields.patch]
            @[fields.prevent-dirty-reads]}

   set{key, value} =
      @[methods.register-patch]{key, -> #update{deprox{value}}}

   .delete{key} =
      @[methods.register-patch]{key, -> #delete{}}

   items{} =
      @[methods.register-tracks]{"@iter", -> true}
      @[fields.obj].items{} each {k, v} ->
         {k, proxy{v
                   @[fields.tracks]
                   @[fields.patch]
                   @[fields.prevent-dirty-reads]}}

