class KernelComplianceRule extends BaseRule {

    @Override
    public RuleResult execute(final Map<String, String> ruleParam, Map<String, String> resourceAttributes) {
        logger.debug("==KernelComplianceRule started===");
        String userName = "username";
        String sshPd = "pwd";
        
        String instanceId = null;
        Annotation annotation = null;
        String ldapApi = null;
        String satAndSpacewalkApi = null;
        String kernelVersionByInstanceIdUrl = null;
        String kernelInfoApi = null;
        String ipAddress = null;
        int connectionPort = 22;
        boolean isComplianceCheckPassed = false;
        boolean isEligibleForAnnotation = true;

        List<String> listOfServersWhereComplianceCheckFailed = new ArrayList<>();
        Gson gson = new Gson();
        List<LinkedHashMap<String, Object>> issueList = new ArrayList<>();
        LinkedHashMap<String, Object> issue = new LinkedHashMap<>();
        
        String defaultKernelCriteriaUrl = ruleParam.get(PacmanRuleConstants.DEFAULT_KERNEL_CRITERIA_URL);
        String severity = ruleParam.get(PacmanRuleConstants.SEVERITY);
        String category = ruleParam.get(PacmanRuleConstants.CATEGORY);
        String accNames = ruleParam.get(PacmanRuleConstants.ACCOUNT_NAMES);
        String tagsSplitter = ruleParam.get(PacmanSdkConstants.SPLITTER_CHAR);
        String sourceType = ruleParam.get(PacmanRuleConstants.SOURCE_TYPE);
        
        String pacmanHost = PacmanUtils.getPacmanHost(PacmanRuleConstants.ES_URI); 
        String kernelVersionByInstanceIdAPI = PacmanUtils.formatUrl(ruleParam,PacmanRuleConstants.KERNEL_VERSION_BY_INSTANCEID_API,PacmanRuleConstants.PACMAN_API_URI);
        logger.debug("==pacmanHost {}  ===",pacmanHost);
        if(!StringUtils.isNullOrEmpty(pacmanHost)){
            ldapApi = ruleParam.get(PacmanRuleConstants.ES_LDAP_URL);
            satAndSpacewalkApi = ruleParam
                    .get(PacmanRuleConstants.ES_SATLLITE_AND_SPACEWALK_URL);
            kernelInfoApi = ruleParam.get(PacmanRuleConstants.KERNEL_INFO_API);
            ldapApi = pacmanHost+ldapApi;
            satAndSpacewalkApi = pacmanHost+satAndSpacewalkApi;
            kernelInfoApi = pacmanHost+kernelInfoApi;
        }
        logger.debug("==kernelInfoApi URL after concatination param {}  ===",kernelInfoApi);
        logger.debug("==ldapApi URL after concatination param {}  ===",ldapApi);
        logger.debug("==satAndSpacewalkApi URL after concatination param {}  ===",satAndSpacewalkApi);
        
        logger.debug("==kernelVersionByInstanceIdAPI {}==",kernelVersionByInstanceIdAPI);
		if (!StringUtils.isNullOrEmpty(kernelVersionByInstanceIdAPI)) {
			kernelVersionByInstanceIdUrl = kernelVersionByInstanceIdAPI;
		}
		logger.debug("==kernelVersionByInstanceIdUrl URL {}==", kernelVersionByInstanceIdUrl);

        MDC.put("executionId", ruleParam.get("executionId"));
        MDC.put("ruleId", ruleParam.get(PacmanSdkConstants.RULE_ID));
        StringBuilder description = new StringBuilder();
        List<String> sourcesverified = new ArrayList<>();
        LinkedHashMap<String, Object> kernelVersionFromSource = new LinkedHashMap<>();
        if (!PacmanUtils.doesAllHaveValue(sourceType, userName, sshPd,severity, category, ldapApi, satAndSpacewalkApi, kernelInfoApi,accNames, tagsSplitter, kernelVersionByInstanceIdUrl,defaultKernelCriteriaUrl)) {
            logger.info(PacmanRuleConstants.MISSING_CONFIGURATION);
            throw new InvalidInputException(PacmanRuleConstants.MISSING_CONFIGURATION);
        }

        if (resourceAttributes != null) {
            String accountName = resourceAttributes.get(PacmanRuleConstants.ACCOUNT_NAME);
            if ("running".equalsIgnoreCase(resourceAttributes.get("statename"))&& (!resourceAttributes.get(PacmanRuleConstants.PLATFORM).equals(PacmanRuleConstants.PLATFORM_VAL))) {
                instanceId = resourceAttributes.get(PacmanRuleConstants.INSTANCEID);
                ipAddress = resourceAttributes.get(PacmanRuleConstants.PRIVATE_IP_ADDRESS);
                List<String> accountNames = PacmanUtils.splitStringToAList(accNames, tagsSplitter);
                List<String> sourceTypesList = PacmanUtils.splitStringToAList(sourceType, tagsSplitter);
                MDC.put("_resourceid", instanceId);
                MDC.put("applicationname",resourceAttributes.get("tags.Application"));
                MDC.put("accountname", accountName);
                boolean isAccountExists = PacmanUtils.isAccountExists(accountNames, accountName);

                // Taking the Quaterly versions of the kernel versions using the
                // PACMAN API
                logger.info("calling PacMan API to get Kernel criteria");
                JsonObject kernelVersionFromPacmanTable = DefaultTargetCriteriaDataProvider.getInstance(defaultKernelCriteriaUrl).getTargetCriterianData();

                if (kernelVersionFromPacmanTable != null && !kernelVersionFromPacmanTable.entrySet().isEmpty()) {
                    Map<String, String> complianceMap = new HashMap<>();
                    HashMap<String, String> mapOfQuaterlyVersions = gson.fromJson(kernelVersionFromPacmanTable.toString(),HashMap.class);
                    Set<String> keySet = mapOfQuaterlyVersions.keySet();

                    for (String source : sourceTypesList) {
                        try {
                            isComplianceCheckPassed = checkCompliance(source,mapOfQuaterlyVersions, keySet, userName,sshPd, ipAddress, connectionPort,instanceId, isAccountExists, ldapApi,
                                    satAndSpacewalkApi, kernelInfoApi,
                                    kernelVersionByInstanceIdUrl, complianceMap);
                        } catch (Exception e) {
                            logger.error("error"+e.getMessage());
                            throw new RuleExecutionFailedExeption(e.getMessage());
                        }
                        if (!isComplianceCheckPassed) {
                            sourcesverified.add(source);
                            if (null == kernelversion)
                                kernelversion = "Kernel not found";
                            kernelVersionFromSource.put(source, kernelversion);
                            listOfServersWhereComplianceCheckFailed.add(source);
                            
                            if (description.length() > 0) {
                                description.append("/").append(source);
                            } else {
                                description.append(source);
                            }

                        } else {
                            isEligibleForAnnotation = false;
                            break;
                        }
                    }

                    if (!listOfServersWhereComplianceCheckFailed.isEmpty() && isEligibleForAnnotation) {
                        annotation = Annotation.buildAnnotation(ruleParam, Annotation.Type.ISSUE);
                        if (kernelMap.size() == sourceTypesList.size()) {
                            kernelMap = new HashMap<>();
                            annotation.put(PacmanSdkConstants.DESCRIPTION, "Kernel version not found." + "validated using:" + description);

                        } else {
                            annotation.put(PacmanSdkConstants.DESCRIPTION, "Kernel version not compliant." + "validated using:" + description);
                        }
                        annotation.put(PacmanRuleConstants.SEVERITY, severity);
                        annotation.put(PacmanRuleConstants.CATEGORY, category);
                        annotation.put(PacmanRuleConstants.FAILED_TYPES,listOfServersWhereComplianceCheckFailed.toString());
                        // Issue Details
                        issue.put(PacmanRuleConstants.VIOLATION_REASON, "ResourceId " + instanceId + " is not patched with latest update");

                        issue.put(PacmanRuleConstants.SOURCE_VERIFIED, String.join(",", sourcesverified));
                        issue.put("kernel_version_from_sources", gson.toJson(kernelVersionFromSource));
                        issueList.add(issue);
                        annotation.put("issueDetails", issueList.toString());
                        logger.debug("==KernelComplianceRule ended with annotation : {}===",annotation);
                        return new RuleResult(PacmanSdkConstants.STATUS_FAILURE,PacmanRuleConstants.FAILURE_MESSAGE, annotation);
                    } else {
                        return new RuleResult(PacmanSdkConstants.STATUS_SUCCESS, complianceMap.toString());
                    }
                } else {
                    logger.info("target kernel criteria not maintained");

                    // If Target Kernel Version not maintained create an issue
                    annotation = Annotation.buildAnnotation(ruleParam, Annotation.Type.ISSUE);
                    annotation.put(PacmanSdkConstants.DESCRIPTION,"Target Kernerl Criteria not maintained");
                    annotation.put(PacmanRuleConstants.SEVERITY, severity);
                    annotation.put(PacmanRuleConstants.CATEGORY, category);
                    issue.put(PacmanRuleConstants.VIOLATION_REASON,PacmanRuleConstants.NO_DEFAULT_TARGET);
                    issueList.add(issue);

                    annotation.put("issueDetails", issueList.toString());
                    logger.debug("==KernelComplianceRule ended with annotation : {}===",annotation);
                    return new RuleResult(PacmanSdkConstants.STATUS_FAILURE,PacmanRuleConstants.FAILURE_MESSAGE, annotation);
                }
            } else {
                logger.info(resourceAttributes.get(PacmanRuleConstants.INSTANCEID)+ " stopped/windows instance");
            }

        }
        logger.debug("==KernelComplianceRule ended===");
        return new RuleResult(PacmanSdkConstants.STATUS_SUCCESS,PacmanRuleConstants.SUCCESS_MESSAGE);
    }

}