public async Task <(bool HasMoreToBuild, IEnumerable <BuildAction> Actions)> GetBuildActions(Village village, IEnumerable <BuildingModel> allBuildings = null)
        {
            var result               = new List <BuildAction>();
            var buildings            = (allBuildings ?? await _buildingRepository.GetAllBuildings()).ToList();
            var dorf1BuildingToBuild = GetResourceFieldToBuildNext(village, buildings);

            if (dorf1BuildingToBuild != null)
            {
                result.Add(new BuildAction
                {
                    BuildingId   = dorf1BuildingToBuild.BuildingId,
                    Action       = GameActionType.BUILD,
                    BuildingSlot = dorf1BuildingToBuild.Id,
                    Village      = village
                });
            }

            BuildingPlanModel plan = null;

            if (!string.IsNullOrEmpty(village.BuildingPlanId))
            {
                plan = await _buildingPlanRepository.GetBuildingPlan(village.BuildingPlanId);
            }
            if (plan == null)
            {
                plan = (await _buildingPlanRepository.GetBuildingPlans(BuildingPlanRepository.DefaultPlanUserName)).FirstOrDefault();
            }

            var hasMoreBuildingsToBuild = TryGetNextBuildingInVillageToBuildFromBuildingPlan(village, buildings, plan, out var dorf2Building);

            if (dorf2Building != null)
            {
                var slot2 = village.BuildingSlots
                            .Where(x => x.BuildingId == dorf2Building.BuildingId)
                            .OrderBy(x => x.Level)
                            .FirstOrDefault();

                result.Add(new BuildAction
                {
                    BuildingId   = dorf2Building.BuildingId,
                    Action       = GameActionType.BUILD,
                    BuildingSlot = string.IsNullOrEmpty(slot2?.Id) ? dorf2Building.PrefferedBuildingSlot : slot2.Id,
                    Village      = village
                });
            }

            return(hasMoreBuildingsToBuild || dorf1BuildingToBuild != null, result);
        }
        //[Route("[controller]/[action]/{id}")]
        public async Task <IActionResult> Upsert(string id)
        {
            BuildingPlanViewModel model = null;

            try
            {
                var allBuildings = (await _buildingRepository.GetAllBuildings()).ToList();

                BuildingPlanModel plan;
                IEnumerable <BuildingPlanStepViewModel> queue = null;
                if (string.IsNullOrEmpty(id))
                {
                    plan = new BuildingPlanModel
                    {
                        BotUserName = User.Identity.Name
                    };
                }
                else
                {
                    plan = await _buildingPlanRepository.GetBuildingPlan(id);

                    queue = plan.BuildingSteps.Select(x => new BuildingPlanStepViewModel
                    {
                        Order    = x.Order,
                        Level    = x.Level,
                        Building = allBuildings.FirstOrDefault(y => y.BuildingId == x.BuildingId)
                    });
                }

                model = _mapper.Map <BuildingPlanViewModel>(plan);
                model.BuildingSteps   = queue?.ToList();
                ViewData["buildings"] = allBuildings;
            }
            catch (Exception exc)
            {
                _logger.LogError(LoggingEvents.GetItemException, exc, exc.Message);
                ViewBag.ErrorMessage = "Unable to find Building Plan.";
            }

            return(View(model));
        }
        private static SortedList <int, Tuple <BuildingModel, int> > CreateBuildingPlan(List <BuildingModel> buildings, BuildingPlanModel buildingPlan)
        {
            var result = new SortedList <int, Tuple <BuildingModel, int> >();

            if (buildingPlan == null)
            {
                var mainBuilding = buildings.First(x => x.Name == "main_building");
                var warehouse    = buildings.First(x => x.Name == "warehouse");
                var granary      = buildings.First(x => x.Name == "granary");
                var marketplace  = buildings.First(x => x.Name == "marketplace");
                var rally_point  = buildings.First(x => x.Name == "rally_point");
                var barracks     = buildings.First(x => x.Name == "barracks");
                var academy      = buildings.First(x => x.Name == "academy");
                var smithy       = buildings.First(x => x.Name == "smithy");
                var stable       = buildings.First(x => x.Name == "stable");
                var trade_office = buildings.First(x => x.Name == "trade_office");
                var sawmill      = buildings.First(x => x.Name == "sawmill");
                var brickyard    = buildings.First(x => x.Name == "brickyard");
                var iron_foundry = buildings.First(x => x.Name == "iron_foundry");
                var grain_mill   = buildings.First(x => x.Name == "grain_mill");
                var bakery       = buildings.First(x => x.Name == "bakery");
                var residence    = buildings.First(x => x.Name == "residence");

                var steps = new List <Tuple <BuildingModel, int> >
                {
                    new Tuple <BuildingModel, int>(mainBuilding, 3),
                    new Tuple <BuildingModel, int>(warehouse, 3),
                    new Tuple <BuildingModel, int>(granary, 2),
                    new Tuple <BuildingModel, int>(mainBuilding, 12),
                    new Tuple <BuildingModel, int>(warehouse, 12),
                    new Tuple <BuildingModel, int>(granary, 9),
                    new Tuple <BuildingModel, int>(residence, 3),
                    new Tuple <BuildingModel, int>(mainBuilding, 20),
                    new Tuple <BuildingModel, int>(marketplace, 3),
                    new Tuple <BuildingModel, int>(barracks, 3),
                    new Tuple <BuildingModel, int>(academy, 5),
                    new Tuple <BuildingModel, int>(smithy, 3),
                    new Tuple <BuildingModel, int>(stable, 5),
                    new Tuple <BuildingModel, int>(brickyard, 2),
                    new Tuple <BuildingModel, int>(sawmill, 2),
                    new Tuple <BuildingModel, int>(brickyard, 3),
                    new Tuple <BuildingModel, int>(sawmill, 3),
                    new Tuple <BuildingModel, int>(iron_foundry, 2),
                    new Tuple <BuildingModel, int>(brickyard, 5),
                    new Tuple <BuildingModel, int>(sawmill, 5),
                    new Tuple <BuildingModel, int>(iron_foundry, 5),
                    new Tuple <BuildingModel, int>(warehouse, 20),
                    new Tuple <BuildingModel, int>(granary, 20),
                    new Tuple <BuildingModel, int>(marketplace, 20),
                    new Tuple <BuildingModel, int>(stable, 10),
                    new Tuple <BuildingModel, int>(trade_office, 12),
                    new Tuple <BuildingModel, int>(grain_mill, 5),
                    new Tuple <BuildingModel, int>(bakery, 5),
                    new Tuple <BuildingModel, int>(residence, 10)
                };

                for (var i = 0; i < steps.Count; i++)
                {
                    result.Add(i, steps[i]);
                }
            }
            else
            {
                foreach (var step in buildingPlan.BuildingSteps)
                {
                    result.Add(step.Order, new Tuple <BuildingModel, int>(buildings.FirstOrDefault(x => x.BuildingId == step.BuildingId), step.Level));
                }
            }

            return(result);
        }
        /// <summary>
        /// Tries to get the next building in village to build from building plan.
        /// </summary>
        /// <param name="village">The village.</param>
        /// <param name="buildings">The buildings.</param>
        /// <param name="buildingModel">The building model.</param>
        /// <returns>True if building plan is not yet completed. Otherwise: false</returns>
        private static bool TryGetNextBuildingInVillageToBuildFromBuildingPlan(Village village, List <BuildingModel> buildings, BuildingPlanModel buildingPlan, out BuildingModel buildingModel)
        {
            //var warehouse = buildings.First(x => x.Name == "warehouse");
            //var granary = buildings.First(x => x.Name == "granary");
            //if (village.ResourcesProduction.ToList().Max() * 5 > village.Warehourse)
            //    return warehouse;
            //if (village.ResourcesProduction.Crop * 5 > village.Granary)
            //    return granary;

            var plan   = CreateBuildingPlan(buildings, buildingPlan);
            var i      = 0;
            var result = false;

            while (!result && i < plan.Count)
            {
                var currentStep = plan[i++];
                if (CheckPrerequiresites(currentStep.Item1, village, buildings))
                {
                    var slot  = village.BuildingSlots.FirstOrDefault(x => x.BuildingId == currentStep.Item1.BuildingId);
                    var level = slot?.Level ?? 0;
                    if (level < currentStep.Item2)
                    {
                        result = true;
                        var state    = (slot?.State ?? BuildingSlotState.Empty);
                        var canBuild = state == BuildingSlotState.Good || state == BuildingSlotState.Empty;
                        if (canBuild)
                        {
                            buildingModel = currentStep.Item1;
                            return(true);
                        }
                    }
                }
            }

            buildingModel = null;
            return(result);
        }