package org.jenkinsci.plugins.ewm;

import hudson.AbortException;
import hudson.ExtensionList;
import hudson.ExtensionPoint;
import hudson.model.AbstractDescribableImpl;
import org.jenkinsci.plugins.ewm.definitions.Disk;
import org.kohsuke.accmod.Restricted;
import org.kohsuke.accmod.restrictions.NoExternalUse;

import javax.annotation.Nonnull;
import java.io.File;
import java.io.IOException;
import java.util.List;

/**
 * Abstract class for defining a disk allocation strategy.
 * Each disk allocation strategy should extend this class and provide its own implementation of disk allocation.
 *
 * @author Alexandru Somai
 */
public abstract class DiskAllocationStrategy extends AbstractDescribableImpl<DiskAllocationStrategy> implements ExtensionPoint {

    private long estimatedWorkspaceSize;

    /**
     * @return all registered {@link DiskAllocationStrategy}s.
     */
    @Nonnull
    public static ExtensionList<DiskAllocationStrategy> all() {
        return ExtensionList.lookup(DiskAllocationStrategy.class);
    }

    /**
     * @return the registered {@link DiskAllocationStrategyDescriptor}s for the {@link DiskAllocationStrategy}.
     */
    @Nonnull
    public static ExtensionList<DiskAllocationStrategyDescriptor> allDescriptors() {
        return ExtensionList.lookup(DiskAllocationStrategyDescriptor.class);
    }

    /**
     * Allocates a disk from the given list. The list contains at least one {@link Disk} entry.
     *
     * @param disks the entries from which to allocate a disk. The list has at least one element
     * @return the selected disk
     * @throws IOException if any mandatory field is missing from the {@link Disk} entry,
     *                     or if the disk allocation fails for any reason
     */
    @Nonnull
    public abstract Disk allocateDisk(@Nonnull List<Disk> disks) throws IOException;

    /**
     * Calculates the usable space for the given {@link Disk} entry.
     * It uses the mounting point property that is defined in the Jenkins global config for each Disk.
     *
     * @param disk the disk entry
     * @return the usable space for the disk
     * @throws IOException       if mounting point from Jenkins Master to Disk is {@code null}
     * @throws SecurityException if the method can't retrieve the usable space for security reasons
     * @see File#getUsableSpace
     */
    @Restricted(NoExternalUse.class)
    public long retrieveUsableSpace(Disk disk) throws IOException {
        String masterMountPoint = disk.getMasterMountPoint();
        if (masterMountPoint == null) {
            String message = String.format("Mounting point from Master to the disk is not defined for Disk ID '%s'", disk.getDiskId());
            throw new AbortException(message);
        }

        return new File(masterMountPoint).getUsableSpace();
    }

    public long getEstimatedWorkspaceSize() {
        return estimatedWorkspaceSize;
    }

    public void setEstimatedWorkspaceSize(long estimatedWorkspaceSize) {
        this.estimatedWorkspaceSize = estimatedWorkspaceSize;
    }

    /**
     * Assuming that the {@link #estimatedWorkspaceSize} is provided by the user in MB,
     * this method returns the size in KB (multiplied by 1024).
     *
     * @return the estimated workspace size in KB (multiplied by 1024)
     */
    public long getEstimatedWorkspaceSizeInKilobytes() {
        return estimatedWorkspaceSize * 1024;
    }
}

@@ -2140,22 +2140,16 @@
 ception 
-      
 if mount
@@ -2171,17 +2171,17 @@
 Jenkins 
-M
+m
 aster to
@@ -2201,24 +2201,28 @@
 de null%7D
+, or
 %0A     * 
 @throws 
@@ -2217,62 +2217,65 @@
   * 
-@throws SecurityException if the method
+                    if the usable space
  can't 
+be 
 retrieve
  the
@@ -2270,33 +2270,17 @@
 retrieve
- the usable space
+d
  for sec
@@ -2730,24 +2730,42 @@
 %0A        %7D%0A%0A
+        try %7B%0A    
         retu
@@ -2808,24 +2808,221 @@
 bleSpace();%0A
+        %7D catch (SecurityException e) %7B%0A            throw new AbortException(String.format(%22Can't retrieve usable space for Disk ID '%25s' because of security reasons%22, disk.getDiskId()));%0A        %7D%0A
     %7D%0A%0A    p

Handle SecurityException when retrieving Disk's usable space