using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using SDL2;

namespace testdrid.SdlWrapper
{
    internal class Renderer : IDisposable
    {
        private Renderer() { }

        internal IntPtr Pointer { get; set; }

        public static Renderer Create(Window targetWindow)
        {
            return Create(targetWindow, -1, SDL.SDL_RendererFlags.SDL_RENDERER_ACCELERATED | SDL.SDL_RendererFlags.SDL_RENDERER_PRESENTVSYNC);
        }

        public static Renderer Create(Window targetWindow, int index, SDL.SDL_RendererFlags flags)
        {
            Renderer child = new Renderer();
            child.Pointer = SDL.SDL_CreateRenderer(targetWindow.Pointer, index, flags);
            if (child.Pointer == IntPtr.Zero)
            {
                throw SdlException.GenerateException();
            }

            return child;
        }

        public void Dispose()
        {
            SDL.SDL_DestroyRenderer(Pointer);
            Pointer = IntPtr.Zero;
        }

        public void Clear()
        {
            SDL.SDL_RenderClear(Pointer);
        }

        public void Copy(Texture texture)
        {
            int sdlRenderCopy = SDL.SDL_RenderCopy(this.Pointer, texture.Pointer, IntPtr.Zero, IntPtr.Zero);
            if (sdlRenderCopy != 0)
                throw SdlException.GenerateException();
        }

        public void Copy(Texture texture, ref SDL.SDL_Rect sourceRect, ref SDL.SDL_Rect targetRect)
        {
            int sdlRenderCopy = SDL.SDL_RenderCopy(this.Pointer, texture.Pointer, ref sourceRect, ref targetRect);
            if (sdlRenderCopy != 0)
                throw SdlException.GenerateException();
        }

        public void Copy(Texture texture, Point targetPoint)
        {
            SDL.SDL_Rect targetRect = new SDL.SDL_Rect();
            targetRect.x = targetPoint.X;
            targetRect.y = targetPoint.Y;
            targetRect.w = texture.GetWidth();
            targetRect.h = texture.GetHeight();

            int sdlRenderCopy = SDL.SDL_RenderCopy(this.Pointer, texture.Pointer, IntPtr.Zero, ref targetRect);
            if (sdlRenderCopy != 0)
                throw SdlException.GenerateException();
        }

        public void Copy(Texture texture, Rectangle rectangle)
        {
            SDL.SDL_Rect targetRect = new SDL.SDL_Rect();
            targetRect.x = rectangle.X;
            targetRect.y = rectangle.Y;
            targetRect.w = rectangle.Width;
            targetRect.h = rectangle.Height;

            int sdlRenderCopy = SDL.SDL_RenderCopy(this.Pointer, texture.Pointer, IntPtr.Zero, ref targetRect);
            if (sdlRenderCopy != 0)
                throw SdlException.GenerateException();
        }

        public void SetDrawBlendMode(SDL.SDL_BlendMode blendMode)
        {
            int result = SDL.SDL_SetRenderDrawBlendMode(Pointer, blendMode);
            if (result != 0)
                throw SdlException.GenerateException();
        }

        public void Present()
        {
            lock (Lockable)
            {
                SDL.SDL_RenderPresent(Pointer);
            }
        }

        private static object _lockable;

        public static object Lockable
        {
            get
            {
                if (_lockable == null)
                    _lockable = new object();

                return _lockable;
            }
        }
    }
}
