(function () { "use strict"; var resultScenarios = { none: 0, distinctLeader: 1, tie: 2, noResults: 3, notParticipating: 4, multipleLeaders: 5 }; angular.module("enrMapModule") .factory("mapRegionLeaderCalculator", ["officeJsonRegionFilter", "detailsData", "participationCalculator", "primaryService", "$filter", function (officeJsonRegionFilter, detailsData, participationCalculator, primaryService, $filter) { return { resultScenarios: resultScenarios, determineLeader: function (officeCategoryElectionResultsJson, regionProperties) { // Initialize result data var resultScenario = resultScenarios.none; var leaderCandidate = 0; // Determine if the region is participating. Early out if they are not. var filteredRegionNodes = []; if (participationCalculator.isOfficesRegionParticipating(detailsData.getData(), regionProperties)) filteredRegionNodes = officeJsonRegionFilter.getRegionNodes(detailsData.getData(), regionProperties); if (filteredRegionNodes.length === 0) { resultScenario = resultScenarios.notParticipating; return { scenario: resultScenario } } // The presence of multiple nodes for a single region is not handled. if (filteredRegionNodes.length > 1) throw Error("RegionNodes.length > 1 error in leader calculator for region with geoId: " + regionProperties.GEOID); // We have found the 1 region node in JSON for this region var racesInThisRegion = filteredRegionNodes[0].Races.Race; //For primary, filter the races for selected party. if (primaryService.getIsPrimary() && typeof (racesInThisRegion.length) !== "undefined") { var party = primaryService.getSelectedParty(); // Loop all the races // check party candidates available or not and push only if party candidates available. var filteredRaces = []; racesInThisRegion.forEach(function (raceItem) { var candidateInfo = raceItem.Candidates.Candidate; if (!angular.isArray(candidateInfo)) candidateInfo = [candidateInfo]; var filteredCandidates = []; candidateInfo.forEach(function (candidateItem) { filteredCandidates.push(candidateItem); }); if (filteredCandidates.length > 0) { raceItem.Candidates.Candidate = filteredCandidates; filteredRaces.push(raceItem); } }); if (filteredRaces.length > 1) { racesInThisRegion = filteredRaces; } else { racesInThisRegion = filteredRaces[0]; } } // Determine if there are multiple races for this office category in the region. var isMultipleRaces = racesInThisRegion.length !== undefined; if (isMultipleRaces) { // It's possible the same race may be listed multiple times due the region having multiple reporting jurisdictions. Check for this. var raceIdList = racesInThisRegion.map(function (race) { return race.OFFICEID }); var raceIdListDistinct = raceIdList.filter(function (value, index, self) { return self.indexOf(value) === index; }); if (raceIdListDistinct.length === 1) { // There is actually only one race. It's just listed multiple times. isMultipleRaces = false; // Rather than add up the votes (as reported by each reporting jurisdiction) myself, just pull the pre-calculated total from the RegionSummary section. // Since we determined there's not multiple races, I can safely assume the RegionSummary only has one race in it. racesInThisRegion = filteredRegionNodes[0].RegionSummary.Race; } } if (isMultipleRaces) { // If there is more than one race, there can't be one distinct leader resultScenario = resultScenarios.multipleLeaders; } else { // There is only one race for this office category in this region. We have a shot at finding a distinct leader var candidatesInfo = racesInThisRegion.Candidates.Candidate; if (!angular.isArray(candidatesInfo)) candidatesInfo = [candidatesInfo]; // In primary mode, limit candidates to selected party if (primaryService.getIsPrimary()) { if (candidatesInfo[0].PARTY) candidatesInfo = $filter("filter")(candidatesInfo, { PARTY: primaryService.getSelectedParty() }); else if (candidatesInfo[0].PARTY_ABBREV) candidatesInfo = $filter("filter")(candidatesInfo, { PARTY_ABBREV: primaryService.getSelectedParty() }); // No candidates for this party. if (candidatesInfo.length === 0) { resultScenario = resultScenarios.notParticipating; return { scenario: resultScenario }; } } // Sort candidate info by votes and select leaders // (This change is being done last minute so I'm using a copy to avoid any chance that changing order of the original would cause problems elsewhere. // It's possibly the use of a copy could be removed, but you'd need to test) var isMultipleCandidates = candidatesInfo.length > 1; var candidatesInfoCopySorted = angular.copy(candidatesInfo) if (isMultipleCandidates) { var votePropertyName = candidatesInfoCopySorted[0].TOTAL_VOTES !== undefined ? "TOTAL_VOTES" : "TOTAL"; candidatesInfoCopySorted = $filter("orderBy")(candidatesInfoCopySorted, function (candidate) { return Number(candidate[votePropertyName]); }, true); } var leadCandidate = candidatesInfoCopySorted[0]; var secondCandidate = isMultipleCandidates ? candidatesInfoCopySorted[1] : undefined; // Pull votes data var leadCandidateVotes = leadCandidate.TOTAL_VOTES !== undefined ? leadCandidate.TOTAL_VOTES : leadCandidate.TOTAL; var secondCandidateVotes; if (secondCandidate !== undefined && secondCandidate !== null) secondCandidateVotes = secondCandidate.TOTAL_VOTES !== undefined ? secondCandidate.TOTAL_VOTES : secondCandidate.TOTAL; // No votes have come in yet. No one can be leading if (leadCandidateVotes === "0" || leadCandidateVotes === 0) resultScenario = resultScenarios.noResults; // Tie else if (secondCandidateVotes !== undefined && secondCandidateVotes !== null && leadCandidateVotes === secondCandidateVotes) resultScenario = resultScenarios.tie; // Single, distinct leader else { resultScenario = resultScenarios.distinctLeader; leaderCandidate = leadCandidate; } } return { scenario: resultScenario, leaderCandidate: leaderCandidate }; } }; }]); }());