public DraggedLinkElement(ProductionGraphViewer parent, NodeElement startNode, LinkType startConnectionType, Item item)
			: base(parent)
		{
			if (startConnectionType == LinkType.Input)
			{
				ConsumerElement = startNode;
			}
			else
			{
				SupplierElement = startNode;
			}
			StartConnectionType = startConnectionType;
			Item = item;
			if ((Control.MouseButtons & MouseButtons.Left) != 0)
			{
				DragType = DragType.MouseDown;
			}
			else
			{
				DragType = DragType.MouseUp;
			}
		}
		public void DeleteNode(NodeElement node)
		{
			if (node != null)
			{
				foreach (NodeLink link in node.DisplayedNode.InputLinks.ToList().Union(node.DisplayedNode.OutputLinks.ToList()))
				{
					Elements.RemoveWhere(le => le is LinkElement && (le as LinkElement).DisplayedLink == link);
				}
				Elements.Remove(node);
				node.DisplayedNode.Destroy();
				UpdateNodes();
				Invalidate();
			}			
		}
		private void EndDrag(Point location)
		{
			if (SupplierElement != null && ConsumerElement != null)
			{
				if (StartConnectionType == LinkType.Input)
				{
					NodeLink.Create(SupplierElement.DisplayedNode, ConsumerElement.DisplayedNode, Item, ConsumerElement.DisplayedNode.GetUnsatisfiedDemand(Item));
				}
				else
				{
					NodeLink.Create(SupplierElement.DisplayedNode, ConsumerElement.DisplayedNode, Item, SupplierElement.DisplayedNode.GetExcessOutput(Item));
				}
			}
			else if (StartConnectionType == LinkType.Output && ConsumerElement == null)
			{
				using (var form = new RecipeChooserForm(DataCache.Recipes.Values.Where(r => r.Ingredients.Keys.Contains(Item)), new List<Item> { Item }, "Create output node", "Use recipe {0}"))
				{
					var result = form.ShowDialog();
					if (result == DialogResult.OK)
					{
						NodeElement newElement = null;
						if (form.selectedRecipe != null)
						{
							newElement = new NodeElement(RecipeNode.Create(form.selectedRecipe, Parent.Graph), Parent);
						}
						else if (form.selectedItem != null)
						{
							newElement = new NodeElement(ConsumerNode.Create(form.selectedItem, Parent.Graph), Parent);
						}
						newElement.Update();
						newElement.Location = Point.Add(location, new Size(-newElement.Width / 2, -newElement.Height / 2));
						new LinkElement(Parent, NodeLink.Create(SupplierElement.DisplayedNode, newElement.DisplayedNode, Item));
					}
				}
			}
			else if (StartConnectionType == LinkType.Input && SupplierElement == null)
			{
				using (var form = new RecipeChooserForm(DataCache.Recipes.Values.Where(r => r.Results.Keys.Contains(Item)), new List<Item> { Item }, "Create infinite supply node", "Use recipe {0}"))
				{
					var result = form.ShowDialog();
					if (result == DialogResult.OK)
					{
						NodeElement newElement = null;
						if (form.selectedRecipe != null)
						{
							newElement = new NodeElement(RecipeNode.Create(form.selectedRecipe, Parent.Graph), Parent);
						}
						else if (form.selectedItem != null)
						{
							newElement = new NodeElement(SupplyNode.Create(form.selectedItem, Parent.Graph), Parent);
						}
						newElement.Update();
						newElement.Location = Point.Add(location, new Size(-newElement.Width / 2, -newElement.Height / 2));
						new LinkElement(Parent, NodeLink.Create(newElement.DisplayedNode, ConsumerElement.DisplayedNode, Item));
					}
				}
			}

			Parent.AddRemoveElements();
			Parent.UpdateNodes();
			Dispose();
		}
        public void PositionNodes()
        {
            if (!Elements.Any())
            {
                return;
            }
            var nodeOrder = Graph.GetTopologicalSort();

            nodeOrder.Reverse();

            List <ProductionNode>[] nodePositions = new List <ProductionNode> [nodeOrder.Count()];
            for (int i = 0; i < nodePositions.Count(); i++)
            {
                nodePositions[i] = new List <ProductionNode>();
            }

            nodePositions.First().AddRange(nodeOrder.OfType <ConsumerNode>());
            foreach (RecipeNode node in nodeOrder.OfType <RecipeNode>())
            {
                bool PositionFound = false;

                for (int i = nodePositions.Count() - 1; i >= 0 && !PositionFound; i--)
                {
                    foreach (ProductionNode listNode in nodePositions[i])
                    {
                        if (listNode.CanUltimatelyTakeFrom(node))
                        {
                            nodePositions[i + 1].Add(node);
                            PositionFound = true;
                            break;
                        }
                    }
                }

                if (!PositionFound)
                {
                    nodePositions.First().Add(node);
                }
            }
            nodePositions.Last().AddRange(nodeOrder.OfType <SupplyNode>());

            int marginX = 100;
            int marginY = 200;
            int y       = marginY;

            int[] tierWidths = new int[nodePositions.Count()];
            for (int i = 0; i < nodePositions.Count(); i++)
            {
                var list      = nodePositions[i];
                int maxHeight = 0;
                int x         = marginX;

                foreach (var node in list)
                {
                    NodeElement control = GetElementForNode(node);
                    control.X = x;
                    control.Y = y;

                    x        += control.Width + marginX;
                    maxHeight = Math.Max(control.Height, maxHeight);
                }

                if (maxHeight > 0)                 // Don't add any height for empty tiers
                {
                    y += maxHeight + marginY;
                }

                tierWidths[i] = x;
            }

            int centrePoint = tierWidths.Last(i => i > marginX) / 2;

            for (int i = tierWidths.Count() - 1; i >= 0; i--)
            {
                int offset = centrePoint - tierWidths[i] / 2;

                foreach (var node in nodePositions[i])
                {
                    NodeElement element = GetElementForNode(node);
                    element.X = element.X + offset;
                }
            }

            UpdateNodes();
            LimitViewToBounds();
            Invalidate(true);
        }