--===========================================================================--
--                                                                           --
--                         System.Collections.Array                          --
--                                                                           --
--===========================================================================--

--===========================================================================--
-- Author       :   kurapica125@outlook.com                                  --
-- URL          :   http://github.com/kurapica/PLoop                         --
-- Create Date  :   2018/03/20                                               --
-- Update Date  :   2018/03/20                                               --
-- Version      :   1.0.0                                                    --
--===========================================================================--

PLoop(function(_ENV)
    namespace "System.Collections"

    import "System.Serialization"

    --- The array of objects with event control
    -- @usage
    --      class "A" {
    --          -- Property
    --          Name = { Type = String, Event = "OnNameChanged", Default = "Anonymous" };
    --
    --          -- Constructor
    --          A = function(self, name) self.Name = name end;
    --      }
    --
    --     -- The Array is a template class, you can specific the element class
    --      ar = Array[A](A("Ann"), A("Ben"), A("Coco"))
    --
    --      -- You can set event handler to all objects by assign it to the array
    --      function ar:OnNameChanged(new, old)
    --          print( ("%s -> %s"):format(old, new)  )
    --      end
    __ObjFuncAttr__() __SuperObject__(false) __Serializable__()
    __NoRawSet__(false) __NoNilValue__(false) __Arguments__{ AnyType }( Any )
    class "Array"                       (function(_ENV, eletype)
        inherit (List[eletype])

        -----------------------------------------------------------
        --                        helper                         --
        -----------------------------------------------------------
        local addeventlistener          = function() end

        export {
            parseindex                  = Toolset.parseindex,
            getErrorMessage             = Struct.GetErrorMessage,
        }

        if Interface.Validate(eletype) or Class.Validate(eletype) then
            export {
                getfeature              = Interface.GetFeature,
                validevent              = Event.Validate,
                rawget                  = rawget,
                rawset                  = rawset,
                pairs                   = pairs,
                tinsert                 = table.insert,
                ARRAY_EVENT             = "__PLOOP_ARRAY_EVENT",
            }

            export { Event }

            function addeventlistener(self, obj)
                local evts              = rawget(self, ARRAY_EVENT)
                if evts then
                    for k, v in pairs(evts) do
                        obj[k]          = v
                    end
                end
            end
        end

        -----------------------------------------------------------
        --                        method                         --
        -----------------------------------------------------------
        if Interface.Validate(eletype) or Class.Validate(eletype) then
            __Arguments__{ Integer, eletype }
            function Insert(self, idx, obj)
                tinsert(self, idx, obj)
                addeventlistener(self, obj)
            end

            __Arguments__{ eletype }
            function Insert(self, obj)
                tinsert(self, obj)
                addeventlistener(self, obj)
            end
        end

        -----------------------------------------------------------
        --                      meta-method                      --
        -----------------------------------------------------------
        if Interface.Validate(eletype) or Class.Validate(eletype) then
            __Arguments__{ String, Callable }
            function __newindex(self, key, value)
                local evt               = getfeature(eletype, key)
                if evt and validevent(evt) then
                    local evts          = rawget(self, ARRAY_EVENT) or {}
                    rawset(self, ARRAY_EVENT, evts)
                    evts[key]           = value

                    self:Each(key, value)
                else
                    error("The " .. tostring(eletype) .. " don't have an event named " .. tostring(key), 2)
                end
            end

            __Arguments__{ Number, eletype }
            __newindex                  = rawset
        else
            __Arguments__{ String, Callable }
            function __newindex(self, key)
                error("The " .. tostring(eletype) .. " don't have an event named " .. tostring(key), 2)
            end

            __Arguments__{ Number, eletype }
            __newindex                  = rawset
        end
    end)
end)