Click here to Skip to main content
15,891,621 members
Articles / Programming Languages / XML

DotNetMQ: A Complete Message Queue System for .NET

Rate me:
Please Sign up or sign in to vote.
4.94/5 (190 votes)
23 May 2011LGPL331 min read 1.1M   53.8K   489  
A new and independent Open Source Message Queue system that is entirely built in C# and .NET framework 3.5.
/*
DotNetMQ - A Complete Message Broker For .NET
Copyright (C) 2011 Halil ibrahim KALKAN

This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 */

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Windows.Forms;
using log4net;
using MDS.Communication;
using MDS.Communication.Messages.ControllerMessages;
using MDS.Exceptions;
using MDS.GUI;

namespace MDS.Management.GUI.MDSServers
{
    /// <summary>
    /// This form is used to design Server graph of MDS.
    /// </summary>
    public partial class ServerGraphForm : Form
    {
        #region Private properties

        /// <summary>
        /// Reference to logger.
        /// </summary>
        private static readonly ILog Logger = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);

        /// <summary>
        /// Reference to MDSController object.
        /// All communication with MDS server is performed using this object.
        /// </summary>
        private readonly MDSController _controller;

        /// <summary>
        /// Reference to this MDS server on graph.
        /// </summary>
        private MDSServer _thisServer;

        /// <summary>
        /// All MDS servers on graph.
        /// </summary>
        private readonly List<MDSServer> _servers;

        /// <summary>
        /// Stores all graph information that are gotten from MDS server.
        /// </summary>
        private ServerGraphInfo _serverGraphInfo;

        #region Designing fields

        /// <summary>
        /// This is the first clicked label to create a link between servers
        /// </summary>
        private Label _selectedLabel;

        /// <summary>
        /// X coordinate of mouse in selected label.
        /// </summary>
        private int _movingLabelOffsetX;

        /// <summary>
        /// Y coordinate of mouse in selected label.
        /// </summary>
        private int _movingLabelOffsetY;

        /// <summary>
        /// X coordinate of label that is guiding for replacement to _movingLabel.
        /// </summary>
        private int _movingLabelGuideLabelX = -1;

        /// <summary>
        /// Y coordinate of label that is guiding for replacement to _movingLabel.
        /// </summary>
        private int _movingLabelGuideLabelY = -1;

        /// <summary>
        /// X coordinate of moouse at the last click in the design area.
        /// It is used to find initial location when adding new server.
        /// </summary>
        private int _designPanelLastX = -1;

        /// <summary>
        /// Y coordinate of moouse at the last click in the design area.
        /// It is used to find initial location when adding new server.
        /// </summary>
        private int _designPanelLastY = -1;

        #endregion

        #region Drawing fields

        /// <summary>
        /// This pen is used to draw lines between servers.
        /// </summary>
        private readonly Pen _linePen;

        /// <summary>
        /// This pen is used to draw lines when moving a label for guide lines.
        /// </summary>
        private readonly Pen _guideLinePen;

        /// <summary>
        /// This pen is used to select (to draw a outer rectangle to) a server label.
        /// </summary>
        private readonly Pen _labelSelectingPen;

        /// <summary>
        /// Background color of label of this server on graph.
        /// </summary>
        private readonly Color _thisServerBackColor;

        /// <summary>
        /// Background color of label of all servers on graph except this server.
        /// </summary>
        private readonly Color _serverBackColor;

        #endregion

        #endregion

        #region Constructor

        /// <summary>
        /// Creates a new ServerGraphForm.
        /// </summary>
        /// <param name="controller">Reference to MDSController object</param>
        public ServerGraphForm(MDSController controller)
        {
            _controller = controller;
            _servers = new List<MDSServer>();
            _linePen = new Pen(Brushes.Black, 1.0f);
            _guideLinePen = new Pen(Color.LightGray, 1.0f);
            _labelSelectingPen = new Pen(Color.Black, 1.0f) { DashStyle = DashStyle.DashDot };
            _thisServerBackColor = Color.Crimson;
            _serverBackColor = Color.DodgerBlue;
            InitializeComponent();
        }

        #endregion

        #region Form events

        private void ServerGraphForm_Load(object sender, EventArgs e)
        {
            try
            {
                PrepareForm();
                GetGraphFromServer();
            }
            catch (Exception ex)
            {
                MessageBox.Show("Can not load graph. " + ex.Message);
                Close();
            }
        }
        
        private void btnSaveGraph_Click(object sender, EventArgs e)
        {
            btnSaveGraph.Enabled = false;
            Application.DoEvents();

            try
            {
                CheckGraph();
                _serverGraphInfo = CreateServerGraphInfo();
                
                //Send message to the server and get response
                var message = _controller.SendMessageAndGetResponse(
                    new UpdateServerGraphMessage {ServerGraph = _serverGraphInfo}
                    );

                //Check response message
                if (message.MessageTypeId != ControlMessageFactory.MessageTypeIdOperationResultMessage)
                {
                    throw new MDSException("Response message to UpdateServerGraphMessage must be a OperationResultMessage");
                }

                var updateResponseMessage = message as OperationResultMessage;
                if (updateResponseMessage == null)
                {
                    throw new MDSException("Incorrect message type. MessageTypeId = " + message.MessageTypeId + ", but Type of object: " + message.GetType().Name);
                }

                //Inform user about update result
                if (updateResponseMessage.Success)
                {
                    MDSGuiHelper.ShowInfoDialog("Server graph is successfully updated on server", "Success.");
                }
                else
                {
                    MDSGuiHelper.ShowErrorMessage(
                        "Server graph can not be updated on server. Reason: " + updateResponseMessage.ResultMessage,
                        "Failed!");
                }
            }
            catch (Exception ex)
            {
                MDSGuiHelper.ShowWarningMessage("Can not save graph. " + ex.Message);
            }
            finally
            {
                btnSaveGraph.Enabled = true;                
            }
        }

        private void ServerGraphForm_Resize(object sender, EventArgs e)
        {
            pnlDesign.Width = Width - 24;
            pnlDesign.Height = Height - 82;
            btnSaveGraph.Left = pnlDesign.Right - 200;
            btnSaveGraph.Top = pnlDesign.Bottom + 5;
        }

        private void ServerLabel_MouseDown(object sender, MouseEventArgs e)
        {
            var currentLabel = sender as Label;
            if (currentLabel == null)
            {
                return;
            }

            if (e.Button == MouseButtons.Left)
            {
                if (((ModifierKeys & Keys.Control) == Keys.Control) && (_selectedLabel != null))
                {
                    LinkOrUnlinkServers(_selectedLabel, currentLabel);
                }

                currentLabel.BackColor = Color.Black;
                _movingLabelOffsetX = e.X;
                _movingLabelOffsetY = e.Y;
            }

            _selectedLabel = currentLabel;
            pnlDesign.Invalidate();
        }

        private void ServerLabel_MouseMove(object sender, MouseEventArgs e)
        {
            if ((_selectedLabel != null) && (e.Button == MouseButtons.Left))
            {
                //Find normal X and Y ccordinate of mouse
                var labelX = e.X + _selectedLabel.Left - _movingLabelOffsetX;
                var labelY = e.Y + _selectedLabel.Top - _movingLabelOffsetY;

                //If Alt key is not pressed and there is a label whose coordinates are (5 pixel) close to this label's, than
                //hold server label, else move label...
                _movingLabelGuideLabelX = ((ModifierKeys & Keys.Alt) == Keys.Alt) ? int.MinValue : FindGuideLabelX(labelX);
                _selectedLabel.Left = (_movingLabelGuideLabelX > int.MinValue) ? _movingLabelGuideLabelX : labelX;
                _movingLabelGuideLabelY = ((ModifierKeys & Keys.Alt) == Keys.Alt) ? int.MinValue : FindGuideLabelY(labelY);
                _selectedLabel.Top = (_movingLabelGuideLabelY > int.MinValue) ? _movingLabelGuideLabelY : labelY;

                pnlDesign.Invalidate();
            }
        }

        private void ServerLabel_MouseUp(object sender, MouseEventArgs e)
        {
            if (_selectedLabel != null && e.Button == MouseButtons.Left)
            {
                _selectedLabel.BackColor = (_thisServer != null && _selectedLabel == _thisServer.LabelOfServer)
                                               ? _thisServerBackColor
                                               : _serverBackColor;
                _movingLabelGuideLabelX = int.MinValue;
                _movingLabelGuideLabelY = int.MinValue;
                pnlDesign.Invalidate();
            }
        }

        private void DesignPanel_MouseDown(object sender, MouseEventArgs e)
        {
            _designPanelLastX = e.X;
            _designPanelLastY = e.Y;

            if (_selectedLabel == null)
            {
                return;
            }

            _selectedLabel = null;
            pnlDesign.Invalidate();
        }

        private void ServerLabel_MouseDoubleClick(object sender, MouseEventArgs e)
        {
            ServerRightMenu_ServerProperties_Click(sender, e);
        }

        private void DesignPanel_Paint(object sender, PaintEventArgs e)
        {
            DrawAllLines(e.Graphics);
        }
        
        private void ServerRightMenu_RemoveServer_Click(object sender, EventArgs e)
        {
            var removingServer = GetSelectedServer();
            if (removingServer == null)
            {
                return;
            }

            if (removingServer.ServerInfo.Name == _thisServer.ServerInfo.Name)
            {
                MDSGuiHelper.ShowWarningMessage("You can not remove this server from graph!", "Attention!");
                return;
            }

            var dialogResult = MDSGuiHelper.ShowQuestionDialog(
                "Are you sure to remove MDS Server " + removingServer.ServerInfo.Name + " (" +
                removingServer.ServerInfo.IpAddress + ") from graph.", "Confirm removing server!");
            if (dialogResult != DialogResult.Yes)
            {
                return;
            }

            foreach (var adjacent in removingServer.Adjacents)
            {
                if (adjacent.Adjacents.Contains(removingServer))
                {
                    adjacent.Adjacents.Remove(removingServer);
                }
            }

            _servers.Remove(removingServer);
            pnlDesign.Controls.Remove(removingServer.LabelOfServer);
            _selectedLabel = null;

            pnlDesign.Invalidate();
        }
        
        private void ServerRightMenu_SetAsThisServer_Click(object sender, EventArgs e)
        {
            var newThisServer = GetSelectedServer();
            if (newThisServer == null || newThisServer == _thisServer)
            {
                return;
            }

            if (_thisServer != null)
            {
                _thisServer.LabelOfServer.BackColor = _serverBackColor;
            }

            _thisServer = newThisServer;
            _thisServer.LabelOfServer.BackColor = _thisServerBackColor;
        }

        private void ServerRightMenu_ServerProperties_Click(object sender, EventArgs e)
        {
            var editingServer = GetSelectedServer();
            if (editingServer == null)
            {
                return;
            }

            var editServerForm = new EditServerForm(editingServer.ServerInfo, false);
            editServerForm.ShowDialog();
            if (!editServerForm.Updated)
            {
                return;
            }

            editingServer.LabelOfServer.Text = editingServer.ServerInfo.Name + Environment.NewLine + editingServer.ServerInfo.IpAddress;
            pnlDesign.Invalidate();
        }
        
        private void DesignArea_AddNewServer_Click(object sender, EventArgs e)
        {
            var newServer = new MDSServer
                                    {
                                        ServerInfo =
                                            new ServerGraphInfo.ServerOnGraph
                                                {
                                                    Name = "",
                                                    IpAddress = "",
                                                    Port = CommunicationConsts.DefaultMDSPort,
                                                    Adjacents = "",
                                                    Location = _designPanelLastX + "," + _designPanelLastY,
                                                }
                                    };

            var addServerForm = new EditServerForm(newServer.ServerInfo, true);
            addServerForm.ShowDialog();
            if (!addServerForm.Updated)
            {
                return;
            }

            newServer.LabelOfServer = CreateServerLabel(newServer);
            newServer.LabelOfServer.Text = newServer.ServerInfo.Name + Environment.NewLine + newServer.ServerInfo.IpAddress;
            newServer.LabelOfServer.Left = _designPanelLastX;
            newServer.LabelOfServer.Top = _designPanelLastY;
            _servers.Add(newServer);
            pnlDesign.Invalidate();
        }

        #endregion

        #region Private methods

        private void PrepareForm()
        {
            Left = (Screen.GetWorkingArea(this).Width - Width) / 2;
            Top = (Screen.GetWorkingArea(this).Height - Height) / 2;
        }

        /// <summary>
        /// Gets server graph from server and creates graph on screen.
        /// </summary>
        private void GetGraphFromServer()
        {
            try
            {
                //Send a message to MDS server to get list of client applications, get response and fill data grid.
                var message = _controller.SendMessageAndGetResponse(new GetServerGraphMessage());
                if (message.MessageTypeId != ControlMessageFactory.MessageTypeIdGetServerGraphResponseMessage)
                {
                    throw new MDSException("Response message to GetServerGraphMessage must be a GetServerGraphResponseMessage");
                }

                var serverGraphResponseMessage = message as GetServerGraphResponseMessage;
                if (serverGraphResponseMessage == null)
                {
                    throw new MDSException("Incorrect message type. MessageTypeId = " + message.MessageTypeId + ", but Type of object: " + message.GetType().Name);
                }

                _serverGraphInfo = serverGraphResponseMessage.ServerGraph;
                CreateGraph();
            }
            catch (Exception ex)
            {
                Logger.Error(ex.Message, ex);
                MDSGuiHelper.ShowErrorMessage("Application list can not received from MDS Server. Detail: " + ex.Message);
            }
        }

        /// <summary>
        /// Creates graph on design area from _serverGraphInfo.
        /// </summary>
        private void CreateGraph()
        {
            //Create MDSServerNode objects and get names of adjacents of nodes
            var adjacentsOfServers = new SortedList<string, string>();
            foreach (var server in _serverGraphInfo.Servers)
            {
                var mdsServer = new MDSServer
                {
                    ServerInfo = server,
                };
                _servers.Add(mdsServer);
                adjacentsOfServers.Add(server.Name, server.Adjacents);
                if (server.Name == _serverGraphInfo.ThisServerName)
                {
                    _thisServer = mdsServer;
                }
            }

            //Set Adjacent servers
            foreach (var mdsServer in _servers)
            {
                //Get adjacent names
                var adjacents = adjacentsOfServers[mdsServer.ServerInfo.Name].Split(',');
                //Add nodes as adjacent
                foreach (var adjacent in adjacents)
                {
                    var trimmedAdjacentName = adjacent.Trim();
                    if (string.IsNullOrEmpty(trimmedAdjacentName))
                    {
                        continue;
                    }

                    var adjacentServer = FindServer(trimmedAdjacentName);
                    if (adjacentServer == null)
                    {
                        continue;
                    }

                    mdsServer.Adjacents.Add(adjacentServer);
                }
            }

            //Create labels for servers
            foreach (var server in _servers)
            {
                server.LabelOfServer = CreateServerLabel(server);
            }

            //Set design properties
            foreach (var server in _serverGraphInfo.Servers)
            {
                var mdsServer = FindServer(server.Name);
                if (mdsServer == null)
                {
                    continue;
                }

                var splittedLocation = server.Location.Split(new[] { ',', ';' });
                mdsServer.LabelOfServer.Left = Convert.ToInt32(splittedLocation[0]);
                mdsServer.LabelOfServer.Top = Convert.ToInt32(splittedLocation[1]);
            }
        }

        /// <summary>
        /// Checks graph if it is a valid graph.
        /// </summary>
        private void CheckGraph()
        {
            //Check if This Server is defined
            if (_thisServer == null || FindServer(_thisServer.ServerInfo.Name) == null)
            {
                throw new MDSException("This server is not defined in the graph.");
            }

            //Return, if there is no server except this server
            if (_servers.Count == 1)
            {
                return;
            }

            //Check if there is an unconnected server exist on graph
            foreach (var server in _servers)
            {
                if (server.Adjacents.Count <= 0)
                {
                    throw new MDSException("MDS Server '" + server.ServerInfo.Name + "' has no connection to other servers on graph.");
                }

                if (!IsThereAPath(_thisServer, server, new List<MDSServer>()))
                {
                    throw new MDSException("There is no path from this MDS server (" +
                                           _thisServer.ServerInfo.Name + ") to '" + server.ServerInfo.Name + "'.");
                }
            }
        }
        
        /// <summary>
        /// Prepares ServerGraphInfo object from graph on screen.
        /// </summary>
        /// <returns>ServerGraphInfo object</returns>
        private ServerGraphInfo CreateServerGraphInfo()
        {
            var graphInfo = new ServerGraphInfo
                                {
                                    ThisServerName = _thisServer.ServerInfo.Name,
                                    Servers = new ServerGraphInfo.ServerOnGraph[_servers.Count]
                                };
            for (var i = 0; i < _servers.Count; i++)
            {
                graphInfo.Servers[i] =
                    new ServerGraphInfo.ServerOnGraph
                        {
                            Name = _servers[i].ServerInfo.Name,
                            IpAddress = _servers[i].ServerInfo.IpAddress,
                            Port = _servers[i].ServerInfo.Port,
                            Location = _servers[i].LabelOfServer.Left + "," + _servers[i].LabelOfServer.Top,
                            Adjacents = GetAdjacentListAsString(_servers[i])
                        };
            }

            return graphInfo;
        }

        /// <summary>
        /// Creates a comma delimited string list from adjacent names of given server.
        /// </summary>
        /// <param name="server">Server to get adjacent list</param>
        /// <returns>Adjacent list as string</returns>
        private static string GetAdjacentListAsString(MDSServer server)
        {
            var adjacentList = new StringBuilder();
            for (var i = 0; i < server.Adjacents.Count; i++)
            {
                if (i > 0)
                {
                    adjacentList.Append(",");
                }

                adjacentList.Append(server.Adjacents[i].ServerInfo.Name);
            }

            return adjacentList.ToString();
        }

        /// <summary>
        /// Checks if there is a path from a MDS server to another.
        /// I runs as recursive and searches all nodes to find a path from source to destination.
        /// </summary>
        /// <param name="sourceServer">Source server of path</param>
        /// <param name="destServer">Destination server of path</param>
        /// <param name="passedServers">List of all passed servers until now</param>
        /// <returns>True, if there is a path</returns>
        private static bool IsThereAPath(MDSServer sourceServer, MDSServer destServer, ICollection<MDSServer> passedServers)
        {
            if (passedServers.Contains(sourceServer))
            {
                return false;
            }

            if (sourceServer.Adjacents.Contains(destServer))
            {
                return true;
            }

            passedServers.Add(sourceServer);
            
            foreach (var adjacent in sourceServer.Adjacents)
            {
                if(IsThereAPath(adjacent, destServer, passedServers))
                {
                    return true;
                }
            }

            return false;
        }

        /// <summary>
        /// Finds a server in Servers list by name.
        /// </summary>
        /// <param name="name">Name of server</param>
        /// <returns>Found server or null if can not find</returns>
        private MDSServer FindServer(string name)
        {
            foreach (var server in _servers)
            {
                if (server.ServerInfo.Name == name)
                {
                    return server;
                }
            }

            return null;
        }

        /// <summary>
        /// Finds a server in Servers list by Label.
        /// </summary>
        /// <param name="label">Label of server</param>
        /// <returns>Found server or null if can not find</returns>
        private MDSServer FindServer(Label label)
        {
            foreach (var server in _servers)
            {
                if (server.LabelOfServer == label)
                {
                    return server;
                }
            }

            return null;
        }

        /// <summary>
        /// Creates a label for a server.
        /// </summary>
        /// <param name="server">Server</param>
        /// <returns>Label</returns>
        private Label CreateServerLabel(MDSServer server)
        {
            var label = new Label
            {
                BackColor = Color.DodgerBlue,
                BorderStyle = BorderStyle.FixedSingle,
                Font = new Font("Verdana", 9.75F, FontStyle.Bold, GraphicsUnit.Point, 162),
                ForeColor = Color.White,
                Location = new Point(1, 1),
                Name = "lbl" + server.ServerInfo.Name,
                Size = new Size(180, 40),
                TabIndex = 1,
                Text = server.ServerInfo.Name + Environment.NewLine + server.ServerInfo.IpAddress,
                TextAlign = ContentAlignment.MiddleCenter
            };

            if (server == _thisServer)
            {
                label.BackColor = Color.Crimson;
            }

            label.ContextMenuStrip = cmsServerRightMenu;
            label.MouseDown += ServerLabel_MouseDown;
            label.MouseUp += ServerLabel_MouseUp;
            label.MouseMove += ServerLabel_MouseMove;
            label.MouseDoubleClick += ServerLabel_MouseDoubleClick;

            pnlDesign.Controls.Add(label);

            return label;
        }

        /// <summary>
        /// Searches all labels if any label's left value is 5 pixel close to given x value.
        /// </summary>
        /// <param name="x">x value to search</param>
        /// <returns>int.MinValue: No label found, >int.MinValue: Left value of found label</returns>
        private int FindGuideLabelX(int x)
        {
            foreach (var mdsServer in _servers)
            {
                if (mdsServer.LabelOfServer == _selectedLabel)
                {
                    continue;
                }

                if (Math.Abs(mdsServer.LabelOfServer.Left - x) < 6)
                {
                    return mdsServer.LabelOfServer.Left;
                }
            }

            return int.MinValue;
        }

        /// <summary>
        /// Searches all labels if any label's Top value is 5 pixel close to given y value.
        /// </summary>
        /// <param name="y">y value to search</param>
        /// <returns>int.MinValue: No label found, >int.MinValue: Top value of found label</returns>
        private int FindGuideLabelY(int y)
        {
            foreach (var mdsServer in _servers)
            {
                if (mdsServer.LabelOfServer == _selectedLabel)
                {
                    continue;
                }

                if (Math.Abs(mdsServer.LabelOfServer.Top - y) < 6)
                {
                    return mdsServer.LabelOfServer.Top;
                }
            }

            return int.MinValue;
        }

        /// <summary>
        /// Links two servers if they are not linked, else unlink them.
        /// </summary>
        /// <param name="firstServerLabel">Label of first server</param>
        /// <param name="secondServerLabel">Label of second server</param>
        private void LinkOrUnlinkServers(Label firstServerLabel, Label secondServerLabel)
        {
            if (firstServerLabel == secondServerLabel)
            {
                return;
            }

            var firstServer = FindServer(firstServerLabel);
            var secondServer = FindServer(secondServerLabel);
            if (firstServer == null || secondServer == null)
            {
                return;
            }

            if (firstServer.Adjacents.Contains(secondServer))
            {
                firstServer.Adjacents.Remove(secondServer);
                if (secondServer.Adjacents.Contains(firstServer))
                {
                    secondServer.Adjacents.Remove(firstServer);
                }
            }
            else
            {
                firstServer.Adjacents.Add(secondServer);
                if (!secondServer.Adjacents.Contains(firstServer))
                {
                    secondServer.Adjacents.Add(firstServer);
                }
            }
        }
        
        /// <summary>
        /// Draws all lines between adjacent servers.
        /// </summary>
        private void DrawAllLines(Graphics graphics)
        {
            if (_servers == null)
            {
                return;
            }

            graphics.SmoothingMode = SmoothingMode.AntiAlias;

            if (_selectedLabel != null && _movingLabelGuideLabelX >= 0)
            {
                graphics.DrawLine(_guideLinePen, _selectedLabel.Left, 0, _selectedLabel.Left, pnlDesign.Height);
                graphics.DrawLine(_guideLinePen, _selectedLabel.Right, 0, _selectedLabel.Right, pnlDesign.Height);
            }

            if (_selectedLabel != null && _movingLabelGuideLabelY >= 0)
            {
                graphics.DrawLine(_guideLinePen, 0, _selectedLabel.Top, pnlDesign.Width, _selectedLabel.Top);
                graphics.DrawLine(_guideLinePen, 0, _selectedLabel.Bottom, pnlDesign.Width, _selectedLabel.Bottom);
            }

            if (_selectedLabel != null)
            {
                graphics.DrawRectangle(
                    _labelSelectingPen,
                    _selectedLabel.Left - 4,
                    _selectedLabel.Top - 4,
                    _selectedLabel.Width + 7,
                    _selectedLabel.Height + 7
                    );
            }

            var passedServers = new List<MDSServer>();
            foreach (var server in _servers)
            {
                passedServers.Add(server);
                foreach (var adjacent in server.Adjacents)
                {
                    if (passedServers.Contains(adjacent))
                    {
                        continue;
                    }

                    graphics.DrawLine(
                        _linePen,
                        server.LabelOfServer.Location.X + server.LabelOfServer.Width / 2,
                        server.LabelOfServer.Location.Y + server.LabelOfServer.Height / 2,
                        adjacent.LabelOfServer.Location.X + adjacent.LabelOfServer.Width / 2,
                        adjacent.LabelOfServer.Location.Y + adjacent.LabelOfServer.Height / 2
                        );
                }
            }
        }
        
        /// <summary>
        /// Finds selected server on design area.
        /// </summary>
        /// <returns>Selected server or null if not selected any server</returns>
        private MDSServer GetSelectedServer()
        {
            return (_selectedLabel == null) ? null : FindServer(_selectedLabel);
        }

        #endregion

        #region Sub classes

        /// <summary>
        /// Represents a MDS server on design area.
        /// </summary>
        private class MDSServer
        {
            /// <summary>
            /// Reference to ServerGraphInfo.ServerOnGraph associated with this MDSServer object.
            /// </summary>
            public ServerGraphInfo.ServerOnGraph ServerInfo { get; set; }

            /// <summary>
            /// List of adjacent servers of MDS server.
            /// </summary>
            public List<MDSServer> Adjacents { get; private set; }

            /// <summary>
            /// Label that represents server on ServerGraphForm form.
            /// </summary>
            public Label LabelOfServer { get; set; }

            /// <summary>
            /// Creates a new MDSServer object.
            /// </summary>
            public MDSServer()
            {
                Adjacents = new List<MDSServer>();
            }
        }
       
        #endregion
    }
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The GNU Lesser General Public License (LGPLv3)


Written By
Founder Volosoft
Turkey Turkey
I have started programming at 14 years old using Pascal as hobby. Then I interested in web development (HTML, JavaScript, ASP...) before university.

I graduated from Sakarya University Computer Engineering. At university, I learned C++, Visual Basic.NET, C#, ASP.NET and Java. I partly implemented ARP, IP and TCP protocols in Java as my final term project.

Now, I am working on Windows and web based software development mostly using Microsoft technologies in my own company.

My open source projects:

* ABP Framework: https://abp.io
* jTable: http://jtable.org
* Others: https://github.com/hikalkan

My personal web site:

https://halilibrahimkalkan.com

Comments and Discussions