class ResourceDimensions {

    public static Pair<Long, ResourceDimension> divide(ResourceDimension left, ResourceDimension right) {
        double multiplier = 0;

        if (left.getCpu() != 0) {
            Preconditions.checkArgument(right.getCpu() != 0, "CPU: division by 0");
            multiplier = left.getCpu() / right.getCpu();
        }
        if (left.getMemoryMB() != 0) {
            Preconditions.checkArgument(right.getMemoryMB() != 0, "MemoryMB: division by 0");
            multiplier = Math.max(multiplier, left.getMemoryMB() / right.getMemoryMB());
        }
        if (left.getDiskMB() != 0) {
            Preconditions.checkArgument(right.getDiskMB() != 0, "DiskMB: division by 0");
            multiplier = Math.max(multiplier, left.getDiskMB() / right.getDiskMB());
        }
        if (left.getNetworkMbs() != 0) {
            Preconditions.checkArgument(right.getNetworkMbs() != 0, "NetworkMbs: division by 0");
            multiplier = Math.max(multiplier, left.getNetworkMbs() / right.getNetworkMbs());
        }
        if (left.getGpu() != 0) {
            Preconditions.checkArgument(right.getGpu() != 0, "GPU: division by 0");
            multiplier = Math.max(multiplier, left.getGpu() / right.getGpu());
        }
        if (left.getOpportunisticCpu() != 0) {
            Preconditions.checkArgument(right.getOpportunisticCpu() != 0, "Opportunistic CPU: division by 0");
            multiplier = Math.max(multiplier, left.getOpportunisticCpu() / right.getOpportunisticCpu());
        }

        if (multiplier == 0) { // left is empty
            return Pair.of(0L, ResourceDimension.empty());
        }
        if (multiplier < 1) { // left < right
            return Pair.of(0L, left);
        }
        if (multiplier == 1) {
            return Pair.of(1L, ResourceDimension.empty());
        }

        long full = (long) multiplier;

        return Pair.of(full,
                ResourceDimension.newBuilder()
                        .withCpus(Math.max(0, left.getCpu() - right.getCpu() * full))
                        .withMemoryMB(Math.max(0, left.getMemoryMB() - right.getMemoryMB() * full))
                        .withDiskMB(Math.max(0, left.getDiskMB() - right.getDiskMB() * full))
                        .withNetworkMbs(Math.max(0, left.getNetworkMbs() - right.getNetworkMbs() * full))
                        .withGpu(Math.max(0, left.getGpu() - right.getGpu() * full))
                        .withOpportunisticCpus(Math.max(0, left.getOpportunisticCpu() - right.getOpportunisticCpu() * full))
                        .build()
        );
    }

}