// Loads a list of vehicles from a file
        // takes string fileName - the file to load from
        // returns a bool that will be true if everything went well
        public bool LoadGarageFromFile(string fileName = @"Garage.xml")
        {
            XElement xml;

            // if the file wasn't found
            if (!File.Exists(fileName))
            {
                return(false);
            }
            xml = XElement.Load(fileName);

            // find the onfo about the garage itself
            var info = xml.Descendants("Info").Select(v => new
            {
                x   = v.Attribute("SizeX").Value.Trim(),
                y   = v.Attribute("SizeY").Value.Trim(),
                fee = v.Attribute("ParkingFee").Value.Trim(),
                max = v.Attribute("MaximumHours").Value.Trim()
            }).First();

            int    xSize, ySize, maxHours;
            double parkingFee;

            // try to parse the values
            if (!int.TryParse(info.x, out xSize) || !int.TryParse(info.y, out ySize) || !int.TryParse(info.max, out maxHours) || !double.TryParse(info.fee, out parkingFee))
            {
                return(false);
            }

            // assign the values
            ParkingFee   = parkingFee;
            SizeX        = xSize;
            SizeY        = ySize;
            MaximumHours = maxHours;

            Vehicle vehicle;

            m_ParkingSpaces = new bool[SizeX, SizeY];

            // start parsing the vehicles
            var vehicles = xml.Descendants("Vehicle")
                           .Where(v => Enum.TryParse(v.Attribute("vehicleType").Value, out v_Vehicle type) &&
                                  int.TryParse(v.Attribute("parkingSpot").Value.Substring(v.Attribute("parkingSpot").Value.IndexOf('[') + 1, v.Attribute("parkingSpot").Value.IndexOf(',') - 1), out xSize) &&
                                  int.TryParse(v.Attribute("parkingSpot").Value.Substring(v.Attribute("parkingSpot").Value.IndexOf(',') + 1, v.Attribute("parkingSpot").Value.IndexOf(']') - v.Attribute("parkingSpot").Value.IndexOf(',') - 1), out ySize))
                           .Select(v => {
                Enum.TryParse(v.Attribute("vehicleType").Value, out v_Vehicle type);
                switch (type)
                {
                case v_Vehicle.Bus:
                    vehicle = new Bus()
                    {
                        regNr = v.Attribute("regNr").Value, dateTime = v.Attribute("dateTime").Value, parkingSpot = new ParkingSpot()
                        {
                            X = xSize - 1, Y = ySize - 1
                        }
                    };
                    break;

                case v_Vehicle.Car:
                    vehicle = new Car()
                    {
                        regNr = v.Attribute("regNr").Value, dateTime = v.Attribute("dateTime").Value, parkingSpot = new ParkingSpot()
                        {
                            X = xSize - 1, Y = ySize - 1
                        }
                    };
                    break;

                case v_Vehicle.MC:
                    vehicle = new MC()
                    {
                        regNr = v.Attribute("regNr").Value, dateTime = v.Attribute("dateTime").Value, parkingSpot = new ParkingSpot()
                        {
                            X = xSize - 1, Y = ySize - 1
                        }
                    };
                    break;

                case v_Vehicle.Truck:
                    vehicle = new Truck()
                    {
                        regNr = v.Attribute("regNr").Value, dateTime = v.Attribute("dateTime").Value, parkingSpot = new ParkingSpot()
                        {
                            X = xSize - 1, Y = ySize - 1
                        }
                    };
                    break;

                default:
                    vehicle = null;
                    break;
                }
                return(vehicle);
            }).ToList();

            // Park the loaded vehicles
            ParkVehiclesFromList(vehicles);
            return(true);
        }
        // !Mainly used for manual testing with different vehicle types!
        // Adds a new Vehicle to the list of Vehicles -
        // Creates a new Vehicle instance and assigns it a free parking space if available
        // takes argument v_Vehicle - type of vehicle to be created
        // returns a string with the return message of the method
        public string ParkVehicle(v_Vehicle type)
        {
            // Checks if the garage is full, so we can exit earlier if the garage is full
            if (NumberOfParkingSpaces == m_Vehicles.Count)
            {
                return($"The garage is full.");
            }

            // Get the current date
            string dateNow = GetDate();

            // the new vehicle to be added
            Vehicle vehicle; // = GenerateRandomVehicle();

            switch (type)
            {
            case v_Vehicle.Bus:
                vehicle = new Bus()
                {
                    regNr = getRandomRegNr(), dateTime = dateNow
                };
                break;

            case v_Vehicle.Car:
                vehicle = new Car()
                {
                    regNr = getRandomRegNr(), dateTime = dateNow
                };
                break;

            case v_Vehicle.MC:
                vehicle = new MC()
                {
                    regNr = getRandomRegNr(), dateTime = dateNow
                };
                break;

            case v_Vehicle.Truck:
                vehicle = new Truck()
                {
                    regNr = getRandomRegNr(), dateTime = dateNow
                };
                break;

            default:
                vehicle = null;
                break;
            }

            // so we can exit earlier if there's not enough space in the garage
            if (GetNumberOfFreeSpaces() < vehicle.vehicleSize)
            {
                return($"The garage is full!!.");
            }

            ParkingSpot index = FindFreeParkingSpace(vehicle.vehicleSize); // index used to find empty parking space

            // checks if we found a free parking space for the type of vehicle
            if (index.X == -1 && index.Y == -1)
            {
                return($"Not enough empty spaces in the garage for a vehicle of type: { vehicle.vehicleType.ToString()}.");
            }

            // sets the found parking space(s) to occupied/true
            for (int i = 0; i < vehicle.vehicleSize; i++)
            {
                m_ParkingSpaces[index.X, index.Y + i] = !m_ParkingSpaces[index.X, index.Y + i];
            }
            // assigns the vehicle its parking space
            vehicle.parkingSpot = index;

            // add the new vehicle to the list
            m_Vehicles.Add(vehicle);

            return($"The vehicle of the type: {vehicle.vehicleType.ToString()} " +
                   $"with the registration number: {vehicle.regNr} \nwas parked in the garage at " +
                   $"parking space(s): {index.ToString()}" + (vehicle.vehicleSize > 1 ? $" to [{index.X + 1},{index.Y + vehicle.vehicleSize}]." : ""));
        }