//Open a open file dialog windowand then import the graph from the specified path using importer.
        //Deselect link, node, source, destination, then set source and destination from the loaded graph. Redraw panel.
        private void LoadGraphButton_Click(object sender, EventArgs e)
        {
            OpenFileDialog openFileDialog = new OpenFileDialog()
            {
                InitialDirectory = $"{Environment.CurrentDirectory}",
                Filter           = "XML (*.xml)|*.xml"
            };

            DialogResult dialogResult = openFileDialog.ShowDialog();

            if (dialogResult == DialogResult.OK)
            {
                string path = openFileDialog.FileName;

                this.graph = this.importer.Import(path, out this.currentMaxLayer);

                this.selectedNode = null;
                DeselectLink();
                this.source      = null;
                this.destination = null;

                if (this.graph.Source != null)
                {
                    this.source = new NodeDraw(this.graph.Source);
                }
                if (this.graph.Destination != null)
                {
                    this.destination = new NodeDraw(this.graph.Destination);
                }

                this.Visualization.Refresh();
            }

            openFileDialog.Dispose();
        }
        //Increases current max layer, calles AddNode method in graph, deselects node and link and redraws panel.
        private void AddNodeButton_Click(object sender, EventArgs e)
        {
            this.currentMaxLayer += 1;

            this.graph.AddNode(this.currentMaxLayer);

            this.selectedNode = null;
            DeselectLink();

            this.Visualization.Refresh();
        }
        public GraphCreator(IGraph graph, IExporter exporter, IImporter importer)
        {
            InitializeComponent();

            this.graph           = graph;
            this.exporter        = exporter;
            this.importer        = importer;
            this.selectedLink    = null;
            this.selectedNode    = null;
            this.currentMaxLayer = DEFAULT_CURRENT_MAX_LAYER;
            this.source          = null;
            this.destination     = null;
        }
        //If there is a selected node deselect destination if any. If selected node is the source deselect the source.
        //Set the destination to the selected node and redraw it in green.
        private void SetDestinationButton_Click(object sender, EventArgs e)
        {
            if (this.selectedNode != null)
            {
                if (this.destination != null && this.destination.Node != null)
                {
                    this.destination.Draw(this.Visualization.CreateGraphics(), Color.Black);
                }

                if (this.source != null && this.selectedNode.Node == this.source.Node)
                {
                    this.source       = null;
                    this.graph.Source = null;
                }

                this.destination       = this.selectedNode;
                this.graph.Destination = this.destination.Node;

                this.destination.Draw(this.Visualization.CreateGraphics(), Color.Green);
            }
        }
        //Check if inputed nodes both exist and are different and a link doesn't already exist between them.
        //If true call AddLink method in graph and redraw panel.
        private void AddLinkButton_Click(object sender, EventArgs e)
        {
            INode node1 = this.graph.Nodes.FirstOrDefault(n => n.NodeNumber == this.Node1NumericUpDown.Value);
            INode node2 = this.graph.Nodes.FirstOrDefault(n => n.NodeNumber == this.Node2NumericUpDown.Value);

            if (node1 != null && node2 != null && node1 != node2)
            {
                bool linkExists = node1.ConnectedLinks.Any(l =>
                                                           (l.ConnectedNodes.Item1 == node1 && l.ConnectedNodes.Item2 == node2) ||
                                                           (l.ConnectedNodes.Item2 == node1 && l.ConnectedNodes.Item1 == node2));

                if (!linkExists)
                {
                    this.graph.AddLink(node1, node2, (int)this.WeightNumericUpDown.Value);

                    this.selectedNode = null;
                    DeselectLink();

                    this.Visualization.Refresh();
                }
            }
        }
        //If a node is selected -> calles remove node method in graph.
        //Than resets source and destination and selected node if any, redraws panel.
        private void RemoveNodeButton_Click(object sender, EventArgs e)
        {
            if (this.selectedNode != null)
            {
                this.graph.RemoveNode(this.selectedNode.Node);

                if (this.source != null && this.selectedNode.Node == this.source.Node)
                {
                    this.graph.Source = null;
                    this.source       = null;
                }

                if (this.destination != null && this.selectedNode.Node == this.destination.Node)
                {
                    this.graph.Destination = null;
                    this.destination       = null;
                }

                this.selectedNode = null;

                this.Visualization.Refresh();
            }
        }
        //Get the inputed values for nodes and links. Delete the current graph.
        //Create random non overlaping nodes and add them to the new graph.
        //Create random non existant links with random weights between existing nodes and add them to the graph.
        //Than deselect everything and redraw the panel.
        private void GenerateRandomButton_Click(object sender, EventArgs e)
        {
            decimal nodesCount = this.RandomNodesUpDown.Value;
            decimal linksCount = this.RandomLinksUpDown.Value;

            int nodesInGraph = this.graph.Nodes.Count;

            for (int i = 0; i < nodesInGraph; i++)
            {
                this.graph.RemoveNode(this.graph.Nodes[0]);
            }

            Random random = new Random();

            decimal createdNodes = 0;

            while (createdNodes < nodesCount)
            {
                int randomX = random.Next((int)Node.NODE_SIZE, this.Visualization.Width - (int)Node.NODE_SIZE);
                int randomY = random.Next((int)Node.NODE_SIZE, this.Visualization.Height - (int)Node.NODE_SIZE);

                IPoint center = new Point(randomX, randomY);

                if (!this.graph.Nodes.Any(n => CheckDistanceBetweenCenters(center, n.Center)))
                {
                    this.currentMaxLayer += 1;

                    this.graph.AddNode(this.currentMaxLayer, center);

                    createdNodes += 1;
                }
            }

            decimal createdLinks = 0;

            while (createdLinks < linksCount)
            {
                int randomNode1 = random.Next(0, this.graph.Nodes.Count);
                int randomNode2 = random.Next(0, this.graph.Nodes.Count);

                if (randomNode1 == randomNode2)
                {
                    continue;
                }

                int weight = random.Next(MINIMUM_RANDOM_WEIGHT, MAXIMUM_RANDOM_WEIGHT);

                INode node1 = this.graph.Nodes[randomNode1];
                INode node2 = this.graph.Nodes[randomNode2];

                if (!node1.ConnectedLinks.Any(l => (l.ConnectedNodes.Item1 == node1 && l.ConnectedNodes.Item2 == node2) ||
                                              (l.ConnectedNodes.Item1 == node2 && l.ConnectedNodes.Item2 == node1)))
                {
                    this.graph.AddLink(node1, node2, weight);

                    createdLinks += 1;
                }
            }

            DeselectLink();
            this.selectedNode      = null;
            this.graph.Source      = null;
            this.graph.Destination = null;
            this.source            = null;
            this.destination       = null;

            this.Visualization.Refresh();
        }
        //If a mouse button is presed saves coordinates of cursor.
        //If its the left mouse button visually deselect link or node if any.
        //Than check if cursor is on any node.
        //If true than increase current layer, deselect link, set node to selected node change its layer and redraw it in red.
        //If false then check if currsor is on any link
        //If true then deselect node, set link as selected link, redraw it and set its values from input.
        //If cursor is not on any link or node then deselect currently selected node and link if any
        private void Visualization_MouseDown(object sender, MouseEventArgs e)
        {
            this.mouseDownXCoordinate = e.X;
            this.mouseDownYCoordinate = e.Y;

            if (e.Button == MouseButtons.Left)
            {
                IPoint cursorPosition = new Point(e.X, e.Y);

                if (this.selectedNode != null)
                {
                    if (this.source != null && this.selectedNode.Node == this.source.Node)
                    {
                        this.selectedNode.Draw(this.Visualization.CreateGraphics(), Color.Blue);
                    }
                    else if (this.destination != null && this.selectedNode.Node == this.destination.Node)
                    {
                        this.selectedNode.Draw(this.Visualization.CreateGraphics(), Color.Green);
                    }
                    else
                    {
                        this.selectedNode.Draw(this.Visualization.CreateGraphics(), Color.Black);
                    }
                }

                if (this.selectedLink != null)
                {
                    this.selectedLink.Draw(this.Visualization.CreateGraphics(), Color.Black);
                }

                bool cursorIsOnAnyLinkOrNode = false;

                foreach (INode node in this.graph.Nodes.OrderByDescending(n => n.Layer))
                {
                    bool isInsideNode = node.Contains(cursorPosition);

                    if (isInsideNode)
                    {
                        this.currentMaxLayer += 1;

                        this.selectedNode = new NodeDraw(node);
                        DeselectLink();

                        this.selectedNode.Node.ChangeCurrentLayer(this.currentMaxLayer);

                        this.selectedNode.Draw(this.Visualization.CreateGraphics(), Color.Red);

                        cursorIsOnAnyLinkOrNode = true;

                        break;
                    }
                }
                if (!cursorIsOnAnyLinkOrNode)
                {
                    foreach (INode node in this.graph.Nodes)
                    {
                        foreach (ILink link in node.ConnectedLinks)
                        {
                            bool isInsideLink = link.Contains(cursorPosition);

                            if (isInsideLink)
                            {
                                this.selectedLink = new LinkDraw(link);
                                this.selectedNode = null;

                                this.selectedLink.Draw(this.Visualization.CreateGraphics(), Color.Red);

                                this.Node1NumericUpDown.Value  = this.selectedLink.Link.ConnectedNodes.Item1.NodeNumber;
                                this.Node2NumericUpDown.Value  = this.selectedLink.Link.ConnectedNodes.Item2.NodeNumber;
                                this.WeightNumericUpDown.Value = this.selectedLink.Link.Weight;

                                cursorIsOnAnyLinkOrNode = true;

                                break;
                            }
                        }

                        if (cursorIsOnAnyLinkOrNode)
                        {
                            break;
                        }
                    }
                }

                if (!cursorIsOnAnyLinkOrNode)
                {
                    this.selectedNode = null;
                    DeselectLink();
                }
            }
        }