package org.alien4cloud.server;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.annotation.Resource;
import javax.inject.Inject;

import org.alien4cloud.server.MaintenanceModeState.MaintenanceLog;
import org.springframework.stereotype.Service;

import com.google.common.collect.Lists;

import alien4cloud.dao.IGenericSearchDAO;
import alien4cloud.exception.AlreadyExistException;
import alien4cloud.exception.NotFoundException;
import alien4cloud.webconfiguration.MaintenanceFilter;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;

/**
 * Service that manage maintenance mode enablement.
 */
@Slf4j
@Service
public class MaintenanceModeService {
    @Resource(name = "alien-es-dao")
    private IGenericSearchDAO dao;
    @Inject
    private MaintenanceFilter maintenanceFilter;

    @Getter
    private MaintenanceModeState maintenanceModeState = null;

    @PostConstruct
    public void init() {
        // Load the maintenance mode state from elasticsearch if any
        maintenanceFilter.setMaintenanceModeService(this);
        maintenanceModeState = dao.findById(MaintenanceModeState.class, MaintenanceModeState.MMS_ID);
        if (maintenanceModeState != null) {
            log.info("Maintenance mode is enabled");
        }
    }

    @PreDestroy
    public void destroy() {
        maintenanceFilter.setMaintenanceModeService(null);
    }

    public boolean isMaintenanceModeEnabled() {
        return maintenanceModeState != null;
    }

    /**
     * Enable the maintenance mode.
     * 
     * @param user Name of the user that enabled the maintenance mode.
     */
    public synchronized void enable(String user) {
        doEnable(user, true);
    }

    /**
     * Let an internal process enable the maintenance mode.
     *
     * @param process Name of the process that enabled the maintenance mode.
     */
    public synchronized void internalEnable(String process) {
        doEnable(process, false);
    }

    private void doEnable(String ownerName, boolean isUser) {
        if (isMaintenanceModeEnabled()) {
            throw new AlreadyExistException("Maintenance mode is already enabled.");
        }

        log.info("Maintenance mode is enabled");

        this.maintenanceModeState = new MaintenanceModeState();
        this.maintenanceModeState.setUser(ownerName);
        this.maintenanceModeState.setUserTriggered(isUser);
        this.maintenanceModeState.setProgressPercent(1);
        this.maintenanceModeState.setLog(Lists.newArrayList(new MaintenanceLog(ownerName, "Maintenance operation started on alien4cloud.")));

        this.dao.save(maintenanceModeState);
    }

    /**
     * Update the current state of the maintenance mode.
     * 
     * @param user Name of the user that performed the update.
     * @param message A message to update the maintenance.
     * @param progressPercentage The new percentage of the maintenance.
     */
    public synchronized void update(String user, String message, Integer progressPercentage) {
        if (maintenanceModeState == null) {
            throw new NotFoundException("Maintenance mode is not enabled.");
        }
        if (!maintenanceModeState.isUserTriggered()) {
            throw new IllegalAccessError("Maintenance mode has not been enabled by a user, you are not allowed to update it.");
        }

    }

    /**
     * Let an internal process update the current state of the maintenance.
     *
     * @param process Name of the process.
     * @param message A message to update the maintenance.
     * @param progressPercentage The new percentage of the maintenance.
     */
    public synchronized void internalUpdate(String process, String message, Integer progressPercentage) {
        if (maintenanceModeState == null) {
            throw new NotFoundException("Maintenance mode is not enabled.");
        }

        doUpdate(process, message, progressPercentage);
    }

    private void doUpdate(String user, String message, Integer progressPercentage) {
        if (message != null) {
            this.maintenanceModeState.getLog().add(new MaintenanceLog(user, message));
        }
        if (progressPercentage != null) {
            this.maintenanceModeState.setProgressPercent(progressPercentage);
        }

        this.dao.save(maintenanceModeState);
    }

    /**
     * Disable a maintenance started by a user.
     */
    public synchronized void disable() {
        if (maintenanceModeState == null) {
            throw new NotFoundException("Maintenance mode is not enabled.");
        }
        if (!maintenanceModeState.isUserTriggered()) {
            throw new IllegalAccessError("Maintenance mode has not been enabled by a user, you are not allowed to disable it.");
        }

        internalDisable();
    }

    /**
     * Let internal process disable maintenance mode.
     */
    public synchronized void internalDisable() {
        if (maintenanceModeState == null) {
            return;
        }

        this.dao.delete(MaintenanceModeState.class, maintenanceModeState.getId());
        this.maintenanceModeState = null;

        log.info("Maintenance mode is disabled");
    }
}
@@ -3347,24 +3347,76 @@
 ;%0A        %7D%0A
+        doUpdate(user, message, progressPercentage);
 %0A    %7D%0A%0A    

Fix maintenance mode update.