using Microsoft.Win32;
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;

namespace GraphDrawer
{
    /// <summary>
    /// Interaction logic for GraphByClick.xaml
    /// </summary>
    public partial class GraphByClick : Window
    {
        public GraphByClick()
        {
            InitializeComponent();

            VertexArray.vertexCount = 0;
        }

        public GraphByClick(int[,] matrix, bool state)
        {
            InitializeComponent();
            VertexArray.vertexCount = 0;

            ClearCanvas();
            if (state)
            {
                MessageBox.Show("asd");
                int length = (int)Math.Sqrt(matrix.Length);
                for(int i = 0; i < length; i++)
                    VertexArray.AddVertex(canvas, rand.Next(1, 600), rand.Next(1, 300));

                for(int i = 0; i < length; i++)
                {
                    var vertex1 = VertexArray.vertex[i];
                    for(int j = 0; j < length; j++)
                    {
                        var vertex2 = VertexArray.vertex[j];
                        if (matrix[i, j] == 1)
                        {
                            EdgeArray.edgeCount++;
                            Array.Resize(ref EdgeArray.edge, EdgeArray.edgeCount);
                            Array.Resize(ref EdgeArray.line, EdgeArray.edgeCount);
                            EdgeArray.line[EdgeArray.edgeCount - 1] = new Line()
                            {
                                Stroke = new SolidColorBrush(Color.FromRgb(0, 0, 0)),
                                StrokeThickness = 2,
                                X1 = vertex1.X + 5,
                                Y1 = vertex1.Y + 5,
                                X2 = vertex2.X + 5,
                                Y2 = vertex2.Y + 5
                            };

                            canvas.Children.Add(EdgeArray.line[EdgeArray.edgeCount - 1]);
                            EdgeArray.edge[EdgeArray.edgeCount - 1] = new Edge(EdgeArray.line[EdgeArray.edgeCount-1], vertex1, vertex2);
                        }
                    }
                }
            }
            else
            {
                int rows = matrix.GetLength(0);
                int cols = matrix.GetLength(1);
                Vertex buffer = null;

                for(int i = 0; i < rows; i++)
                {
                    VertexArray.AddVertex(canvas, rand.Next(1, 600), rand.Next(1, 300));
                }

                for(int j = 0; j < cols; j++)
                {
                    for(int i = 0; i < rows; i++)
                    {
                        if (matrix[i, j] == 1)
                        {
                            if (buffer == null)
                                buffer = VertexArray.vertex[i];
                            else
                            {
                                EdgeArray.AddEdge(canvas, buffer, VertexArray.vertex[i]);
                                buffer = null;
                            }
                        }
                    }
                }
            }
        }

        private void BackBtn_Click(object sender, RoutedEventArgs e) // Выбор режима рисования
        {
            ChoiceMode regime = new ChoiceMode();
            regime.Show();
            Close();
        }
        private void Canvas_MouseUp(object sender, MouseButtonEventArgs e)
        {
            
            var point = e.GetPosition(canvas); // Получение позиции курсора
            int x = Convert.ToInt32(point.X); // Перевод в координаты
            int y = Convert.ToInt32(point.Y);
            if (vertexRb.IsChecked == true)
            {
                if (GraphState.named)
                {
                    VertexArray.AddNamedVertex(canvas, x, y);
                }
                else
                {
                    VertexArray.AddVertex(canvas, x, y);
                }
            }
            if(edgeRb.IsChecked == true)
            {
                if (GraphState.focused)
                {
                    var point1 = e.GetPosition(canvas);
                    int X = Convert.ToInt32(point1.X);
                    int Y = Convert.ToInt32(point1.Y);
                    for (int i = 0; i <= VertexArray.vertexCount - 1; i++)// Проверка на принадлежность точки к какой-либо вершине
                    {
                        if (((X - VertexArray.vertex[i].X <= 15) && (X - VertexArray.vertex[i].X >= 0)) ||
                            ((VertexArray.vertex[i].X - X <= 15) && (VertexArray.vertex[i].X - X >= 0)))
                        {
                            if (((Y - VertexArray.vertex[i].Y <= 15) && (Y - VertexArray.vertex[i].Y >= 0)) ||
                            ((VertexArray.vertex[i].Y - Y <= 15) && (VertexArray.vertex[i].Y - Y >= 0)))
                            {
                                if (VertexArray.buffer[0] == null)
                                {
                                    VertexArray.buffer[0] = VertexArray.vertex[i];
                                }
                                else
                                {
                                    VertexArray.buffer[1] = VertexArray.vertex[i];
                                    ArrowedEdgeArray.AddArrowedEdge(canvas, VertexArray.buffer[0], VertexArray.buffer[1]);
                                    VertexArray.buffer[0] = null;
                                    VertexArray.buffer[1] = null;
                                }
                            }
                        }
                    } // Конец проверки
                }
                else
                {
                    var point1 = e.GetPosition(canvas);
                    int X = Convert.ToInt32(point1.X);
                    int Y = Convert.ToInt32(point1.Y);
                    for (int i = 0; i <= VertexArray.vertexCount - 1; i++)// Проверка на принадлежность точки к какой-либо вершине
                    {
                        if (((X - VertexArray.vertex[i].X <= 15) && (X - VertexArray.vertex[i].X >= 0)) ||
                            ((VertexArray.vertex[i].X - X <= 15) && (VertexArray.vertex[i].X - X >= 0)))
                        {
                            if (((Y - VertexArray.vertex[i].Y <= 15) && (Y - VertexArray.vertex[i].Y >= 0)) ||
                            ((VertexArray.vertex[i].Y - Y <= 15) && (VertexArray.vertex[i].Y - Y >= 0)))
                            {
                                if (VertexArray.buffer[0] == null)
                                {
                                    VertexArray.buffer[0] = VertexArray.vertex[i];
                                }
                                else
                                {
                                    VertexArray.buffer[1] = VertexArray.vertex[i];
                                    EdgeArray.AddEdge(canvas, VertexArray.buffer[0], VertexArray.buffer[1]);
                                    VertexArray.buffer[0] = null;
                                    VertexArray.buffer[1] = null;
                                }
                            }
                        }
                    } // Конец проверки
                }
            }
        }


        // Получение рандомной кисти из заданных цветов
        readonly Random rand = new Random((DateTime.Now.Millisecond * DateTime.Now.Second) % DateTime.Now.Hour);
        public SolidColorBrush GetBrush()
        {
            SolidColorBrush[] brush = new SolidColorBrush[10];
            brush[0] = new SolidColorBrush(Color.FromRgb(235, 64, 52));
            brush[1] = new SolidColorBrush(Color.FromRgb(235, 235, 52));
            brush[2] = new SolidColorBrush(Color.FromRgb(64, 235, 52));
            brush[3] = new SolidColorBrush(Color.FromRgb(52, 235, 229));
            brush[4] = new SolidColorBrush(Color.FromRgb(0, 13, 255));
            brush[5] = new SolidColorBrush(Color.FromRgb(140, 0, 255));
            brush[6] = new SolidColorBrush(Color.FromRgb(255, 0, 230));
            brush[7] = new SolidColorBrush(Color.FromRgb(255, 162, 0));
            brush[8] = new SolidColorBrush(Color.FromRgb(0, 0, 0));
            return brush[rand.Next(0, 8)];
        }


        // Очистка канваса
        private void ClearBtn_Click(object sender, RoutedEventArgs e)
        {
            ClearCanvas();
        }

        public void ClearCanvas()
        {
            canvas.Children.Clear();
            VertexArray.vertexCount = 0;
            EdgeArray.edgeCount = 0;
            Array.Clear(VertexArray.edge, 0, VertexArray.edge.Length);
            Array.Clear(VertexArray.ellipse, 0, VertexArray.ellipse.Length);
            Array.Clear(EdgeArray.edge, 0, EdgeArray.edge.Length);
            Array.Clear(EdgeArray.line, 0, EdgeArray.line.Length);
        }


        // Кнопки меню
        private void UnfocusedGraphBtn_Click(object sender, RoutedEventArgs e)
        {
            GraphState.focused = false;
        }

        private void FocusedGraphBtn_Click(object sender, RoutedEventArgs e)
        {
            GraphState.focused = true;
        }

        private void ExportPngBtn_Click(object sender, RoutedEventArgs e)
        {
            SaveFileDialog sfg = new SaveFileDialog
            {
                Filter = "PNG (*.png) | *.png"
            };
            sfg.ShowDialog();
            string filename = sfg.FileName;
            Rect rect = new Rect(canvas.Margin.Left, canvas.Margin.Top, canvas.ActualWidth, canvas.ActualHeight);

            double dpi = 96d;

            RenderTargetBitmap rtb = new RenderTargetBitmap((int)rect.Right, (int)rect.Bottom, dpi, dpi, System.Windows.Media.PixelFormats.Default);

            rtb.Render(canvas);

            BitmapEncoder pngEncoder = new PngBitmapEncoder();
            pngEncoder.Frames.Add(BitmapFrame.Create(rtb));

            try
            {
                System.IO.MemoryStream ms = new System.IO.MemoryStream();

                pngEncoder.Save(ms);
                ms.Close();

                System.IO.File.WriteAllBytes(filename, ms.ToArray());
            }
            catch (Exception err)
            {
                MessageBox.Show(err.ToString(), "Error", MessageBoxButton.OK, MessageBoxImage.Error);
            }
        }

        private void DelEdgeBtn_Click(object sender, RoutedEventArgs e)
        {
            for(int i = 0; i < EdgeArray.edgeCount; i++)
            {
                canvas.Children.Remove(EdgeArray.line[i]);
            }
            EdgeArray.edgeCount = 0;
            Array.Clear(EdgeArray.edge, 0, EdgeArray.edge.Length);
        }

        private void PrintBtn_Click(object sender, RoutedEventArgs e)
        {
            PrintDialog printDialog = new PrintDialog();
            printDialog.PrintVisual(canvas, "Your graph");
        }

        private void NamedGraphBtn_Click(object sender, RoutedEventArgs e)
        {
            GraphState.named = true;
        }

        private void UnnamedGraphBtn_Click(object sender, RoutedEventArgs e)
        {
            GraphState.named = false;
        }

        private void AdjacencyMatrix_Click(object sender, RoutedEventArgs e)
        {
            int length = VertexArray.vertex.Length;
            int[,] matrix = new int[length, length];
            for(int i = 0; i < VertexArray.vertex.Length; i++)
            {
                var vertex1 = VertexArray.vertex[i];
                for(int j = 0; j < VertexArray.vertex.Length; j++)
                {
                    if (i != j)
                    {
                        var vertex2 = VertexArray.vertex[j];
                        for (int k = 0; k < EdgeArray.edge.Length; k++)
                        {
                            var edge = EdgeArray.edge[k];
                            if (Vertex.Compare(edge.finishVertex, vertex1) && Vertex.Compare(edge.startVertex, vertex2))
                                matrix[i, j] = 1;
                            else if (Vertex.Compare(edge.startVertex, vertex1) && Vertex.Compare(edge.finishVertex, vertex2))
                                matrix[i, j] = 1;
                        }
                    }
                    else
                    {
                        matrix[i, j] = 0;
                    }
                }
            }

            for (int i = 0; i < length; i++)
                for (int j = 0; j < length; j++)
                    matrix[i, j] = matrix[j, i];

            MatrixOutput output = new MatrixOutput(matrix);
            output.Show();
        }

        private void IncidenceMatrix_Click(object sender, RoutedEventArgs e)
        {
            int rows = VertexArray.vertex.Length;
            int cols = EdgeArray.edge.Length;
            int[,] matrix = new int[rows, cols];
            for(int i = 0; i < rows; i++)
            {
                var vertex = VertexArray.vertex[i];

                for (int j = 0; j < cols; j++)
                {
                    var edge = EdgeArray.edge[j];
                    if (Vertex.Compare(vertex, edge.finishVertex) || Vertex.Compare(vertex, edge.startVertex))
                        matrix[i, j] = 1;
                    else
                        matrix[i, j] = 0;
                }
            }
            MatrixOutput output = new MatrixOutput(matrix);
            output.Show();

        }

        private void CreateGraphByMatrixBtn_Click(object sender, RoutedEventArgs e)
        {
            GraphByMatrix matrix = new GraphByMatrix();
            matrix.Show();
            Close();
        }
    }

    public class VertexArray
    {
        public static int vertexCount;
        public static Vertex[] vertex = new Vertex[vertexCount];
        public static Ellipse[] ellipse = new Ellipse[vertexCount];
        public static Edge[] edge = new Edge[vertexCount];
        public static Vertex[] buffer = new Vertex[2];
        public static Label[] label = new Label[vertexCount];

        public static int AddVertex(Canvas canvas, int x, int y)
        {

            vertexCount++;
            Array.Resize(ref vertex, vertexCount);
            Array.Resize(ref ellipse, vertexCount);
            vertex[vertexCount-1] = new Vertex(x, y);
            ellipse[vertexCount - 1] = new Ellipse
            {
                Height = 20,
                Width = 20,
                StrokeThickness = 2,
                Stroke = new SolidColorBrush(Color.FromRgb(0, 0, 0))
            };
            ellipse[vertexCount-1].Fill = ellipse[vertexCount-1].Stroke;
            Canvas.SetTop(ellipse[vertexCount-1], vertex[vertexCount-1].Y);
            Canvas.SetLeft(ellipse[vertexCount-1], vertex[vertexCount-1].X);
            canvas.Children.Add(ellipse[vertexCount-1]);
            return vertexCount-1;
        }

        public static int AddNamedVertex(Canvas canvas, int x, int y)
        {
            vertexCount++;
            Array.Resize(ref vertex, vertexCount);
            Array.Resize(ref ellipse, vertexCount);
            Array.Resize(ref label, vertexCount);
            vertex[vertexCount - 1] = new Vertex(x, y);
            label[vertexCount - 1] = new Label
            {
                Foreground = new SolidColorBrush(Color.FromRgb(0, 0, 0)),
                FontSize = 18
            };
            ellipse[vertexCount - 1] = new Ellipse
            {
                Height = 10,
                Width = 10,
                StrokeThickness = 2,
                Stroke = new SolidColorBrush(Color.FromRgb(0, 0, 0))
            };


            ellipse[vertexCount - 1].Fill = ellipse[vertexCount - 1].Stroke;
            label[vertexCount - 1].Content = vertexCount.ToString();
            Canvas.SetTop(ellipse[vertexCount - 1], vertex[vertexCount - 1].Y);
            Canvas.SetLeft(ellipse[vertexCount - 1], vertex[vertexCount - 1].X);
            canvas.Children.Add(ellipse[vertexCount - 1]);
            Canvas.SetTop(label[vertexCount - 1], vertex[vertexCount - 1].Y+5);
            Canvas.SetLeft(label[vertexCount - 1], vertex[vertexCount - 1].X-15);
            canvas.Children.Add(label[vertexCount-1]);
            return vertexCount - 1;
        }
    }

    public class EdgeArray
    {
        public static int edgeCount;
        public static Edge[] edge = new Edge[edgeCount];
        public static Line[] line = new Line[edgeCount];

        public static void AddEdge(Canvas canvas, Vertex v1, Vertex v2)
        {
            edgeCount++;
            Array.Resize(ref edge, edgeCount);
            Array.Resize(ref line, edgeCount);
            line[edgeCount-1] = new Line();
            edge[edgeCount-1] = new Edge(line[edgeCount-1], v1, v2);
            line[edgeCount - 1].Stroke = new SolidColorBrush(Color.FromRgb(0, 0, 0));
            line[edgeCount - 1].StrokeThickness = 2;
            line[edgeCount - 1].X1 = v1.X+10;
            line[edgeCount - 1].Y1 = v1.Y+10;
            line[edgeCount - 1].X2 = v2.X+10;
            line[edgeCount - 1].Y2 = v2.Y+10;
            canvas.Children.Add(line[edgeCount - 1]);
        }
    }

    public class ArrowedEdgeArray
    {
        public static ArrowLine[] line = new ArrowLine[EdgeArray.edgeCount];
        public static Edge[] edge = new Edge[EdgeArray.edgeCount];

        public static void AddArrowedEdge(Canvas canvas, Vertex v1, Vertex v2)
        {
            int edgeCount = EdgeArray.edgeCount;
            edgeCount++;
            Array.Resize(ref edge, edgeCount);
            Array.Resize(ref line, edgeCount);
            line[edgeCount - 1] = new ArrowLine();
            edge[edgeCount - 1] = new Edge(line[edgeCount - 1], v1, v2);
            line[edgeCount - 1].Stroke = new SolidColorBrush(Color.FromRgb(0, 0, 0));
            line[edgeCount - 1].StrokeThickness = 2;
            line[edgeCount - 1].X1 = v1.X + 5;
            line[edgeCount - 1].Y1 = v1.Y + 5;
            line[edgeCount - 1].X2 = v2.X + 5;
            line[edgeCount - 1].Y2 = v2.Y + 5;
            canvas.Children.Add(line[edgeCount - 1]);
            EdgeArray.edgeCount = edgeCount;
        }
    }

    
}
