using UnityEngine;
using System.Collections;
using System.Collections.Generic;

public class Game : MonoBehaviour
{

    public Camera gameCamera;
    public Character player;
    bool[] inputs;
    bool[] prevInputs;

    public KeyCode goLeftKey = KeyCode.A;
    public KeyCode goRightKey = KeyCode.D;
    public KeyCode goJumpKey = KeyCode.W;
    public KeyCode goDownKey = KeyCode.S;

    int lastMouseTileX = -1;
    int lastMouseTileY = -1;

    public Map mMap;

    public TileType mPlacedTileType;

    public Transform mCharacterPrefab;
    public Transform mMovingPlatformPrefab;

    protected List<MovingObject> mObjects = new List<MovingObject>();

    public SpriteRenderer mMouseSprite;

    void Start ()
    {
        Application.targetFrameRate = 60;

        Slopes.Init();

        inputs = new bool[(int)KeyInput.Count];
        prevInputs = new bool[(int)KeyInput.Count];

        player.mGame = this;
        player.mMap = mMap;
        player.Init(inputs, prevInputs);
        player.mType = ObjectType.Player;

        mMap.Init();
        mMap.SetSprite(mMouseSprite, mPlacedTileType);
    }
	
	void Update()
    {
        inputs[(int)KeyInput.GoRight] = Input.GetKey(goRightKey);
        inputs[(int)KeyInput.GoLeft] = Input.GetKey(goLeftKey);
        inputs[(int)KeyInput.GoDown] = Input.GetKey(goDownKey);
        inputs[(int)KeyInput.Jump] = Input.GetKey(goJumpKey);

        if (Input.GetKeyUp(KeyCode.Mouse0))
            lastMouseTileX = lastMouseTileY = -1;

        Vector2 mousePos = Input.mousePosition;
        Vector2 cameraPos = Camera.main.transform.position;
        var mousePosInWorld = cameraPos + mousePos - new Vector2(gameCamera.pixelWidth / 2, gameCamera.pixelHeight / 2);

        int mouseTileX, mouseTileY;
        mMap.GetMapTileAtPoint(mousePosInWorld, out mouseTileX, out mouseTileY);

        Vector2 offsetMouse = (Vector2)(Input.mousePosition) - new Vector2(Camera.main.pixelWidth / 2, Camera.main.pixelHeight / 2);

        if (Input.GetKeyDown(KeyCode.Tab))
            Debug.Break();

        if (Input.GetKey(KeyCode.Mouse1) || Input.GetKey(KeyCode.Mouse2))
        {
            if (mouseTileX != lastMouseTileX || mouseTileY != lastMouseTileY || Input.GetKeyDown(KeyCode.Mouse1) || Input.GetKeyDown(KeyCode.Mouse2))
            {
                if (!mMap.IsNotEmpty(mouseTileX, mouseTileY))
                    mMap.SetTile(mouseTileX, mouseTileY, mPlacedTileType);
                else
                    mMap.SetTile(mouseTileX, mouseTileY, TileType.Empty);

                lastMouseTileX = mouseTileX;
                lastMouseTileY = mouseTileY;

                Debug.Log(mouseTileX + "  " + mouseTileY);
            }
        }
        else if (Input.GetKeyDown(KeyCode.Space))
        {
            Character chara = Instantiate(mCharacterPrefab).GetComponent<Character>();
            chara.mGame = this;
            chara.mMap = mMap;
            chara.mTransform.position = mousePosInWorld;
            chara.Init(new bool[(int)KeyInput.Count], new bool[(int)KeyInput.Count]);
            chara.mType = ObjectType.NPC;
        }
        else if (Input.GetKeyDown(KeyCode.P))
        {
            MovingPlatform platform = Instantiate(mMovingPlatformPrefab).GetComponent<MovingPlatform>();
            platform.mGame = this;
            platform.mMap = mMap;
            platform.mTransform.position = mousePosInWorld;
            platform.mPosition = platform.mTransform.position;
            platform.Init();
            platform.mType = ObjectType.MovingPlatform;
        }

        TileCollisionType collisionType = TileCollisionType.Empty;

        bool set = true;
        while (set || (Slopes.IsOneWay(collisionType) && (Slopes.IsFlippedY(collisionType) || Slopes.IsFlipped90(collisionType))))
        {
            set = false;

            var wheel = Input.GetAxis("Mouse ScrollWheel");
            if (wheel > 0.05f || Input.GetKeyUp(KeyCode.RightArrow))
            {

                if ((int)mPlacedTileType < (int)TileType.Count - 1)
                    mPlacedTileType +=  1;
                else
                    mPlacedTileType = TileType.Block;

                collisionType = mMap.SetSprite(mMouseSprite, mPlacedTileType);

            }
            else if (wheel < -0.05f || Input.GetKeyUp(KeyCode.LeftArrow))
            {
                if ((int)mPlacedTileType > (int)TileType.Empty + 1)
                    mPlacedTileType -= 1;
                else
                    mPlacedTileType = TileType.Count - 1;

                collisionType = mMap.SetSprite(mMouseSprite, mPlacedTileType);
            }
        }

        mMouseSprite.transform.position = mMap.GetMapTilePosition(mouseTileX, mouseTileY);
    }

    public void SwapUpdateIds(MovingObject a, MovingObject b)
    {
        int tmp = a.mUpdateId;
        a.mUpdateId = b.mUpdateId;
        b.mUpdateId = tmp;
        mObjects[a.mUpdateId] = a;
        mObjects[b.mUpdateId] = b;
    }

    public int AddToUpdateList(MovingObject obj)
    {
        mObjects.Add(obj);
        return mObjects.Count - 1;
    }

    void FixedUpdate()
    {
        for (int i = 0; i < mObjects.Count; ++i)
        {
            switch (mObjects[i].mType)
            {
                case ObjectType.Player:
                case ObjectType.NPC:
                    ((Character)mObjects[i]).CustomUpdate();
                    mMap.UpdateAreas(mObjects[i]);
                    mObjects[i].mAllCollidingObjects.Clear();
                    break;
                case ObjectType.MovingPlatform:
                    ((MovingPlatform)mObjects[i]).CustomUpdate();
                    mMap.UpdateAreas(mObjects[i]);
                    mObjects[i].mAllCollidingObjects.Clear();
                    break;
            }
        }

        mMap.CheckCollisions();

        for (int i = 0; i < mObjects.Count; ++i)
            mObjects[i].UpdatePhysicsP2();
    }
}
