using Igdc;
using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media.Imaging;

namespace Editor
{
    public partial class MapCanvas
    {
        public event EventHandler<Point> PointerOver;

        public Point[,] Map
        {
            get { return _map; }
            set
            {
                _map = value;
                Refresh();
            }
        }

        private Point[,] _map = new Point[0, 0];

        private BitmapSource _bitmap;

        private const int TileSize = 16;

        public Point Tool { get; set; }

        public MapCanvas()
        {
            InitializeComponent();
            _bitmap = BitmapLoader<AssemblyPointer>.Load("MapBackground1");
            SetSize(10, 10);
        }

        private void Root_StylusMove(object sender, StylusEventArgs e)
        {
            var p = e.GetPosition(Root);
            var x = (int)(p.X / TileSize);
            var y = (int)(p.Y / TileSize);
            ProcessInput(MouseButton.Left, x, y);
        }

        private void Root_MouseUp(object sender, MouseButtonEventArgs e)
        {
            var p = e.GetPosition(Root);
            var x = (int)(p.X / TileSize);
            var y = (int)(p.Y / TileSize);
            ProcessInput(e.ChangedButton, x, y);
        }

        private void ProcessInput(MouseButton b, int x, int y)
        {
            if (x > Map.GetUpperBound(0) || y > Map.GetUpperBound(1)) return;
            if (b == MouseButton.Left)
            {
                var tag = new Point(x, y);
                var markedImages = new List<Image>();
                foreach (Image image in TileCanvas.Children)
                    if ((Point)image.Tag == tag)
                        markedImages.Add(image);
                foreach (var image in markedImages)
                    TileCanvas.Children.Remove(image);
                var brushX = (int)Tool.X;
                var brushY = (int)Tool.Y;
                var source = new CroppedBitmap(_bitmap, new Int32Rect(brushX * TileSize, brushY * TileSize, TileSize, TileSize));
                var tile = new Image
                {
                    Width = TileSize,
                    Height = TileSize,
                    Source = source,
                    Margin = new Thickness(x * TileSize, y * TileSize, 0, 0),
                    Tag = new Point(x, y)
                };
                TileCanvas.Children.Add(tile);
                Map[x, y] = new Point(brushX, brushY);
            }
            else
            {
                var tag = new Point(x, y);
                var markedImages = new List<Image>();
                foreach (Image image in TileCanvas.Children)
                    if ((Point)image.Tag == tag)
                        markedImages.Add(image);
                foreach (var image in markedImages)
                    TileCanvas.Children.Remove(image);
            }
        }

        private void Refresh()
        {
            TileCanvas.Children.Clear();
            for (var x = 0; x < Map.GetUpperBound(0) + 1; x++)
                for (var y = 0; y < Map.GetUpperBound(1) + 1; y++)
                {
                    var brushX = (int)Map[x, y].X;
                    var brushY = (int)Map[x, y].Y;
                    var source = new CroppedBitmap(_bitmap, new Int32Rect(brushX * TileSize, brushY * TileSize, TileSize, TileSize));
                    var tile = new Image
                    {
                        Width = TileSize,
                        Height = TileSize,
                        Source = source,
                        Margin = new Thickness(x * TileSize, y * TileSize, 0, 0),
                        Tag = new Point(x, y)
                    };
                    TileCanvas.Children.Add(tile);
                }
        }

        public void SetSize(int width, int height)
        {
            Map = ResizeArray(Map, width, height);
            TileCanvas.Width = width * TileSize;
            TileCanvas.Height = height * TileSize;
        }

        private T[,] ResizeArray<T>(T[,] original, int newCoNum, int newRoNum)
        {
            var newArray = new T[newCoNum, newRoNum];
            var columnCount = original.GetLength(1);
            var columnCount2 = newRoNum;
            var columns = original.GetUpperBound(0);
            if (original.GetUpperBound(0) >= newCoNum || original.GetUpperBound(1) >= newRoNum)
            {
                var array = new T[newCoNum, newRoNum];
                for (var x = 0; x < newCoNum; x++)
                    for (var y = 0; y < newRoNum; y++)
                        array[x, y] = original[x, y];
            }
            else
            {
                for (var co = 0; co <= columns; co++)
                    Array.Copy(original, co * columnCount, newArray, co * columnCount2, columnCount);
            }
            return newArray;
        }

        private void Root_PreviewMouseMove(object sender, MouseEventArgs e)
        {
            var p = e.GetPosition(Root);
            var x = (int)(p.X / TileSize);
            var y = (int)(p.Y / TileSize);
            if (x > Map.GetUpperBound(0) || y > Map.GetUpperBound(1)) return;
            PointerOver?.Invoke(this, new Point(x, y));
        }
    }
}
