class ProjectionServiceImpl implements ProjectionService, Constants {

    @Override
    public ProjectionResponse getPatchingAndProjectionByWeek(String assetGroup)
            throws ServiceException {
        if (projectionAssetgroups.contains(assetGroup)) {
            List<Map<String, Object>> patchingAndProjectionProgressList = new ArrayList<>();
            Long totalAssets = 0l;
            LocalDate todayDate = LocalDate.now();
            DateTimeFormatter formatter = DateTimeFormatter
                    .ofPattern("yyyy-MM-dd");
            int quarter = todayDate.get(IsoFields.QUARTER_OF_YEAR);
            int year = todayDate.getYear();
            int weekNumber = 0;
            StringBuilder targetType = new StringBuilder();
            String targetTypes = complianceRepository.getTargetTypeForAG(
                    assetGroup, null);
            List<String> targetTypesList = new ArrayList<>(
                    Arrays.asList(targetTypes.split(",")));
            Map<Integer, Map<String, Object>> onpremProjectionByWeekMap = new HashMap<>();
            Map<Integer, Map<String, Object>> ec2ProjectionByWeekMap = new HashMap<>();
            long totalPatchCount = 0;
            long patchCount = 0;
            long previoudWeekTotalPatchCount = 0;
            long projectionCount;
            long onpremProjectionCount;
            long ec2ProjectionCount;
            long totalProjectionCount = 0;
            long previousWeekProjectionCount = 0;
            Map<String, Object> patchingAndProjection = null;
            // get data from repository
            for (String resourceType : targetTypesList) {
                try {
                    resourceType = resourceType.replaceAll("\'", "");

                    if (resourceType.equalsIgnoreCase(ONPREMSERVER)) {
                        if (targetType.length() > 0) {
                            targetType.append(",").append(resourceType);
                        } else {
                            targetType.append(resourceType);
                        }
                       Long onpremTotalAssets = 0l;
                       if(complianceService.getPatching(
                               assetGroup, resourceType, null).containsKey(TOTAL_INSTANCES)){
                           onpremTotalAssets = complianceService.getPatching(
                                   assetGroup, resourceType, null).get(TOTAL_INSTANCES);
                       }
                       
                        totalAssets += onpremTotalAssets;
                        List<Map<String, Object>> onpremProjectionByWeekList = repository
                                .getProjectionDetailsFromDb(resourceType, year,
                                        quarter);
                        if (!onpremProjectionByWeekList.isEmpty()) {
                            onpremProjectionByWeekMap = onpremProjectionByWeekList
                                    .parallelStream()
                                    .collect(
                                            Collectors.toMap(
                                                    projection -> Integer
                                                            .parseInt(projection
                                                                    .get("week")
                                                                    .toString()),
                                                    projection -> projection));
                        }
                    } else if (resourceType.equalsIgnoreCase(EC2)) {
                        if (targetType.length() > 0) {
                            targetType.append(",").append(resourceType);
                        } else {
                            targetType.append(resourceType);
                        }
                       Long ec2TotalAssets = 0l;
                       if(complianceService.getPatching(
                               assetGroup, resourceType, null).containsKey(TOTAL_INSTANCES)){
                           ec2TotalAssets = complianceService.getPatching(
                                   assetGroup, resourceType, null).get(TOTAL_INSTANCES);
                       }
                       
                        totalAssets += ec2TotalAssets;
 
                        List<Map<String, Object>> ec2ProjectionByWeekList = repository
                                .getProjectionDetailsFromDb(resourceType, year,
                                        quarter);
                        if (!ec2ProjectionByWeekList.isEmpty()) {
                            ec2ProjectionByWeekMap = ec2ProjectionByWeekList
                                    .parallelStream()
                                    .collect(
                                            Collectors.toMap(
                                                    projection -> Integer
                                                            .parseInt(projection
                                                                    .get("week")
                                                                    .toString()),
                                                    projection -> projection));
                        }
                    }
                } catch (DataException e) {
                	logger.error("Error @ getPatchingAndProjectionByWeek", e);
                    throw new ServiceException(e);
                }
            }
            Map<Integer, Long> patchingSnapshot;
            try {
                patchingSnapshot = repository.getPatchingSnapshot(assetGroup);
            } catch (DataException e) {
            	logger.error("Error @ getPatchingAndProjectionByWeek while getting the patching snapshot", e);
                throw new ServiceException(e);
            }
            List<LocalDate> lastDayOfEachWeek = repository
                    .getListOfLastWeekDateOfQuarter();
            for (LocalDate lastdayofWeek : lastDayOfEachWeek) {
                onpremProjectionCount = 0;
                ec2ProjectionCount = 0;
                projectionCount = 0;

                patchingAndProjection = new HashMap<>();

                weekNumber = repository.getWeekNoByDate(lastdayofWeek);
                if (null != patchingSnapshot.get(weekNumber)) {
                    totalPatchCount = patchingSnapshot.get(weekNumber);
                }
                if (totalPatchCount > previoudWeekTotalPatchCount) {
                    patchCount = totalPatchCount - previoudWeekTotalPatchCount;
                } else if (totalPatchCount == 0) {
                    patchCount = 0;
                    totalPatchCount = previoudWeekTotalPatchCount;
                } else {
                    patchCount = totalPatchCount;
                }

                previoudWeekTotalPatchCount = totalPatchCount;
                if (null != onpremProjectionByWeekMap.get(weekNumber)) {
                    Map<String, Object> onpremProjectionDetails = onpremProjectionByWeekMap
                            .get(weekNumber);
                    if (!onpremProjectionDetails.isEmpty()) {
                        onpremProjectionCount = Long
                                .parseLong(onpremProjectionDetails.get(
                                        "projection").toString());
                    }
                }

                if (null != ec2ProjectionByWeekMap.get(weekNumber)) {
                    Map<String, Object> ec2ProjectionDetails = ec2ProjectionByWeekMap
                            .get(weekNumber);
                    if (!ec2ProjectionDetails.isEmpty()) {
                        ec2ProjectionCount = Long
                                .parseLong(ec2ProjectionDetails.get(
                                        "projection").toString());
                    }
                }

                if (onpremProjectionCount > 0 || ec2ProjectionCount > 0) {
                    projectionCount = onpremProjectionCount
                            + ec2ProjectionCount;
                }

                totalProjectionCount = projectionCount
                        + previousWeekProjectionCount;
                previousWeekProjectionCount += projectionCount;
                patchingAndProjection.put("week", weekNumber);
                patchingAndProjection.put("date",
                        lastdayofWeek.format(formatter));
                patchingAndProjection.put("patched", patchCount);
                patchingAndProjection.put("projected", projectionCount);
                patchingAndProjection.put("totalPatched", totalPatchCount);
                patchingAndProjection.put("totalProjected",
                        totalProjectionCount);
                patchingAndProjectionProgressList.add(patchingAndProjection);

            }

            return new ProjectionResponse(assetGroup, targetType.toString(),
                    totalAssets, year, quarter,
                    patchingAndProjectionProgressList);
        } else {
            throw new ServiceException(
                    NOT_ELIGIBLE_PROJECTIONS);
        }
    }

}