private LuaTable GetNativeContainerCore(IDataContainer container)
        {
            // Makes the container friendly :)
            FriendLuaDataContainer fc = container as FriendLuaDataContainer;

            // Sanity check.
            if (fc == null)
            {
                throw new InvalidOperationException("The container has not been created by this instance of LuaDataFactory.");
            }

            // Returns the container.
            return(fc.Table);
        }
        private FriendLuaDataContainer CreateContainerCore(LuaTable native, bool protectFromGC = false)
        {
            // Gets a protected version of the table if needed.
            if (protectFromGC)
            {
                native = _luaState.SafeProtectTableFromGC(native);
            }

            // Creates a new container.
            FriendLuaDataContainer ldc = new FriendLuaDataContainer(native, _luaState, this);

            // Returns the container.
            return(ldc);
        }
        private WherigoObject GetWherigoObjectCore(
            LuaTable obj,
            bool dontFailIfNotWigEntity = false,
            bool forceProtectFromGC     = false,
            bool allowsNullTable        = false,
            Type typeToCompare          = null)
        {
            // Sanity check.
            if (obj == null)
            {
                if (!allowsNullTable)
                {
                    throw new ArgumentNullException("Null table argument is not allowed.");
                }

                return(null);
            }

            // Gets the class of the entity.
            string cn = _luaState.SafeGetField <string>(obj, "ClassName");

            if (cn == null)
            {
                if (dontFailIfNotWigEntity)
                {
                    return(null);
                }

                throw new InvalidOperationException("obj has no ClassName string property.");
            }

            // Does the entity have an ObjIndex?
            // YES -> it should be in the AllZObjects table, so retrieve or make it.
            // NO -> make it anyway.
            WherigoObject ret   = null;
            double?       oiRaw = _luaState.SafeGetField <double?>(obj, "ObjIndex");

            if (oiRaw == null)
            {
                // Creates a container for the table.
                // It is not protected from GC by default.
                LuaDataContainer ldc = CreateContainerCore(obj, forceProtectFromGC);

                // Immediately wraps the table into its corresponding class.
                if ("ZonePoint" == cn)
                {
                    ret = new ZonePoint(ldc);
                }

                else if ("ZCommand" == cn || "ZReciprocalCommand" == cn)
                {
                    ret = new Command(
                        ldc,
                        MakeCommandCalcTargetObjectsInstance(ldc),
                        MakeCommandExecuteCommandInstance(ldc)
                        );
                }

                else if ("Distance" == cn)
                {
                    ret = new Distance(ldc);
                }
            }
            else
            {
                // Tries to get the object from the cache if it is not
                // the player or cartridge object.
                int  oi          = (int)oiRaw.Value;
                bool isPlayer    = oi < 0;
                bool isCartridge = oi == 0;
                Node node;
                if (!isPlayer && !isCartridge)
                {
                    bool hasValue;
                    lock (_syncRoot)
                    {
                        hasValue = _wEntities.TryGetValue(oi, out node);
                    }
                    // The object is known, returns it.
                    if (hasValue)
                    {
                        ret = node.Object;

                        // Double check the classname.
                        string cachedCn = ret.DataContainer.GetString("ClassName");
                        if (cn != cachedCn)
                        {
                            throw new InvalidOperationException(String.Format("The object with id {0} is known to have class {1}, but class {2} was requested.", oi, cachedCn ?? "<null>", cn ?? "<null>"));
                        }
                    }
                }

                // The object is not known, make it and create a node for it.
                if (ret == null)
                {
                    // Creates a GC-protected container for the table.
                    FriendLuaDataContainer ldc = CreateContainerCore(obj, true);

                    // Creates the object.
                    if ("ZInput" == cn)
                    {
                        ret = new Input(
                            ldc,
                            MakeInputRunOnGetInputInstance(ldc)
                            );
                    }

                    else if ("ZTimer" == cn)
                    {
                        ret = new Timer(ldc);
                    }

                    else if ("ZCharacter" == cn)
                    {
                        if (isPlayer && _helper.Player != null)
                        {
                            ret = _helper.Player;
                        }
                        else
                        {
                            ret = new Character(
                                ldc,
                                MakeUIObjectRunOnClickInstance(ldc)
                                );
                        }
                    }
                    else if ("ZItem" == cn)
                    {
                        ret = new Item(
                            ldc,
                            MakeUIObjectRunOnClickInstance(ldc)
                            );
                    }

                    else if ("ZTask" == cn)
                    {
                        ret = new Task(
                            ldc,
                            MakeUIObjectRunOnClickInstance(ldc)
                            );
                    }

                    else if ("Zone" == cn)
                    {
                        ret = new Zone(
                            ldc,
                            MakeUIObjectRunOnClickInstance(ldc)
                            );
                    }
                    else if ("ZMedia" == cn)
                    {
                        // Gets the ZMedia from the Cartridge which has the same Id.
                        Media media = _helper.Cartridge.Resources.Single(m => m.MediaId == oi);

                        // Injects the data container with metadata about the media.
                        media.DataContainer = ldc;

                        // The returned object is the media.
                        ret = media;
                    }
                    else if ("ZCartridge" == cn)
                    {
                        // Sanity checks if the Cartridge GUIDs match.
                        string baseId = _helper.Cartridge.Guid;
                        string reqId  = ldc.GetString("Id");
                        if (baseId != reqId)
                        {
                            //throw new InvalidOperationException(String.Format("Requested Cartridge with id {0}, but only knows Cartridge with id {1}.", reqId, baseId));
                            System.Diagnostics.Debug.WriteLine("LuaDataFactory: WARNING: " + String.Format("Requested Cartridge with id {0}, but only knows Cartridge with id {1}.", reqId, baseId));
                        }

                        // Returns the cartridge object.
                        ret = _helper.Cartridge;

                        // Binds the cartridge container if the cartridge is unbound.
                        if (ret.DataContainer == null)
                        {
                            ret.DataContainer = ldc;
                        }
                    }
                    else
                    {
                        throw new InvalidOperationException("obj has an unknown classname: " + cn);
                    }

                    // Creates a node and registers it. Cartridge and player are not registered.
                    if (!isPlayer && !isCartridge)
                    {
                        node = new Node()
                        {
                            Container = ldc,
                            Object    = ret
                        };
                        lock (_syncRoot)
                        {
                            _wEntities.Add(oi, node);
                        }
                    }
                }
            }

            // Final sanity checks.
            if (ret == null)
            {
                throw new InvalidOperationException("Returned value was not computed.");
            }
            if (typeToCompare != null && !typeToCompare.IsAssignableFrom(ret.GetType()))
            {
                throw new InvalidOperationException(String.Format("The wherigo object is known to have type {0}, not {1} as requested.", ret.GetType().FullName, typeToCompare.FullName));
            }

            return(ret);
        }