Example #1
0
        /// <summary>
        /// Parses a single line of a scenario file.
        /// </summary>
        /// <param name="Parts">List of tokens of the line being parsed.</param>
        /// <param name="LineNumber">Line number of the line being parsed.</param>
        /// <returns>Initialized command object.</returns>
        public static Command ParseCommand(string[] Parts, int LineNumber)
        {
            log.Trace("(Parse:'{0}',LineNumber:{1})", string.Join(" ", Parts), LineNumber);

            Command     res = null;
            CommandType commandType;

            if (!Enum.TryParse(Parts[0], out commandType))
            {
                commandType = CommandType.Unknown;
            }

            int    paramCount = Parts.Length - 1;
            int    p          = 1;
            string line       = string.Join(" ", Parts);

            switch (commandType)
            {
            case CommandType.ProfileServer:
            {
                if (paramCount != 6)
                {
                    log.Error("ProfileServer requires 6 parameters, but {0} parameters found on line {1}.", paramCount, LineNumber);
                    break;
                }

                CommandProfileServer command = new CommandProfileServer(LineNumber, line)
                {
                    GroupName = Parts[p++],
                    Count     = int.Parse(Parts[p++]),
                    BasePort  = int.Parse(Parts[p++]),
                    Latitude  = decimal.Parse(Parts[p++], CultureInfo.InvariantCulture),
                    Longitude = decimal.Parse(Parts[p++], CultureInfo.InvariantCulture),
                    Radius    = int.Parse(Parts[p++])
                };

                bool countValid = (1 <= command.Count) && (command.Count <= 999);
                if (!countValid)
                {
                    log.Error("Count '{0}' on line {1} is invalid. It must be an integer between 1 and 999.", command.Count, LineNumber);
                    break;
                }

                int  basePortUpperLimit = 65535 - 20 * command.Count;
                bool basePortValid      = (1 <= command.BasePort) && (command.BasePort <= basePortUpperLimit);
                if (!basePortValid)
                {
                    log.Error("Having Count {0}, BasePort '{1}' on line {2} is invalid. It must be an integer between 1 and {3}.", command.Count, command.BasePort, LineNumber, basePortUpperLimit);
                    break;
                }

                bool latitudeValid = new GpsLocation(command.Latitude, 0).IsValid();
                if (!latitudeValid)
                {
                    log.Error("Latitude '{0}' on line {1} is invalid. It must be a decimal number between -90 and 90.", command.Latitude, LineNumber);
                    break;
                }

                bool longitudeValid = new GpsLocation(0, command.Longitude).IsValid();
                if (!longitudeValid)
                {
                    log.Error("Longitude '{0}' on line {1}. It must be a decimal number between -179.999999 and 180.", command.Longitude, LineNumber);
                    break;
                }

                bool radiusValid = (0 <= command.Radius) && (command.Radius <= MaxRadius);
                if (!radiusValid)
                {
                    log.Error("Radius '{0}' given on line {1}. It must be an integer between 0 and {2}.", command.Radius, LineNumber, MaxRadius);
                    break;
                }

                res = command;
                break;
            }


            case CommandType.StartServer:
            {
                if (paramCount != 3)
                {
                    log.Error("StartServer requires 3 parameters, but {0} parameters found on line {1}.", paramCount, LineNumber);
                    break;
                }

                CommandStartServer command = new CommandStartServer(LineNumber, line)
                {
                    PsGroup = Parts[p++],
                    PsIndex = int.Parse(Parts[p++]),
                    PsCount = int.Parse(Parts[p++])
                };

                bool psIndexValid = (1 <= command.PsIndex) && (command.PsIndex <= 999);
                if (!psIndexValid)
                {
                    log.Error("PsIndex '{0}' on line {1} is invalid. It must be an integer between 1 and 999.", command.PsIndex, LineNumber);
                    break;
                }

                bool psCountValid = (1 <= command.PsCount) && (command.PsCount <= 999);
                if (!psCountValid)
                {
                    log.Error("PsCount '{0}' on line {1} is invalid. It must be an integer between 1 and 999.", command.PsCount, LineNumber);
                    break;
                }

                psCountValid = command.PsIndex + command.PsCount <= 999;
                if (!psCountValid)
                {
                    log.Error("Having PsIndex '{0}', PsCount '{1}' on line {2} is invalid. PsIndex + PsCount must not be greater than 999.", command.PsIndex, command.PsCount, LineNumber);
                    break;
                }

                res = command;
                break;
            }

            case CommandType.StopServer:
            {
                if (paramCount != 3)
                {
                    log.Error("StopServer requires 3 parameters, but {0} parameters found on line {1}.", paramCount, LineNumber);
                    break;
                }

                CommandStopServer command = new CommandStopServer(LineNumber, line)
                {
                    PsGroup = Parts[p++],
                    PsIndex = int.Parse(Parts[p++]),
                    PsCount = int.Parse(Parts[p++])
                };

                bool psIndexValid = (1 <= command.PsIndex) && (command.PsIndex <= 999);
                if (!psIndexValid)
                {
                    log.Error("PsIndex '{0}' on line {1} is invalid. It must be an integer between 1 and 999.", command.PsIndex, LineNumber);
                    break;
                }

                bool psCountValid = (1 <= command.PsCount) && (command.PsCount <= 999);
                if (!psCountValid)
                {
                    log.Error("PsCount '{0}' on line {1} is invalid. It must be an integer between 1 and 999.", command.PsCount, LineNumber);
                    break;
                }

                psCountValid = command.PsIndex + command.PsCount <= 999;
                if (!psCountValid)
                {
                    log.Error("Having PsIndex '{0}', PsCount '{1}' on line {2} is invalid. PsIndex + PsCount must not be greater than 999.", command.PsIndex, command.PsCount, LineNumber);
                    break;
                }

                res = command;
                break;
            }

            case CommandType.Neighborhood:
            {
                if ((paramCount % 3) != 0)
                {
                    log.Error("Neighborhood requires 3*N parameters, but {0} parameters found on line {1}.", paramCount, LineNumber);
                    break;
                }

                CommandNeighborhood command = new CommandNeighborhood(LineNumber, line)
                {
                    PsGroups  = new List <string>(),
                    PsIndexes = new List <int>(),
                    PsCounts  = new List <int>()
                };

                for (int i = 0; i < paramCount; i += 3)
                {
                    command.PsGroups.Add(Parts[p++]);
                    command.PsIndexes.Add(int.Parse(Parts[p++]));
                    command.PsCounts.Add(int.Parse(Parts[p++]));

                    int groupNo    = (i / 3) + 1;
                    int groupIndex = groupNo - 1;

                    bool indexValid = (1 <= command.PsIndexes[groupIndex]) && (command.PsIndexes[groupIndex] <= 999);
                    if (!indexValid)
                    {
                        log.Error("PsIndex${0} '{1}' on line {2} is invalid. It must be an integer between 1 and 999.", groupNo, command.PsIndexes[groupIndex], LineNumber);
                        break;
                    }

                    bool countValid = (1 <= command.PsCounts[groupIndex]) && (command.PsCounts[groupIndex] <= 999);
                    if (!countValid)
                    {
                        log.Error("PsCount${0} '{1}' on line {2} is invalid. It must be an integer between 1 and 999.", groupNo, command.PsCounts[groupIndex], LineNumber);
                        break;
                    }

                    countValid = command.PsIndexes[groupIndex] + command.PsCounts[groupIndex] <= 999;
                    if (!countValid)
                    {
                        log.Error("Having PsIndex${0} '{1}', PsCount{0} '{2}' on line {3} is invalid. PsIndex$i + PsCount$i must not be greater than 999.", groupNo, command.PsIndexes[groupIndex], command.PsCounts[groupIndex], LineNumber);
                        break;
                    }
                }

                res = command;
                break;
            }

            case CommandType.CancelNeighborhood:
            {
                if ((paramCount % 3) != 0)
                {
                    log.Error("CancelNeighborhood requires 3*N parameters, but {0} parameters found on line {1}.", paramCount, LineNumber);
                    break;
                }

                CommandCancelNeighborhood command = new CommandCancelNeighborhood(LineNumber, line)
                {
                    PsGroups  = new List <string>(),
                    PsIndexes = new List <int>(),
                    PsCounts  = new List <int>()
                };

                for (int i = 0; i < paramCount; i += 3)
                {
                    command.PsGroups.Add(Parts[p++]);
                    command.PsIndexes.Add(int.Parse(Parts[p++]));
                    command.PsCounts.Add(int.Parse(Parts[p++]));

                    int groupNo = (i / 3) + 1;

                    bool indexValid = (1 <= command.PsIndexes[i]) && (command.PsIndexes[i] <= 999);
                    if (!indexValid)
                    {
                        log.Error("PsIndex${0} '{1}' on line {2} is invalid. It must be an integer between 1 and 999.", groupNo, command.PsIndexes[i], LineNumber);
                        break;
                    }

                    bool countValid = (1 <= command.PsCounts[i]) && (command.PsCounts[i] <= 999);
                    if (!countValid)
                    {
                        log.Error("PsCount${0} '{1}' on line {2} is invalid. It must be an integer between 1 and 999.", groupNo, command.PsCounts[i], LineNumber);
                        break;
                    }

                    countValid = command.PsIndexes[i] + command.PsCounts[i] <= 999;
                    if (!countValid)
                    {
                        log.Error("Having PsIndex${0} '{1}', PsCount{0} '{2}' on line {3} is invalid. PsIndex$i + PsCount$i must not be greater than 999.", groupNo, command.PsIndexes[i], command.PsCounts[i], LineNumber);
                        break;
                    }
                }

                res = command;
                break;
            }

            case CommandType.Neighbor:
            {
                if (paramCount < 2)
                {
                    log.Error("Neighbor requires 2 or more parameters, but {0} parameters found on line {1}.", paramCount, LineNumber);
                    break;
                }

                CommandNeighbor command = new CommandNeighbor(LineNumber, line)
                {
                    Source  = Parts[p++],
                    Targets = new List <string>()
                };

                for (int i = 0; i < paramCount - 1; i++)
                {
                    command.Targets.Add(Parts[p++]);
                }

                res = command;
                break;
            }

            case CommandType.CancelNeighbor:
            {
                if (paramCount < 2)
                {
                    log.Error("CancelNeighbor requires 2 or more parameters, but {0} parameters found on line {1}.", paramCount, LineNumber);
                    break;
                }

                CommandCancelNeighbor command = new CommandCancelNeighbor(LineNumber, line)
                {
                    Source  = Parts[p++],
                    Targets = new List <string>()
                };

                for (int i = 0; i < paramCount - 1; i++)
                {
                    command.Targets.Add(Parts[p++]);
                }

                res = command;
                break;
            }

            case CommandType.Identity:
            {
                if (paramCount != 11)
                {
                    log.Error("Neighbor requires 11 parameters, but {0} parameters found on line {1}.", paramCount, LineNumber);
                    break;
                }

                CommandIdentity command = new CommandIdentity(LineNumber, line)
                {
                    Name         = Parts[p++],
                    Count        = int.Parse(Parts[p++]),
                    IdentityType = Parts[p++],
                    Latitude     = decimal.Parse(Parts[p++], CultureInfo.InvariantCulture),
                    Longitude    = decimal.Parse(Parts[p++], CultureInfo.InvariantCulture),
                    Radius       = int.Parse(Parts[p++]),
                    ImageMask    = Parts[p++],
                    ImageChance  = int.Parse(Parts[p++]),
                    PsGroup      = Parts[p++],
                    PsIndex      = int.Parse(Parts[p++]),
                    PsCount      = int.Parse(Parts[p++])
                };


                bool countValid = (1 <= command.Count) && (command.Count <= 99999);
                if (!countValid)
                {
                    log.Error("Count '{0}' on line {1} is invalid. It must be an integer between 1 and 99999.", command.Count, LineNumber);
                    break;
                }

                bool latitudeValid = new GpsLocation(command.Latitude, 0).IsValid();
                if (!latitudeValid)
                {
                    log.Error("Latitude '{0}' on line {1} is invalid. It must be a decimal number between -90 and 90.", command.Latitude, LineNumber);
                    break;
                }

                bool longitudeValid = new GpsLocation(0, command.Longitude).IsValid();
                if (!longitudeValid)
                {
                    log.Error("Longitude '{0}' on line {1}. It must be a decimal number between -179.999999 and 180.", command.Longitude, LineNumber);
                    break;
                }

                bool radiusValid = (0 <= command.Radius) && (command.Radius <= MaxRadius);
                if (!radiusValid)
                {
                    log.Error("Radius '{0}' given on line {1}. It must be an integer between 0 and {2}.", command.Radius, LineNumber, MaxRadius);
                    break;
                }

                bool imageChance = (0 <= command.ImageChance) && (command.ImageChance <= 100);
                if (!imageChance)
                {
                    log.Error("ImageChance '{0}' on line {1} is invalid. It must be an integer between 0 and 100.", command.ImageChance, LineNumber);
                    break;
                }

                bool psIndexValid = (1 <= command.PsIndex) && (command.PsIndex <= 999);
                if (!psIndexValid)
                {
                    log.Error("PsIndex '{0}' on line {1} is invalid. It must be an integer between 1 and 999.", command.PsIndex, LineNumber);
                    break;
                }

                bool psCountValid = (1 <= command.PsCount) && (command.PsCount <= 999);
                if (!psCountValid)
                {
                    log.Error("PsCount '{0}' on line {1} is invalid. It must be an integer between 1 and 999.", command.PsCount, LineNumber);
                    break;
                }

                psCountValid = command.PsIndex + command.PsCount <= 999;
                if (!psCountValid)
                {
                    log.Error("Having PsIndex '{0}', PsCount '{1}' on line {2} is invalid. PsIndex + PsCount must not be greater than 999.", command.PsIndex, command.PsCount, LineNumber);
                    break;
                }

                countValid = command.Count - command.PsCount * 20000 <= 0;
                if (!countValid)
                {
                    log.Error("Having PsCount '{0}', Count '{1}' on line {2} is invalid. Count / PsCount must not be greater than 20000.", command.PsCount, command.Count, LineNumber);
                    break;
                }

                res = command;
                break;
            }

            case CommandType.CancelIdentity:
            {
                if (paramCount != 3)
                {
                    log.Error("CancelIdentity requires 3 parameters, but {0} parameters found on line {1}.", paramCount, LineNumber);
                    break;
                }

                CommandCancelIdentity command = new CommandCancelIdentity(LineNumber, line)
                {
                    Name  = Parts[p++],
                    Index = int.Parse(Parts[p++]),
                    Count = int.Parse(Parts[p++])
                };

                bool indexValid = (1 <= command.Index) && (command.Index <= 99999);
                if (!indexValid)
                {
                    log.Error("Index '{0}' on line {1} is invalid. It must be an integer between 1 and 99999.", command.Index, LineNumber);
                    break;
                }

                bool countValid = (1 <= command.Count) && (command.Count <= 99999);
                if (!countValid)
                {
                    log.Error("Count '{0}' on line {1} is invalid. It must be an integer between 1 and 99999.", command.Count, LineNumber);
                    break;
                }

                countValid = command.Index + command.Count <= 99999;
                if (!countValid)
                {
                    log.Error("Having Index '{0}', Count '{1}' on line {2} is invalid. Index + Count must not be greater than 99999.", command.Index, command.Count, LineNumber);
                    break;
                }

                res = command;
                break;
            }

            case CommandType.TestQuery:
            {
                if (paramCount != 9)
                {
                    log.Error("TestQuery requires 9 parameters, but {0} parameters found on line {1}.", paramCount, LineNumber);
                    break;
                }

                int    li     = p + 6;
                string latStr = Parts[li++];
                string lonStr = Parts[li++];
                string radStr = Parts[li++];

                decimal latitude  = GpsLocation.NoLocation.Latitude;
                decimal longitude = GpsLocation.NoLocation.Longitude;
                int     radius    = 0;

                bool noLocation = latStr == "NO_LOCATION";
                if (!noLocation)
                {
                    latitude  = decimal.Parse(latStr, CultureInfo.InvariantCulture);
                    longitude = decimal.Parse(lonStr, CultureInfo.InvariantCulture);
                    radius    = int.Parse(radStr);
                }

                CommandTestQuery command = new CommandTestQuery(LineNumber, line)
                {
                    PsGroup       = Parts[p++],
                    PsIndex       = int.Parse(Parts[p++]),
                    PsCount       = int.Parse(Parts[p++]),
                    NameFilter    = Parts[p++],
                    TypeFilter    = Parts[p++],
                    IncludeImages = bool.Parse(Parts[p++]),
                    Latitude      = latitude,
                    Longitude     = longitude,
                    Radius        = radius
                };


                bool psIndexValid = (1 <= command.PsIndex) && (command.PsIndex <= 999);
                if (!psIndexValid)
                {
                    log.Error("PsIndex '{0}' on line {1} is invalid. It must be an integer between 1 and 999.", command.PsIndex, LineNumber);
                    break;
                }

                bool psCountValid = (1 <= command.PsCount) && (command.PsCount <= 999);
                if (!psCountValid)
                {
                    log.Error("PsCount '{0}' on line {1} is invalid. It must be an integer between 1 and 999.", command.PsCount, LineNumber);
                    break;
                }

                psCountValid = command.PsIndex + command.PsCount <= 999;
                if (!psCountValid)
                {
                    log.Error("Having PsIndex '{0}', PsCount '{1}' on line {2} is invalid. PsIndex + PsCount must not be greater than 999.", command.PsIndex, command.PsCount, LineNumber);
                    break;
                }

                if (!noLocation)
                {
                    bool latitudeValid = new GpsLocation(command.Latitude, 0).IsValid();
                    if (!latitudeValid)
                    {
                        log.Error("Latitude '{0}' on line {1} is invalid. It must be a decimal number between -90 and 90.", command.Latitude, LineNumber);
                        break;
                    }

                    bool longitudeValid = new GpsLocation(0, command.Longitude).IsValid();
                    if (!longitudeValid)
                    {
                        log.Error("Longitude '{0}' on line {1}. It must be a decimal number between -179.999999 and 180.", command.Longitude, LineNumber);
                        break;
                    }

                    bool radiusValid = (0 <= command.Radius) && (command.Radius <= MaxRadius);
                    if (!radiusValid)
                    {
                        log.Error("Radius '{0}' given on line {1}. It must be an integer between 0 and {2}.", command.Radius, LineNumber, MaxRadius);
                        break;
                    }
                }

                res = command;
                break;
            }

            case CommandType.Delay:
            {
                if (paramCount != 1)
                {
                    log.Error("Delay requires 1 parameter, but {0} parameters found on line {1}.", paramCount, LineNumber);
                    break;
                }

                CommandDelay command = new CommandDelay(LineNumber, line)
                {
                    Seconds = decimal.Parse(Parts[p++], CultureInfo.InvariantCulture)
                };


                bool secondsValid = command.Seconds > 0;
                if (!secondsValid)
                {
                    log.Error("Seconds '{0}' on line {1} is invalid. It must be a positive decimal number.", command.Seconds);
                    break;
                }

                res = command;
                break;
            }


            case CommandType.TakeSnapshot:
            {
                if (paramCount != 1)
                {
                    log.Error("TakeSnapshot requires 1 parameter, but {0} parameters found on line {1}.", paramCount, LineNumber);
                    break;
                }

                CommandTakeSnapshot command = new CommandTakeSnapshot(LineNumber, line)
                {
                    Name = Parts[p++]
                };


                res = command;
                break;
            }


            case CommandType.LoadSnapshot:
            {
                if (paramCount != 1)
                {
                    log.Error("LoadSnapshot requires 1 parameter, but {0} parameters found on line {1}.", paramCount, LineNumber);
                    break;
                }

                CommandLoadSnapshot command = new CommandLoadSnapshot(LineNumber, line)
                {
                    Name = Parts[p++]
                };


                res = command;
                break;
            }

            case CommandType.DebugMode:
            {
                if (paramCount != 1)
                {
                    log.Error("DebugMode requires 1 parameter, but {0} parameters found on line {1}.", paramCount, LineNumber);
                    break;
                }

                string           enable  = Parts[p++].ToLowerInvariant();
                CommandDebugMode command = new CommandDebugMode(LineNumber, line)
                {
                    Enable = enable == "on"
                };

                bool enableValid = (enable == "on") || (enable == "off");
                if (!enableValid)
                {
                    log.Error("Enable on line {0} is invalid. It must be either 'on' or 'off'.", enable);
                    break;
                }


                res = command;
                break;
            }

            default:
                log.Error("Invalid command '{0}' on line number {1}.", Parts[0], LineNumber);
                break;
            }


            log.Trace("(-):{0}", res != null ? "Command" : "null");
            return(res);
        }
        /// <summary>
        /// Executes all commands.
        /// </summary>
        /// <returns>true if the function succeeds and all the commands are executed successfully, false otherwise.</returns>
        public bool Execute()
        {
            log.Trace("()");

            bool res = false;

            log.Info("Cleaning old history.");

            if (!ClearHistory())
            {
                log.Error("Unable to clear history, please make sure the access to the instance folder is not blocked by other process.");
                log.Trace("(-):{0}", res);
                return(res);
            }
            log.Info("");

            int  index = 1;
            bool error = false;

            foreach (Command command in commands)
            {
                log.Info("Executing #{0:0000}@l{1}: {2}", index, command.LineNumber, command.OriginalCommand);

                switch (command.Type)
                {
                case CommandType.ProfileServer:
                {
                    CommandProfileServer cmd = (CommandProfileServer)command;
                    for (int i = 1; i <= cmd.Count; i++)
                    {
                        string        name          = GetInstanceName(cmd.GroupName, i);
                        GpsLocation   location      = Helpers.GenerateRandomGpsLocation(cmd.Latitude, cmd.Longitude, cmd.Radius);
                        int           basePort      = cmd.BasePort + 20 * (i - 1);
                        ProfileServer profileServer = new ProfileServer(name, location, basePort);
                        if (profileServer.Initialize())
                        {
                            profileServers.Add(name, profileServer);
                        }
                        else
                        {
                            log.Error("  * Initialization of profile server '{0}' failed.", profileServer.Name);
                            error = true;
                            break;
                        }
                    }

                    if (!error)
                    {
                        log.Info("  * {0} profile servers created.", cmd.Count);
                    }
                    break;
                }

                case CommandType.StartServer:
                {
                    CommandStartServer cmd = (CommandStartServer)command;
                    for (int i = 0; i < cmd.PsCount; i++)
                    {
                        string        name = GetInstanceName(cmd.PsGroup, cmd.PsIndex + i);
                        ProfileServer profileServer;
                        if (profileServers.TryGetValue(name, out profileServer))
                        {
                            if (!profileServer.Start())
                            {
                                log.Error("  * Unable to start server instance '{0}'.", name);
                                error = true;
                                break;
                            }
                        }
                        else
                        {
                            log.Error("  * Profile server instance '{0}' does not exist.", name);
                            error = true;
                            break;
                        }
                    }

                    if (!error)
                    {
                        log.Info("  * {0} profile servers started.", cmd.PsCount);
                    }
                    break;
                }

                case CommandType.StopServer:
                {
                    CommandStopServer cmd = (CommandStopServer)command;
                    for (int i = 0; i < cmd.PsCount; i++)
                    {
                        string        name = GetInstanceName(cmd.PsGroup, cmd.PsIndex + i);
                        ProfileServer profileServer;
                        if (profileServers.TryGetValue(name, out profileServer))
                        {
                            if (!profileServer.Stop())
                            {
                                log.Error("  * Unable to stop server instance '{0}'.", name);
                                error = true;
                            }
                        }
                        else
                        {
                            log.Error("  * Profile server instance '{0}' does not exist.", name);
                            error = true;
                            break;
                        }
                    }

                    if (!error)
                    {
                        log.Info("  * {0} profile servers stopped.", cmd.PsCount);
                    }
                    break;
                }

                case CommandType.Identity:
                {
                    CommandIdentity cmd = (CommandIdentity)command;

                    List <ProfileServer> availableServers = new List <ProfileServer>();
                    int availableSlots = 0;
                    for (int i = 0; i < cmd.PsCount; i++)
                    {
                        string        name = GetInstanceName(cmd.PsGroup, cmd.PsIndex + i);
                        ProfileServer profileServer;
                        if (profileServers.TryGetValue(name, out profileServer))
                        {
                            availableServers.Add(profileServer);
                            availableSlots += profileServer.AvailableIdentitySlots;
                        }
                        else
                        {
                            log.Error("  * Profile server instance '{0}' does not exist.", name);
                            error = true;
                            break;
                        }
                    }

                    if (error)
                    {
                        break;
                    }


                    if (availableSlots < cmd.Count)
                    {
                        log.Error("  * Total number of available identity slots in selected servers is {0}, but {1} slots are required.", availableSlots, cmd.Count);
                        error = true;
                        break;
                    }


                    for (int i = 1; i <= cmd.Count; i++)
                    {
                        string name = GetIdentityName(cmd.Name, i);

                        int           serverIndex   = Helpers.Rng.Next(availableServers.Count);
                        ProfileServer profileServer = availableServers[serverIndex];

                        GpsLocation    location       = Helpers.GenerateRandomGpsLocation(cmd.Latitude, cmd.Longitude, cmd.Radius);
                        IdentityClient identityClient = null;
                        try
                        {
                            identityClient = new IdentityClient(name, cmd.IdentityType, location, cmd.ImageMask, cmd.ImageChance);
                            identityClients.Add(name, identityClient);
                        }
                        catch
                        {
                            log.Error("Unable to create identity '{0}'.", name);
                            error = true;
                            break;
                        }

                        Task <bool> initTask = identityClient.InitializeProfileHosting(profileServer);
                        if (initTask.Result)
                        {
                            profileServer.AddIdentityClient(identityClient);
                            if (profileServer.AvailableIdentitySlots == 0)
                            {
                                availableServers.RemoveAt(serverIndex);
                            }
                        }
                        else
                        {
                            log.Error("Unable to register profile hosting and initialize profile of identity '{0}' on server '{1}'.", name, profileServer.Name);
                            error = true;
                            break;
                        }
                    }

                    if (!error)
                    {
                        log.Info("  * {0} identities created and initialized on {1} servers.", cmd.Count, cmd.PsCount);
                    }
                    break;
                }

                case CommandType.CancelIdentity:
                {
                    CommandCancelIdentity cmd = (CommandCancelIdentity)command;

                    List <IdentityClient> clients = new List <IdentityClient>();
                    for (int i = 0; i < cmd.Count; i++)
                    {
                        string         name = GetIdentityName(cmd.Name, cmd.Index + i);
                        IdentityClient identityClient;
                        if (identityClients.TryGetValue(name, out identityClient))
                        {
                            clients.Add(identityClient);
                        }
                        else
                        {
                            log.Error("  * Identity name '{0}' does not exist.", name);
                            error = true;
                            break;
                        }
                    }

                    if (error)
                    {
                        break;
                    }


                    foreach (IdentityClient client in clients)
                    {
                        Task <bool> cancelTask = client.CancelProfileHosting();
                        if (!cancelTask.Result)
                        {
                            log.Error("Unable to cancel profile hosting agreement of identity '{0}' on server '{1}'.", client.Name, client.ProfileServer.Name);
                            error = true;
                        }
                    }

                    if (!error)
                    {
                        log.Info("  * {0} identities cancelled their hosting agreement.", clients.Count);
                    }

                    break;
                }

                case CommandType.Neighborhood:
                {
                    CommandNeighborhood cmd = (CommandNeighborhood)command;

                    List <ProfileServer> neighborhoodList = new List <ProfileServer>();
                    for (int i = 0; i < cmd.PsGroups.Count; i++)
                    {
                        string psGroup = cmd.PsGroups[i];
                        int    psCount = cmd.PsCounts[i];
                        int    psIndex = cmd.PsIndexes[i];
                        for (int j = 0; j < psCount; j++)
                        {
                            string name = GetInstanceName(psGroup, psIndex + j);

                            ProfileServer profileServer;
                            if (profileServers.TryGetValue(name, out profileServer))
                            {
                                neighborhoodList.Add(profileServer);
                            }
                            else
                            {
                                log.Error("  * Profile server instance '{0}' does not exist.", name);
                                error = true;
                                break;
                            }
                        }
                    }

                    if (!error)
                    {
                        foreach (ProfileServer ps in neighborhoodList)
                        {
                            if (!ps.LocServer.AddNeighborhood(neighborhoodList))
                            {
                                log.Error("  * Unable to add neighbors to server '{0}'.", ps.Name);
                                error = true;
                                break;
                            }
                        }

                        if (!error)
                        {
                            log.Info("  * Neighborhood of {0} profile servers has been established.", neighborhoodList.Count);
                        }
                    }
                    break;
                }

                case CommandType.CancelNeighborhood:
                {
                    CommandCancelNeighborhood cmd = (CommandCancelNeighborhood)command;

                    List <ProfileServer> neighborhoodList = new List <ProfileServer>();
                    for (int i = 0; i < cmd.PsGroups.Count; i++)
                    {
                        string psGroup = cmd.PsGroups[i];
                        int    psCount = cmd.PsCounts[i];
                        int    psIndex = cmd.PsIndexes[i];
                        for (int j = 0; j < psCount; j++)
                        {
                            string name = GetInstanceName(psGroup, psIndex + j);

                            ProfileServer profileServer;
                            if (profileServers.TryGetValue(name, out profileServer))
                            {
                                neighborhoodList.Add(profileServer);
                            }
                            else
                            {
                                log.Error("  * Profile server instance '{0}' does not exist.", name);
                                error = true;
                                break;
                            }
                        }
                    }

                    if (!error)
                    {
                        foreach (ProfileServer ps in neighborhoodList)
                        {
                            if (!ps.LocServer.CancelNeighborhood(neighborhoodList))
                            {
                                log.Error("  * Unable to add neighbors to server '{0}'.", ps.Name);
                                error = true;
                                break;
                            }
                        }

                        if (!error)
                        {
                            log.Info("  * Neighbor relations among {0} profile servers have been cancelled.", neighborhoodList.Count);
                        }
                    }
                    break;
                }

                case CommandType.Neighbor:
                {
                    CommandNeighbor cmd = (CommandNeighbor)command;

                    ProfileServer profileServer;
                    if (profileServers.TryGetValue(cmd.Source, out profileServer))
                    {
                        List <ProfileServer> neighborhoodList = new List <ProfileServer>();
                        for (int i = 0; i < cmd.Targets.Count; i++)
                        {
                            string        name = cmd.Targets[i];
                            ProfileServer target;
                            if (profileServers.TryGetValue(name, out target))
                            {
                                neighborhoodList.Add(target);
                            }
                            else
                            {
                                log.Error("  * Profile server instance '{0}' does not exist.", name);
                                error = true;
                                break;
                            }
                        }


                        if (!error)
                        {
                            if (profileServer.LocServer.AddNeighborhood(neighborhoodList))
                            {
                                log.Info("  * {0} servers have been added to the neighborhood of server '{1}'.", neighborhoodList.Count, profileServer.Name);
                            }
                            else
                            {
                                log.Error("  * Unable to add neighbors to server '{0}'.", profileServer.Name);
                                error = true;
                                break;
                            }
                        }
                    }
                    else
                    {
                        log.Error("  * Profile server instance '{0}' does not exist.", cmd.Source);
                        error = true;
                        break;
                    }

                    break;
                }

                case CommandType.CancelNeighbor:
                {
                    CommandCancelNeighbor cmd = (CommandCancelNeighbor)command;

                    ProfileServer profileServer;
                    if (profileServers.TryGetValue(cmd.Source, out profileServer))
                    {
                        List <ProfileServer> neighborhoodList = new List <ProfileServer>();
                        for (int i = 0; i < cmd.Targets.Count; i++)
                        {
                            string        name = cmd.Targets[i];
                            ProfileServer target;
                            if (profileServers.TryGetValue(name, out target))
                            {
                                neighborhoodList.Add(target);
                            }
                            else
                            {
                                log.Error("  * Profile server instance '{0}' does not exist.", name);
                                error = true;
                                break;
                            }
                        }


                        if (!error)
                        {
                            if (profileServer.LocServer.CancelNeighborhood(neighborhoodList))
                            {
                                log.Info("  * {0} servers have been removed from the neighborhood of server '{1}'.", neighborhoodList.Count, profileServer.Name);
                            }
                            else
                            {
                                log.Error("  * Unable to remove neighbors from neighborhood of server '{0}'.", profileServer.Name);
                                error = true;
                                break;
                            }
                        }
                    }
                    else
                    {
                        log.Error("  * Profile server instance '{0}' does not exist.", cmd.Source);
                        error = true;
                        break;
                    }

                    break;
                }


                case CommandType.TestQuery:
                {
                    CommandTestQuery cmd = (CommandTestQuery)command;

                    List <ProfileServer> targetServers = new List <ProfileServer>();
                    for (int i = 0; i < cmd.PsCount; i++)
                    {
                        string        name = GetInstanceName(cmd.PsGroup, cmd.PsIndex + i);
                        ProfileServer profileServer;
                        if (profileServers.TryGetValue(name, out profileServer))
                        {
                            targetServers.Add(profileServer);
                        }
                        else
                        {
                            log.Error("  * Profile server instance '{0}' does not exist.", name);
                            error = true;
                            break;
                        }
                    }

                    int            serversSkipped = 0;
                    int            serversQueried = 0;
                    IdentityClient client         = null;
                    try
                    {
                        client = new IdentityClient("Query Client", "Query Client", new GpsLocation(0, 0), null, 0);

                        int         maxResults    = cmd.IncludeImages ? 1000 : 10000;
                        string      nameFilter    = cmd.NameFilter != "**" ? cmd.NameFilter : null;
                        string      typeFilter    = cmd.TypeFilter != "**" ? cmd.TypeFilter : null;
                        GpsLocation queryLocation = cmd.Latitude != GpsLocation.NoLocation.Latitude ? new GpsLocation(cmd.Latitude, cmd.Longitude) : null;
                        foreach (ProfileServer targetServer in targetServers)
                        {
                            if (!targetServer.IsInitialized())
                            {
                                log.Trace("Profile server '{0}' not initialized, skipping ...", targetServer.Name);
                                serversSkipped++;
                                continue;
                            }
                            byte[] targetServerId = targetServer.GetNetworkId();
                            client.InitializeTcpClient();
                            Task <IdentityClient.SearchQueryInfo> searchTask    = client.SearchQueryAsync(targetServer, nameFilter, typeFilter, queryLocation, cmd.Radius, false, cmd.IncludeImages);
                            IdentityClient.SearchQueryInfo        searchResults = searchTask.Result;
                            if (searchResults != null)
                            {
                                List <byte[]> expectedCoveredServers;
                                int           localServerResults;
                                List <IdentityNetworkProfileInformation> expectedSearchResults = targetServer.GetExpectedSearchResults(nameFilter, typeFilter, queryLocation, cmd.Radius, false, cmd.IncludeImages, out expectedCoveredServers, out localServerResults);
                                List <IdentityNetworkProfileInformation> realResults           = searchResults.Results;
                                List <byte[]> realCoveredServers = searchResults.CoveredServers;

                                if (DebugModeEnabled)
                                {
                                    log.Info("  * '{0}': {1} real results, {2} calculated results, {3} max. real results, {4} local server results, {5} real covered servers, {6} calculated covered servers.", targetServer.Name, realResults.Count, expectedSearchResults.Count, maxResults, localServerResults, realCoveredServers.Count, expectedCoveredServers.Count);
                                }

                                if (!CompareSearchResults(realResults, expectedSearchResults, maxResults))
                                {
                                    log.Error("  * Real search results are different from the expected results on server instance '{0}'.", targetServer.Name);
                                    error = true;
                                    break;
                                }

                                if (!CompareCoveredServers(targetServerId, realCoveredServers, expectedCoveredServers, localServerResults, maxResults))
                                {
                                    log.Error("  * Real covered servers are different from the expected covered servers on server instance '{0}'.", targetServer.Name);
                                    error = true;
                                    break;
                                }

                                serversQueried++;
                            }
                            else
                            {
                                log.Error("  * Unable to perform search on server instance '{0}'.", targetServer.Name);
                                error = true;
                                break;
                            }
                        }
                    }
                    catch (Exception e)
                    {
                        log.Error("Exception occurred: {0}", e.ToString());
                        error = true;
                        break;
                    }

                    if (!error)
                    {
                        log.Info("  * Results of search queries on {0} servers match expected results. {1} servers were offline and skipped.", serversQueried, serversSkipped);
                    }

                    break;
                }



                case CommandType.Delay:
                {
                    CommandDelay cmd = (CommandDelay)command;
                    log.Info("  * Waiting {0} seconds ...", cmd.Seconds);
                    Thread.Sleep(TimeSpan.FromSeconds((double)cmd.Seconds));
                    break;
                }


                case CommandType.TakeSnapshot:
                {
                    CommandTakeSnapshot cmd = (CommandTakeSnapshot)command;

                    HashSet <string> runningServerNames = new HashSet <string>(StringComparer.Ordinal);
                    foreach (ProfileServer ps in profileServers.Values)
                    {
                        if (ps.IsRunningProcess())
                        {
                            if (!ps.Stop())
                            {
                                log.Error("  * Failed to stop profile server '{0}'.", ps.Name);
                                error = true;
                                break;
                            }

                            runningServerNames.Add(ps.Name);
                        }
                    }

                    if (error)
                    {
                        break;
                    }

                    Snapshot snapshot = new Snapshot(cmd.Name);
                    if (snapshot.Take(runningServerNames, profileServers, identityClients))
                    {
                        log.Info("  * Snapshot '{0}' has been created.", cmd.Name);
                    }
                    else
                    {
                        log.Error("  * Failed to take simulation snapshot.");
                        error = true;
                    }

                    break;
                }

                case CommandType.LoadSnapshot:
                {
                    CommandLoadSnapshot cmd = (CommandLoadSnapshot)command;

                    if (index != 1)
                    {
                        log.Error("  * LoadSnapshot must be the very first command in the scenario.");
                        error = true;
                        break;
                    }

                    Snapshot snapshot = new Snapshot(cmd.Name);
                    if (!snapshot.Load())
                    {
                        log.Error("  * Unable to load snapshot '{0}'.", cmd.Name);
                        error = true;
                        break;
                    }

                    try
                    {
                        // Initialize profile servers.
                        log.Debug("Initializing profile servers.");
                        foreach (ProfileServerSnapshot serverSnapshot in snapshot.ProfileServers)
                        {
                            ProfileServer profileServer = ProfileServer.CreateFromSnapshot(serverSnapshot);
                            profileServers.Add(profileServer.Name, profileServer);
                        }

                        // Initialize identities and connect them with their profile servers.
                        log.Debug("Initializing identity clients.");
                        foreach (IdentitySnapshot identitySnapshot in snapshot.Identities)
                        {
                            ProfileServer  profileServer  = profileServers[identitySnapshot.ProfileServerName];
                            IdentityClient identityClient = IdentityClient.CreateFromSnapshot(identitySnapshot, snapshot.Images, profileServer);
                            profileServer.AddIdentityClientSnapshot(identityClient);
                            identityClients.Add(identityClient.Name, identityClient);
                        }

                        // Initialize neighbor relations.
                        log.Debug("Initializing neighborhoods.");
                        foreach (ProfileServerSnapshot serverSnapshot in snapshot.ProfileServers)
                        {
                            ProfileServer profileServer = profileServers[serverSnapshot.Name];

                            List <ProfileServer> neighborServers = new List <ProfileServer>();
                            foreach (string neighborName in serverSnapshot.LocServer.NeighborsNames)
                            {
                                ProfileServer neighborServer = profileServers[neighborName];
                                neighborServers.Add(neighborServer);
                            }

                            profileServer.LocServer.SetNeighborhood(neighborServers);
                        }

                        // Start LOC servers and profile servers.
                        log.Debug("Starting servers.");
                        foreach (ProfileServerSnapshot serverSnapshot in snapshot.ProfileServers)
                        {
                            ProfileServer profileServer = profileServers[serverSnapshot.Name];
                            if (!profileServer.LocServer.Start())
                            {
                                log.Error("  * Unable to start LOC server of profile server instance '{0}'.", profileServer.Name);
                                error = true;
                                break;
                            }

                            if (serverSnapshot.IsRunning)
                            {
                                if (!profileServer.Start())
                                {
                                    log.Error("  * Unable to start profile server instance '{0}'.", profileServer.Name);
                                    error = true;
                                    break;
                                }
                            }
                        }
                    }
                    catch (Exception e)
                    {
                        log.Error("  * Snapshot is corrupted, exception occurred: {0}", e.ToString());
                        error = true;
                        break;
                    }


                    if (!error)
                    {
                        log.Info("  * Simulation state loaded from snapshot '{0}'.", cmd.Name);
                    }

                    break;
                }


                case CommandType.DebugMode:
                {
                    CommandDebugMode cmd = (CommandDebugMode)command;
                    log.Info("  * Debug mode is now {0}.", cmd.Enable ? "ENABLED" : "DISABLED");
                    DebugModeEnabled = cmd.Enable;
                    break;
                }



                default:
                    log.Error("Invalid command type '{0}'.", command.Type);
                    error = true;
                    break;
                }

                index++;
                if (error)
                {
                    break;
                }
            }

            res = !error;

            log.Trace("(-):{0}", res);
            return(res);
        }