package br.ufrgs.inf.prosoft.adaptivecaching.analysis.decision.flowchart.stats;

import br.ufrgs.inf.prosoft.adaptivecaching.analysis.decision.CacheDecider;
import br.ufrgs.inf.prosoft.adaptivecaching.analysis.decision.flowchart.FlowchartWorkFlow;
import br.ufrgs.inf.prosoft.adaptivecaching.analysis.decision.flowchart.model.MethodStats;
import br.ufrgs.inf.prosoft.tigris.monitoring.metadata.MethodInfo;
import br.ufrgs.inf.prosoft.adaptivecaching.cache.CacheInfo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Optional;

/**
 * TODO flowchart paper link
 *
 * @see
 */
public class CacheabilityPatternDecider implements CacheDecider {

    private final int population;
    /**
     * The Logger.
     */
    Logger logger = LoggerFactory.getLogger(CacheabilityPatternDecider.class);

    /**
     * The Workflow.
     */
    FlowchartWorkFlow workflow;

    /**
     * Instantiates a new Cacheability pattern decider.
     *
     * @param size     the size
     * @param workflow the workflow
     */
    public CacheabilityPatternDecider(int size, FlowchartWorkFlow workflow) {
        this.workflow = workflow;
        this.population = size;
    }

    /**
     * Flowchart definition
     *
     * @param methodStats
     * @return
     */
    @Override
    public boolean isCacheable(CacheInfo cacheInfo, MethodInfo methodInfo, MethodStats methodStats) {

        //used more than once, in many parts of the reasoning
        Optional<Boolean> isCacheSizeLarge = CacheabilityMetrics.isCacheSizeLarge(cacheInfo);


        //Is the data completely static?
        Optional<Boolean> isStaticData = CacheabilityMetrics.isStaticData(methodStats, workflow, population);
        if (isStaticData.isPresent() && isStaticData.get()) { // staticity yes

            Optional<Boolean> isDataSizeLarge = CacheabilityMetrics.isDataSizeLarge(cacheInfo, methodInfo);
            if (isDataSizeLarge.isPresent() && !isDataSizeLarge.get()) {
                return true;
            } else {
                if (isCacheSizeLarge.isPresent() && isCacheSizeLarge.get()) {
                    return true;
                } else {
                    return false;
                }
            }
        } else { // staticity no/not sure

            Optional<Boolean> changeMoreThanUsed = CacheabilityMetrics.changeMoreThanUsed(methodStats, workflow);
            if (changeMoreThanUsed.isPresent() && changeMoreThanUsed.get()) { //changeMoreThanUsed true
                return false;
            } else { //changeMoreThanUsed not/not sure
                Optional<Boolean> usedByManyRequests = CacheabilityMetrics.usedByManyRequests(methodStats, workflow, population);
                if (usedByManyRequests.isPresent() && !usedByManyRequests.get()) { //useByManyRequests no
                    return false;
                } else {
                    Optional<Boolean> isUserSpecific = CacheabilityMetrics.isUserSpecific(methodStats, workflow);
                    if (isUserSpecific.isPresent() && isUserSpecific.get()) {
                        if (isCacheSizeLarge.isPresent() && isCacheSizeLarge.get()) {
                            return true;
                        } else {
                            return false;
                        }
                    } else {
                        Optional<Boolean> isExpensive = CacheabilityMetrics.isExpensive(methodStats, workflow);
                        if (!isExpensive.isPresent()) {

                            if (isCacheSizeLarge.isPresent() && isCacheSizeLarge.get()) {
                                return true;
                            } else {
                                return false;
                            }
                        } else {
                            if (isExpensive.get()) {
                                return true;
                            } else {
                                return false;
                            }
                        }
                    }
                }
            }
        }
    }
}
