'use strict'; app .controller('supplyDemandCalendarController', ['$scope', '$q', 'activityCalendarService', 'teamInfoService', 'activityCalendarUIService', 'dataSources', 'hoursResourcesConverter', function ($scope, $q, activityCalendarService, teamInfoService, activityCalendarUIService, dataSources, hoursResourcesConverter) { var reportDataUrl = '/SupplyDemandReport/GetReport'; $scope.ViewModel = { DisplayMode: null, Header: null, Rows: null, TotalRow: null, DataLoaded: false }; $scope.Filter = null; /* Event listeners */ $scope.$on('ac.rebuild-calendar', rebuildCalendarHandler); $scope.$on('ac.options-changed', optionsChangedHandler); /* Methods for interaction with view */ $scope.init = function (filter, displayMode) { rebuildCalendarHandler(null, filter, displayMode); }; $scope.toggleMonth = function (monthIndex) { $scope.ViewModel.Header.toggleMonth(monthIndex); }; $scope.toggleRow = function (uiRow, $event) { hideRedundantPopovers(); if ($($event.target).parents('.menuGroup').length > 0) return; // to-do: we should keep collapsed state in data-model items between possible future postbacks var dataModel = activityCalendarService.dataItemStub || {}; activityCalendarUIService.toggleRow(uiRow, dataModel); }; /* Event handlers */ function rebuildCalendarHandler(event, filter, displayMode, forceDataReload, successCallback) { // if filter is changed we need to invalidate cache if ($scope.Filter && !activityCalendarService.cacheKeysEqual($scope.Filter, filter)) { activityCalendarService.invalidateCache($scope.Filter); } $scope.ViewModel.DataLoaded = false; $scope.ViewModel.DisplayMode = angular.copy(displayMode || {}); $scope.Filter = angular.copy(filter || {}); blockUI(); hoursResourcesConverter.load(forceDataReload).then(function () { var loadCalendarTask = activityCalendarService.getActivityCalendar(reportDataUrl, filter, forceDataReload); var cachedTemplates = activityCalendarUIService.cacheTemplates(); var allTasks = [loadCalendarTask].concat(cachedTemplates); $q.all(allTasks) .then(function (asyncResults) { var calendar = asyncResults[0]; if (calendar.Teams) { var teamIds = Object.keys(calendar.Teams); var promise = dataSources.loadResourcesByTeamIds(teamIds) .then(function (result) { return asyncResults; }); return promise; } else { return asyncResults; } }) .then(function (asyncResults) { var calendar = asyncResults[0]; createViewModel(calendar); initBottomPart(); toggleParts(); toggleSortBy(); toggleHoursResourcesMode(); toggleBarsValuesMode(); toggleMonths(); unblockUI(); if (typeof successCallback === 'function') { successCallback(); } if (angular.isObject(calendar)) $scope.ViewModel.DataLoaded = true; }) .then(null, function () { unblockUI(); showErrorModal(); }); }).then(null, function () { unblockUI(); showErrorModal(); }); }; function optionsChangedHandler(event, displayMode, key, newValue) { //console.log(key); $scope.ViewModel.DisplayMode = displayMode || {}; switch (key) { case 'uomMode': toggleHoursResourcesMode(); $scope.$broadcast('changeUOMMode', newValue); break; case 'capBarMode': toggleBarsValuesMode(); break; case 'defaultView': toggleMonths(); break; case 'sortBy': case 'sortOrder': toggleSortBy(); break; case 'showParts': toggleParts(); toggleSortBy(); toggleHoursResourcesMode(); break; case 'capacityView': toggleCapacityType(); $scope.$broadcast('capacityViewChanged', newValue); break; default: break; }; }; /* Methods for creating view models */ function createViewModel(model) { var projectExpendituresCache = {}; createHeaderViewModel(model.WeekEndings); createRowsViewModel(model, projectExpendituresCache); fillViewModelWithData(model, projectExpendituresCache); projectExpendituresCache = null; }; function createHeaderViewModel(weekEndings) { $scope.ViewModel.Header = (new GridHeader(weekEndings || {}).create()); }; function createRowsViewModel(model, projectExpendituresCache) { $scope.ViewModel.Rows = []; if (!model || !model.Projects) { return; } var allocationMode = ($scope.Filter.Teams || []).length ? activityCalendarUIService.allocationMode.teamAllocation : activityCalendarUIService.allocationMode.needAllocation; var includeProjectNeed = allocationMode !== activityCalendarUIService.allocationMode.teamAllocation; var filterCategories = allocationMode == activityCalendarUIService.allocationMode.teamAllocation; var projects = model.Projects; for (var projectId in projects) { var extendedProjectModel = angular.extend({}, projects[projectId], { AllocationMode: allocationMode }); var projectExpenditures = activityCalendarUIService.getExpendituresWithResources4Project(extendedProjectModel, null, null, $scope.ViewModel.Header, $scope.Filter, includeProjectNeed, filterCategories, false, true); if (projectExpenditures && Object.keys(projectExpenditures).length) { projectExpendituresCache[projectId] = projectExpenditures; var templates = { projectRowTemplate: activityCalendarUIService.viewRowTemplates.projectSupplyDemandReportRowTemplate, projectRowNumbersTemplate: activityCalendarUIService.viewRowTemplates.projectSupplyDemandReportRowNumbersTemplate, expCatRowTemplate: activityCalendarUIService.viewRowTemplates.expCatSupplyDemandReportRowTemplate, expCatRowNumbersTemplate: activityCalendarUIService.viewRowTemplates.expCatSupplyDemandReportRowNumbersTemplate, }; var projectViewModel = activityCalendarUIService.createViewModel4Project(extendedProjectModel, projectExpendituresCache[projectId], $scope.Filter, false, templates); if (projectViewModel) { setTooltips(projectViewModel); $scope.ViewModel.Rows.push(projectViewModel); } } } // Create total rows createTotalRowModels(); }; function setTooltips(projectRow) { if (!projectRow || !projectRow.Children) return; for (var index = 0; index < projectRow.Children.length; index++) { var expCatRow = projectRow.Children[index]; if (expCatRow) { expCatRow.getTooltipContent = $scope.getTooltipContent; } } }; function createTotalRowModels() { $scope.ViewModel.TotalRow = activityCalendarUIService.createViewModel4TotalRow('Total'); }; function getTotalRows() { var rows = []; if ($scope.ViewModel.TotalRow) { rows.push($scope.ViewModel.TotalRow); } return rows; }; function getResourceRows(resourceId) { return activityCalendarUIService.getResourceRows($scope.ViewModel.Rows, resourceId); }; /* Methods for filling view models with data */ function fillViewModelWithData(model, projectExpendituresCache) { if (!$scope.ViewModel.Rows) { return; } for (var i = 0; i < $scope.ViewModel.Rows.length; i++) { var project = $scope.ViewModel.Rows[i]; var expenditures = projectExpendituresCache[project.Id]; activityCalendarUIService.fillProjectRowWithData(null, project, expenditures, $scope.ViewModel.Header, $scope.Filter, false); } // Fill total rows with data fillTotalRowsWithData(); }; function fillTotalRowsWithData() { var rowsForTotal = angular.copy($scope.ViewModel.Rows) || []; activityCalendarUIService.fillTotalRowData(rowsForTotal, $scope.ViewModel.TotalRow, $scope.ViewModel.Header); }; /* Methods for toggling display modes */ function toggleHoursResourcesMode() { var totalRows = getTotalRows(); activityCalendarUIService.toggleGridSource($scope.ViewModel.Rows, $scope.ViewModel.DisplayMode.IsUOMHours); activityCalendarUIService.toggleGridSource(totalRows, $scope.ViewModel.DisplayMode.IsUOMHours); if ($scope.ViewModel.DisplayMode.IsAvgMode()) { activityCalendarUIService.applyAvgMode($scope.ViewModel.Rows, $scope.ViewModel.Header); activityCalendarUIService.applyAvgMode(totalRows, $scope.ViewModel.Header); } }; function toggleBarsValuesMode() { activityCalendarUIService.toggleBarsValuesMode($scope.ViewModel.Rows, $scope.ViewModel.DisplayMode.IsBarMode); }; function toggleMonths() { if ($scope.ViewModel.DisplayMode.IsViewModeMonth) { $scope.ViewModel.Header.collapseMonthes(); } else { $scope.ViewModel.Header.expandMonthes(); } }; function toggleParts() { $scope.ViewModel.Rows = activityCalendarUIService.toggleParts($scope.ViewModel.Rows, $scope.ViewModel.DisplayMode.ShowParts.Value); activityCalendarUIService.updateProjectStyles($scope.ViewModel.Header, $scope.Filter, $scope.ViewModel.Rows); }; function toggleSortBy() { console.log($scope.ViewModel.DisplayMode.SortBy); var sortBy = ['Priority', 'Name']; //$scope.ViewModel.DisplayMode.SortBy $scope.ViewModel.Rows = activityCalendarUIService.toggleSortBy($scope.ViewModel.Rows, sortBy, $scope.ViewModel.DisplayMode.SortOrder); }; function toggleCapacityType() { // reset total row values createTotalRowModels(); // recalculate total row UI data fillTotalRowsWithData(); toggleHoursResourcesMode(); }; function initBottomPart() { // need to pass new objects for preventing using single instances of objects inside current and other controllers var displayMode = activityCalendarUIService.castDisplayModeIntoTeamInfoMode($scope.ViewModel.DisplayMode); displayMode.DisplayPriorityColumn = true; $scope.$broadcast('rebindTeamInfo', { Header: $scope.ViewModel.Header, DisplayMode: displayMode }); }; /* ===== ToolTips display ==== */ $scope.getTooltipContent = function (opts) { var tooltip = 'No data available'; var units = ' hours'; if (!$scope.DisplayMode.IsUOMHours) units = ' resources'; if (!opts || !opts.header || !opts.projectId || !opts.expCatId) return tooltip; var header = opts.header; var projectId = opts.projectId; var expCatId = opts.expCatId; var teamId = opts.teamId; var teamAllocations = activityCalendarUIService.getTeamAllocations4Display($scope.Filter, $scope.ViewModel.DisplayMode, $scope.ViewModel.Header, header, projectId, expCatId, teamId); if (teamAllocations && (teamAllocations.length > 0)) { tooltip = 'Allocated to Teams:'; for (var index = 0; index < teamAllocations.length; index++) { var teamInfo = teamAllocations[index]; tooltip += ('
' + teamInfo.Name + ': ' + teamInfo.Need + units); } } else { tooltip = 'No Team Allocations present'; } return tooltip; } }]);