using EnVisage.Code.DAL.Mongo; using EnVisage.Models; using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Mvc; namespace EnVisage.Code.BLL { /// /// Does merging of client changes model to server model /// public class MixModelsMergeManager { public void MergeFilters(MixFilterModel serverModel, MixFilterModel clientModel) { if ((clientModel == null) || (clientModel.Selection == null)) return; if (serverModel == null) throw new ArgumentNullException("serverModel"); if (serverModel.Selection == null) serverModel.Selection = new MixFilterSelectionModel(); serverModel.Selection.StartDate = clientModel.Selection.StartDate; serverModel.Selection.EndDate = clientModel.Selection.EndDate; serverModel.Selection.TeamsViews = clientModel.Selection.TeamsViews.Select(c => new MixTeamViewModel() { Id = c.Id, IsNew = c.IsNew, TVName = c.TVName, Group = new SelectListGroup { Name = c.Group.Name, Disabled = false }, CompanyId = c.CompanyId, CostCenterId = c.CostCenterId, CapacityTeamId = c.CapacityTeamId, CopyPlanned = c.CopyPlanned, UserId = (c.UserId != null) ? c.UserId.Select(u => u).ToArray() : null, Data = (c.Data != null) ? c.Data.Where(d => (d != null)).Select(r => new WidgetExpCategory() { Id = r.Id, Name = r.Name, InPlan = r.InPlan, Positions = (r.Positions != null) ? r.Positions.Where(a => (a != null)).Select(p => new WidgetExpCatPosition() { StartDate = p.StartDate, EndDate = p.EndDate, Need = p.Need, SDate = null, EDate = null }).ToArray() : null }).ToArray() : null }).ToList(); } public void MergeHeaders(MixSaveModel serverModel, MixSaveModel clientModel) { serverModel.Id = clientModel.Id; serverModel.Name = clientModel.Name; serverModel.StartDate = clientModel.StartDate; serverModel.EndDate = clientModel.EndDate; serverModel.CreatedBy = clientModel.CreatedBy; if (clientModel.Users != null) { if (serverModel.Users == null) serverModel.Users = new List(); List usersToAppend = clientModel.Users.Where(u => !serverModel.Users.Contains(u)).ToList(); serverModel.Users.AddRange(usersToAppend); } } public void MergeCalendars(MixSaveModel serverModel, MixSaveModel clientModel, DateTime periodStartWeekending, DateTime periodEndWeekending) { if ((serverModel == null) || (serverModel.Calendar == null)) return; if ((clientModel == null) || (clientModel.Calendar == null)) return; // Convert period bound dates to Unix long startDateUnix = GetUnixDate(periodStartWeekending); long endDateUnix = GetUnixDate(periodEndWeekending); this.MergeTeamCollections(serverModel.Calendar, clientModel.Calendar); this.MergeProjectCollections(serverModel.Calendar, clientModel.Calendar); this.SortProjects(serverModel.Calendar, startDateUnix, endDateUnix); this.MergeProjectLists(serverModel.Calendar, clientModel.Calendar); this.MergeLayouts(serverModel.Calendar, clientModel.Calendar); } protected void MergeProjectCollections(MixCalendarModel serverCalendarModel, MixCalendarModel clientCalendarModel) { if (serverCalendarModel == null) throw new ArgumentNullException("serverCalendarModel"); if (serverCalendarModel.Projects == null) serverCalendarModel.Projects = new Dictionary(); if ((clientCalendarModel == null) || (clientCalendarModel.Projects == null)) return; // Get project list to update (exist in both models) List projectsToUpdate = serverCalendarModel.Projects.Where(p => clientCalendarModel.Projects.ContainsKey(p.Key)).Select(p => p.Key).ToList(); foreach (string projectId in projectsToUpdate) { MixProjectModel serverProjectItem = serverCalendarModel.Projects[projectId]; MixProjectModel clientProjectItem = clientCalendarModel.Projects[projectId]; MergeSingleProjectModels(serverProjectItem, clientProjectItem); } } protected void MergeSingleProjectModels(MixProjectModel serverProjectModel, MixProjectModel clientProjectModel) { if (clientProjectModel.Scenario != null) serverProjectModel.Scenario = clientProjectModel.Scenario.Clone(); else serverProjectModel.Scenario = null; if (clientProjectModel.Teams != null) { // Merging of project Teams serverProjectModel.Teams = new List(); serverProjectModel.Teams.AddRange(clientProjectModel.Teams); } } protected void MergeTeamCollections(MixCalendarModel serverCalendarModel, MixCalendarModel clientCalendarModel) { if (serverCalendarModel.Teams == null) throw new ArgumentNullException("serverCalendarModel.Teams"); if (clientCalendarModel.Teams == null) return; // Merging of teams, that exist both in server and client models // serverModel must have all new teams from clientModel (as a result of the MixController.GetCalendar method) foreach (MixTeamModel clientTeam in clientCalendarModel.Teams) { MixTeamModel serverTeam = serverCalendarModel.Teams.FirstOrDefault(t => t.Id.Equals(clientTeam.Id)); if ((serverTeam != null) && (serverTeam.Id.Length > 0)) { MergeSingleTeamModels(serverTeam, clientTeam); } } // Check, if some new teams in client Model doesn't exist in server Model. // If so, write here code for adding absent teams } protected void MergeSingleTeamModels(MixTeamModel serverTeamModel, MixTeamModel clientTeamModel) { if (serverTeamModel == null) throw new ArgumentNullException("serverTeamModel"); if (clientTeamModel == null) throw new ArgumentNullException("clientTeamModel"); serverTeamModel.CompanyId = clientTeamModel.CompanyId; serverTeamModel.CostCenterId = clientTeamModel.CostCenterId; serverTeamModel.Name = clientTeamModel.Name; serverTeamModel.UserId = clientTeamModel.UserId; serverTeamModel.PlannedCapacity = (clientTeamModel.PlannedCapacity != null) ? clientTeamModel.PlannedCapacity.Select(pc => new MixTeamCapacity() { Id = pc.Id, ExpCatId = pc.ExpCatId, Values = (pc.Values != null) ? pc.Values.Select(k => new KeyValuePair(k.Key, k.Value)) .ToDictionary(k => k.Key, v => v.Value) : new Dictionary() }).ToList() : null; serverTeamModel.ExpCategories = (clientTeamModel.ExpCategories != null) ? clientTeamModel.ExpCategories.Select(k => new KeyValuePair(k.Key, new ActivityExpCategoryFooterModel() { Id = k.Value.Id, Name = k.Value.Name, UomValue = k.Value.UomValue, ActualCapacityValues = (k.Value.ActualCapacityValues != null) ? k.Value.ActualCapacityValues.Select(ac => new KeyValuePair(ac.Key, ac.Value)) .ToDictionary(ac => ac.Key, ac => ac.Value) : new Dictionary(), AllocatedCapacity = (k.Value.AllocatedCapacity != null) ? k.Value.AllocatedCapacity.Select(ac => new KeyValuePair(ac.Key, ac.Value)) .ToDictionary(ac => ac.Key, ac => ac.Value) : new Dictionary(), NeedCapacity = (k.Value.NeedCapacity != null) ? k.Value.NeedCapacity.Select(ac => new KeyValuePair(ac.Key, ac.Value)) .ToDictionary(ac => ac.Key, ac => ac.Value) : new Dictionary(), PlannedCapacityValues = (k.Value.PlannedCapacityValues != null) ? k.Value.PlannedCapacityValues.Select(ac => new KeyValuePair(ac.Key, ac.Value)) .ToDictionary(ac => ac.Key, ac => ac.Value) : new Dictionary(), Resources = (k.Value.Resources != null) ? k.Value.Resources.Select(ac => new KeyValuePair(ac.Key, new ActivityResourceFooterModel() { Id = ac.Value.Id, Name = ac.Value.Name, AllocatedCapacity = (ac.Value.AllocatedCapacity != null) ? ac.Value.AllocatedCapacity.Select(r => new KeyValuePair(r.Key, r.Value)) .ToDictionary(r => r.Key, r => r.Value) : new Dictionary(), TotalCapacity = (ac.Value.TotalCapacity != null) ? ac.Value.TotalCapacity.Select(r => new KeyValuePair(r.Key, r.Value)) .ToDictionary(r => r.Key, r => r.Value) : new Dictionary() })).ToDictionary(r => r.Key, r => r.Value) : new Dictionary() })).ToDictionary(k => k.Key, v => v.Value) : null; } protected void SortProjects(MixCalendarModel model, long startDateUnix, long endDateUnix) { model.ManagedProjects = new List(); model.UnscheduledProjects = new List(); model.QueuedProjects = new List(); model.UnassignedExpendituresProjects = new List(); // SA. ENV-1210 if ((model.Projects == null) || (model.Projects.Count < 1)) return; foreach (string projectIdText in model.Projects.Keys) { Guid projectId = new Guid(projectIdText); MixProjectModel projectModel = model.Projects[projectIdText]; if (projectModel.Scenario == null) { // Send project to Unscheduled list model.UnscheduledProjects.Add(projectId); continue; } if ((projectModel.Scenario.StartDate > endDateUnix) || (projectModel.Scenario.EndDate < startDateUnix)) { // Send project to Queued list model.QueuedProjects.Add(projectId); continue; } model.ManagedProjects.Add(projectId); } } protected void MergeProjectLists(MixCalendarModel serverCalendarModel, MixCalendarModel clientCalendarModel) { if (serverCalendarModel == null) throw new ArgumentException("serverCalendarModel"); if (serverCalendarModel.Projects == null) throw new ArgumentException("serverCalendarModel.Projects"); if (serverCalendarModel.Teams == null) throw new ArgumentException("serverCalendarModel.Teams"); if ((clientCalendarModel == null) || (clientCalendarModel.Projects == null)) return; if (((clientCalendarModel.Projects == null) || (clientCalendarModel.Projects.Count < 1)) && (clientCalendarModel.ManagedProjects == null || (clientCalendarModel.ManagedProjects.Count < 1)) && ((clientCalendarModel.UnscheduledProjects == null) || (clientCalendarModel.UnscheduledProjects.Count < 1))) // Client model is empty return; foreach (var project in serverCalendarModel.Projects) { var mixProject = clientCalendarModel.Projects.FirstOrDefault(x => x.Value.Id == project.Value.Id); if(mixProject.Value != null) project.Value.Pinned = mixProject.Value.Pinned; } // Merge Managed projects lists List existingManagedProjects = clientCalendarModel.ManagedProjects.Where(p => serverCalendarModel.ManagedProjects.Contains(p)).ToList(); List newManagedProjectsFromServer = serverCalendarModel.ManagedProjects.Where(p => !existingManagedProjects.Contains(p) && !clientCalendarModel.UnscheduledProjects.Contains(p)).ToList(); serverCalendarModel.ManagedProjects.RemoveAll(p => !existingManagedProjects.Contains(p)); serverCalendarModel.ManagedProjects.AddRange(newManagedProjectsFromServer); // Merge Unscheduled projects lists List existingUnscheduledProjects = clientCalendarModel.UnscheduledProjects.Where(p => serverCalendarModel.UnscheduledProjects.Contains(p)).ToList(); List newUnscheduledProjectsFromServer = clientCalendarModel.UnscheduledProjects.Where(p => !existingUnscheduledProjects.Contains(p) && !serverCalendarModel.ManagedProjects.Contains(p)).ToList(); serverCalendarModel.UnscheduledProjects.RemoveAll(p => !existingUnscheduledProjects.Contains(p)); serverCalendarModel.UnscheduledProjects.AddRange(newUnscheduledProjectsFromServer); serverCalendarModel.QueuedProjects.RemoveAll(p => serverCalendarModel.ManagedProjects.Contains(p) || serverCalendarModel.UnscheduledProjects.Contains(p)); // Merge Unassigned Expenditures Projects lists (ENV-1210) List existingUnassignedExpProjects = clientCalendarModel.UnassignedExpendituresProjects.Where(p => serverCalendarModel.Projects.ContainsKey(p.ProjectId.ToString())).ToList(); serverCalendarModel.UnassignedExpendituresProjects.Clear(); serverCalendarModel.UnassignedExpendituresProjects.AddRange(existingUnassignedExpProjects); } protected void MergeLayouts(MixCalendarModel serverCalendarModel, MixCalendarModel clientCalendarModel) { if (serverCalendarModel == null) throw new ArgumentException("serverCalendarModel"); if (serverCalendarModel.Projects == null) throw new ArgumentException("serverCalendarModel.Projects"); if (serverCalendarModel.Teams == null) throw new ArgumentException("serverCalendarModel.Teams"); if ((clientCalendarModel == null) || (clientCalendarModel.Projects == null) || (clientCalendarModel.Layout == null) || (clientCalendarModel.Layout.Count < 1)) return; List layoutTeams = serverCalendarModel.Teams.Select(t => new Guid(t.Id)).ToList(); serverCalendarModel.Layout = new List(); foreach (Guid teamId in layoutTeams) { List existingForTeam = serverCalendarModel.ManagedProjects.Where(p => (serverCalendarModel.Projects[p.ToString()].Teams != null) && (serverCalendarModel.Projects[p.ToString()].Teams.Contains(teamId)) && (clientCalendarModel.Layout != null) && clientCalendarModel.Layout.Any(l => (l.TeamId.Equals(teamId) && l.ProjectId.Equals(p))) ).ToList(); List newForTeam = serverCalendarModel.ManagedProjects.Where(p => (serverCalendarModel.Projects[p.ToString()].Teams != null) && (serverCalendarModel.Projects[p.ToString()].Teams.Contains(teamId)) && !existingForTeam.Contains(p) ).ToList(); List teamLayoutRowsForExisingProjects = clientCalendarModel.Layout.Where(l => l.TeamId.Equals(teamId) && existingForTeam.Contains(l.ProjectId)) .Select(r => new MixTeamLayoutRowItem() { TeamId = teamId, Row = r.Row, ProjectId = r.ProjectId, Index = r.Index }).OrderBy(o1 => o1.Row).ThenBy(o2 => o2.Index).ToList(); List teamLayoutRowsForNewProjects = newForTeam.Select(pId => new MixTeamLayoutRowItem() { TeamId = teamId, Row = -1, ProjectId = pId, Index = 0 }).ToList(); // Renum row numbers for result layout rows int lastOldRowNum = -1; int newRowNum = -1; int newColNum = 0; foreach (MixTeamLayoutRowItem currentLayoutRow in teamLayoutRowsForExisingProjects) { if (lastOldRowNum != currentLayoutRow.Row) { // Project is located at new line lastOldRowNum = currentLayoutRow.Row; newRowNum++; newColNum = 0; } else { // Projects is located at the same line with the previous one newColNum++; } currentLayoutRow.Row = newRowNum; currentLayoutRow.Index = newColNum; } // Set row numbers for new project layout rows foreach (MixTeamLayoutRowItem currentLayoutRow in teamLayoutRowsForNewProjects) { newRowNum++; currentLayoutRow.Row = newRowNum; currentLayoutRow.Index = 0; } serverCalendarModel.Layout.AddRange(teamLayoutRowsForExisingProjects); serverCalendarModel.Layout.AddRange(teamLayoutRowsForNewProjects); } } protected long GetUnixDate(DateTime? date) { return date.HasValue ? Utils.ConvertToUnixDate(date.Value) : 0; } } }