package dst.ass3.elastic.impl;

import dst.ass3.elastic.ContainerException;
import dst.ass3.elastic.ContainerInfo;
import dst.ass3.elastic.IContainerService;
import dst.ass3.elastic.IElasticityController;
import dst.ass3.messaging.IWorkloadMonitor;
import dst.ass3.messaging.RequestType;

import java.util.List;
import java.util.Map;

public class ElasticityController implements IElasticityController {
    final static double alpha = 0.1;
    final static double omega = 0.05;
    private IContainerService containerService;
    private IWorkloadMonitor workloadMonitor;

    public ElasticityController(IContainerService containerService, IWorkloadMonitor workloadMonitor) {
        this.containerService = containerService;
        this.workloadMonitor = workloadMonitor;
    }

    @Override
    public void adjustWorkers() throws ContainerException {
        Map<RequestType, Long> workers = workloadMonitor.getWorkerCount();
        Map<RequestType, Long> reqs = workloadMonitor.getRequestCount();
        Map<RequestType, Double> avg = workloadMonitor.getAverageProcessingTime();

        for (RequestType t : workers.keySet()) {
            // do weird math.
            double k = workers.get(t);
            double q = reqs.get(t);
            double r10 = avg.get(t);
            double rMax = (t == RequestType.VIDEO) ? 120000.0 : 30000.0; // 30 sec or 120 sec for videos.

            double rExp = r10 * (double) q / k;

            if (rExp > (rMax * (1.0 + alpha))) {
                while (((r10 * q) / (k)) > rMax) {
                    //if (containerService.startWorker(t).isRunning()) k++; // FIXME: DOES NOT WORK - mock doesnt seem to return a valid container info.
                    containerService.startWorker(t);
                    k++;
                }
            }
            if (rExp < (rMax * (1.0 - omega))) {
                List<ContainerInfo> cl = containerService.listContainers();
                while ((((r10 * q) / (k)) < rMax) && k > 0) {
                    for (ContainerInfo ci : cl) {
                        if (ci.getWorkerType() == t) {
                            containerService.stopContainer(ci.getContainerId());
                            k--;
                            break;
                        }
                    }
                }
            }
        }
    }
}
