package com.atlassian.stash.internal.maintenance;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.annotation.Nonnull;
import java.util.concurrent.atomic.AtomicReference;

import static com.google.common.base.Preconditions.checkNotNull;

/**
 * An implementation of {@link MaintenanceTaskStatusSupplier} which holds the status in a local atomic reference
 *
 * @since 3.5
 */
public class LocalMaintenanceTaskStatusSupplier implements MaintenanceTaskStatusSupplier {

    private static final Logger log = LoggerFactory.getLogger(LocalMaintenanceTaskStatusSupplier.class);

    private final AtomicReference<MaintenanceTaskStatus> statusRef = new AtomicReference<>();

    @Override
    public MaintenanceTaskStatus get() {
        return statusRef.get();
    }

    @Override
    public void set(@Nonnull MaintenanceTaskStatus status) {
        checkNotNull(status, "status");
        MaintenanceTaskStatus existing;
        do {
            existing = statusRef.get();
            // Only update the status if the task IDs match or the new status is for a more recent maintenance
            // task. This helps to handle when a split brain occurs and a node cannot keep up to date with
            // the latest status
            if (existing != null && !existing.getId().equals(status.getId()) &&
                    existing.getStartTime().after(status.getStartTime())) {
                log.warn("Ignoring maintenance task status {} as existing status {} is newer",
                        status, existing);
                break;
            }
        } while (!statusRef.compareAndSet(existing, status));
    }

}
