using System;
using System.Collections.Generic;
using System.Text;
using IrrlichtNetSwig;

namespace Movement
{
    class Program
    {
        static void Main(string[] args)
        {

            E_DRIVER_TYPE driverType = E_DRIVER_TYPE.EDT_DIRECT3D9;

            System.Console.WriteLine(@"Please select the driver you want for this example:
(a) Direct3D 9.0c
(b) Direct3D 8.1
(c) OpenGL 1.5
(d) Software Renderer
(e) Burning's Software Renderer
(f) NullDevice
(otherKey) exit");

            ConsoleKeyInfo key = Console.ReadKey();

            switch (key.KeyChar)
            {
                case 'a': driverType = E_DRIVER_TYPE.EDT_DIRECT3D9; break;
                case 'b': driverType = E_DRIVER_TYPE.EDT_DIRECT3D8; break;
                case 'c': driverType = E_DRIVER_TYPE.EDT_OPENGL; break;
                case 'd': driverType = E_DRIVER_TYPE.EDT_SOFTWARE; break;
                case 'e': driverType = E_DRIVER_TYPE.EDT_BURNINGSVIDEO; break;
                case 'f': driverType = E_DRIVER_TYPE.EDT_NULL; break;
                default: return;
            }

            // create device
            SEventReceiver receiver = new SEventReceiver();

            IrrlichtDevice device = IrrlichtNet.createDevice(driverType,
                    new dimension2di(640, 480), 16, false, false, false, receiver);

            if (device == null)
                return; // could not create selected driver.

            IVideoDriver driver = device.getVideoDriver();
            ISceneManager smgr = device.getSceneManager();

            /*
            Create the node which will be moved with the WSAD keys. We create a
            sphere node, which is a built-in geometry primitive. We place the node
            at (0,0,30) and assign a texture to it to let it look a little bit more
            interesting. Because we have no dynamic lights in this scene we disable
            lighting for each model (otherwise the models would be black).
            */
            ISceneNode node = smgr.addSphereSceneNode();
            if (node != null)
            {
                node.setPosition(new vector3df(0, 0, 30));
                node.setMaterialTexture(0, driver.getTexture("../../media/wall.bmp"));
                node.setMaterialFlag(E_MATERIAL_FLAG.EMF_LIGHTING, false);
            }

            /*
            Now we create another node, movable using a scene node animator. Scene
            node animators modify scene nodes and can be attached to any scene node
            like mesh scene nodes, billboards, lights and even camera scene nodes.
            Scene node animators are not only able to modify the position of a
            scene node, they can also animate the textures of an object for
            example. We create a cube scene node and attach a 'fly circle' scene
            node animator to it, letting this node fly around our sphere scene node.
            */
            ISceneNode n = smgr.addCubeSceneNode();

            if (n != null)
            {
                n.setMaterialTexture(0, driver.getTexture("../../media/t351sml.jpg"));
                n.setMaterialFlag(E_MATERIAL_FLAG.EMF_LIGHTING, false);
                ISceneNodeAnimator anim =
                    smgr.createFlyCircleAnimator(new vector3df(0, 0, 30), 20.0f);
                if (anim != null)
                {
                    n.addAnimator(anim);
                }
            }

            /*
            The last scene node we add to show possibilities of scene node animators is
            a md2 model, which uses a 'fly straight' animator to run between to points.
            */
            IAnimatedMeshSceneNode anms =
                smgr.addAnimatedMeshSceneNode(smgr.getMesh("../../media/ninja.b3d"));

            if (anms != null)
            {
                ISceneNodeAnimator anim =
                    smgr.createFlyStraightAnimator(new vector3df(100, 0, 60),
                    new vector3df(-100, 0, 60), 3500, true);
                if (anim != null)
                {
                    anms.addAnimator(anim);
                    anim.drop();
                }

                /*
                To make the model look right we disable lighting, set the
                frames between which the animation should loop, rotate the
                model around 180 degrees, and adjust the animation speed and
                the texture. To set the right animation (frames and speed), we
                would also be able to just call
                "anms->setMD2Animation(scene::EMAT_RUN)" for the 'run'
                animation instead of "setFrameLoop" and "setAnimationSpeed",
                but this only works with MD2 animations, and so you know how to
                start other animations. But a good advice is to not use
                hardcoded frame-numbers...
                */
                anms.setMaterialFlag(E_MATERIAL_FLAG.EMF_LIGHTING, false);

                anms.setFrameLoop(0, 14);
                anms.setAnimationSpeed(15);
                //		anms->setMD2Animation(scene::EMAT_RUN);

                anms.setScale(new vector3df(2.0f, 2.0f, 2.0f));
                anms.setRotation(new vector3df(0, -90, 0));
                //		anms->setMaterialTexture(0, driver->getTexture("../../media/sydney.bmp"));

            }


            /*
            To be able to look at and move around in this scene, we create a first
            person shooter style camera and make the mouse cursor invisible.
            */
            smgr.addCameraSceneNodeFPS(null, 100.0f, .1f);
            device.getCursorControl().setVisible(false);

            /*
            Add a colorful irrlicht logo
            */
            device.getGUIEnvironment().addImage(
                driver.getTexture("../../media/irrlichtlogoalpha2.tga"),
                new position2di(10, 20));

            IGUIStaticText diagnostics = device.getGUIEnvironment().addStaticText(
                "", new recti(10, 10, 400, 20));
            diagnostics.setOverrideColor(new SColor(255, 255, 255, 0));

            /*
            We have done everything, so lets draw it. We also write the current
            frames per second and the name of the driver to the caption of the
            window.
            */
            int lastFPS = -1;

            // In order to do framerate independent movement, we have to know
            // how long it was since the last frame
            uint then = device.getTimer().getTime();

            // This is the movemen speed in units per second.
            const float MOVEMENT_SPEED = 5.0f;

            while (device.run())
            {
                // Work out a frame delta time.
                uint now = device.getTimer().getTime();
                float frameDeltaTime = (float)(now - then) / 1000.0f; // Time in seconds
                then = now;

                /* Check if keys W, S, A or D are being held down, and move the
                sphere node around respectively. */
                vector3df nodePosition = node.getPosition();

                if (receiver.IsKeyDown(EKEY_CODE.KEY_KEY_W))
                    nodePosition.Y += MOVEMENT_SPEED * frameDeltaTime;
                else if (receiver.IsKeyDown(EKEY_CODE.KEY_KEY_S))
                    nodePosition.Y -= MOVEMENT_SPEED * frameDeltaTime;

                if (receiver.IsKeyDown(EKEY_CODE.KEY_KEY_A))
                    nodePosition.X -= MOVEMENT_SPEED * frameDeltaTime;
                else if (receiver.IsKeyDown(EKEY_CODE.KEY_KEY_D))
                    nodePosition.X += MOVEMENT_SPEED * frameDeltaTime;

                node.setPosition(nodePosition);

                driver.beginScene(true, true, new SColor(255, 113, 113, 133));

                smgr.drawAll(); // draw the 3d scene
                device.getGUIEnvironment().drawAll(); // draw the gui environment (the logo)

                driver.endScene();

                int fps = driver.getFPS();

                if (lastFPS != fps)
                {
                    string tmp = "Movement Example - Irrlicht Engine [";
                    tmp += driver.getName();
                    tmp += "] fps: ";
                    tmp += fps.ToString();

                    device.setWindowCaption(tmp);
                    lastFPS = fps;
                }
            }

        }
    }


    class SEventReceiver : IEventReceiver
    {
        public override bool OnEvent(SEvent arg0)
        {
            if (arg0.EventType == EEVENT_TYPE.EET_KEY_INPUT_EVENT)
            {
                KeyIsDown[(int)arg0.getKeyInput().Key] = arg0.getKeyInput().PressedDown;
                Console.WriteLine("EET_KEY_INPUT_EVENT {0} {1}", arg0.KeyInput.Char, arg0.KeyInput.Key);
            }
            else if (arg0.EventType == EEVENT_TYPE.EET_MOUSE_INPUT_EVENT)
            {
                Console.WriteLine("EET_MOUSE_INPUT_EVENT {0} {1} {2}", arg0.MouseInput.X, arg0.MouseInput.Y, arg0.MouseInput.Wheel);
            }
            else if (arg0.EventType == EEVENT_TYPE.EET_LOG_TEXT_EVENT)
            {
                Console.WriteLine("EET_LOG_TEXT_EVENT {0}", arg0.LogEvent.Text);
            }
            return false;
        }

        // This is used to check whether a key is being held down
        public bool IsKeyDown(EKEY_CODE keyCode)
        {
            return KeyIsDown[(int)keyCode];
        }

        public SEventReceiver()
            :base()
        {
            for (int i = 0; i < (int)EKEY_CODE.KEY_KEY_CODES_COUNT; ++i)
            {
                KeyIsDown[i] = false;
            }
        }


        // We use this array to store the current state of each key
        bool[] KeyIsDown = new bool[(int)EKEY_CODE.KEY_KEY_CODES_COUNT];
    }
}
