// Path: CutletLib/src/main/java/com/cutlet/lib/errors/EmptyProjectException.java
// public class EmptyProjectException extends OptimizationFailedException {
// 
//     /**
//      * Creates a new instance of <code>EmptyProjectException</code> without
//      * detail message.
//      */
//     public EmptyProjectException() {
//     }
// 
//     /**
//      * Constructs an instance of <code>EmptyProjectException</code> with the
//      * specified detail message.
//      *
//      * @param msg the detail message.
//      */
//     public EmptyProjectException(String msg) {
//         super(msg);
//     }
// }
// 
// Path: CutletLib/src/main/java/com/cutlet/lib/errors/OptimizationFailedException.java
// public class OptimizationFailedException extends Exception {
// 
//     /**
//      * Creates a new instance of <code>OptimizationFailedException</code>
//      * without detail message.
//      */
//     public OptimizationFailedException() {
//     }
// 
//     /**
//      * Constructs an instance of <code>OptimizationFailedException</code> with
//      * the specified detail message.
//      *
//      * @param msg the detail message.
//      */
//     public OptimizationFailedException(String msg) {
//         super(msg);
//     }
//     
//     public OptimizationFailedException(Throwable other) {
//         super(other);
//     }
// }
// 
// Path: CutletLib/src/main/java/com/cutlet/lib/model/Project.java
// public class Project implements Serializable {
// 
//     private List<Panel> panels = new ArrayList<>();
//     private double bladeWidth = 3;
//     private Optional<OptimizationResult> optimizationResult;
// 
//     public List<Panel> getPanels() {
//         return panels;
//     }
// 
//     public void setPanels(@NonNull final List<Panel> inputs) {
//         this.panels = inputs;
//     }
// 
//     public double getBladeWidth() {
//         return bladeWidth;
//     }
// 
//     public void setBladeWidth(final double bladeWidth) {
//         checkArgument(bladeWidth >= 0, "bladeWidth can't be negative");
//         this.bladeWidth = bladeWidth;
//     }
// 
//     public Optional<OptimizationResult> getOptimizationResult() {
//         return optimizationResult;
//     }
// 
//     public void setOptimizationResult(@NonNull final Optional<OptimizationResult> optimizationResult) {
//         this.optimizationResult = optimizationResult;
//     }
// 
//     public void setOptimizationResult(java.util.Optional<OptimizationResult> newValue) {
//         if (newValue.isPresent()) {
//             this.optimizationResult = Optional.of(newValue.get());
// 
//         } else {
//             this.optimizationResult = Optional.absent();
// 
//         }
//     }
// 
//     public List<PanelInstance> getPanelInstances() {
//         List<PanelInstance> pis = new ArrayList<>();
//         for (Panel p : panels) {
//             for (int i = 0; i < p.getCount(); i++) {
//                 pis.add(new PanelInstance(p.getSheet(), p.getDimension(), p.getTitle(), i, p.canRotate()));
//             }
//         }
//         return pis;
//     }
// }


import com.cutlet.lib.errors.EmptyProjectException;
import com.cutlet.lib.errors.OptimizationFailedException;
import com.cutlet.lib.model.Project;
import com.google.common.base.Stopwatch;
import java.util.concurrent.TimeUnit;
import java.util.logging.Logger;
import lombok.NonNull;

/*
 * Copyright (C) 2017 rudolf.muehlbauer@gmail.com
 */
package com.cutlet.lib.optimizer;


/**
 *
 * @author rmuehlba
 */
public class Optimizer {
    
    private static final Logger log = Logger.getLogger("Optimizer");
    
    public OptimizationResult optimize(@NonNull Project project, @NonNull OptimizationStrategy strategy) throws OptimizationFailedException {
        
        if (project.getPanels().isEmpty()) {

// Path: CutletLib/src/main/java/com/cutlet/lib/errors/EmptyProjectException.java
// public class EmptyProjectException extends OptimizationFailedException {
// 
//     /**
//      * Creates a new instance of <code>EmptyProjectException</code> without
//      * detail message.
//      */
//     public EmptyProjectException() {
//     }
// 
//     /**
//      * Constructs an instance of <code>EmptyProjectException</code> with the
//      * specified detail message.
//      *
//      * @param msg the detail message.
//      */
//     public EmptyProjectException(String msg) {
//         super(msg);
//     }
// }
// 
// Path: CutletLib/src/main/java/com/cutlet/lib/errors/OptimizationFailedException.java
// public class OptimizationFailedException extends Exception {
// 
//     /**
//      * Creates a new instance of <code>OptimizationFailedException</code>
//      * without detail message.
//      */
//     public OptimizationFailedException() {
//     }
// 
//     /**
//      * Constructs an instance of <code>OptimizationFailedException</code> with
//      * the specified detail message.
//      *
//      * @param msg the detail message.
//      */
//     public OptimizationFailedException(String msg) {
//         super(msg);
//     }
//     
//     public OptimizationFailedException(Throwable other) {
//         super(other);
//     }
// }
// 
// Path: CutletLib/src/main/java/com/cutlet/lib/model/Project.java
// public class Project implements Serializable {
// 
//     private List<Panel> panels = new ArrayList<>();
//     private double bladeWidth = 3;
//     private Optional<OptimizationResult> optimizationResult;
// 
//     public List<Panel> getPanels() {
//         return panels;
//     }
// 
//     public void setPanels(@NonNull final List<Panel> inputs) {
//         this.panels = inputs;
//     }
// 
//     public double getBladeWidth() {
//         return bladeWidth;
//     }
// 
//     public void setBladeWidth(final double bladeWidth) {
//         checkArgument(bladeWidth >= 0, "bladeWidth can't be negative");
//         this.bladeWidth = bladeWidth;
//     }
// 
//     public Optional<OptimizationResult> getOptimizationResult() {
//         return optimizationResult;
//     }
// 
//     public void setOptimizationResult(@NonNull final Optional<OptimizationResult> optimizationResult) {
//         this.optimizationResult = optimizationResult;
//     }
// 
//     public void setOptimizationResult(java.util.Optional<OptimizationResult> newValue) {
//         if (newValue.isPresent()) {
//             this.optimizationResult = Optional.of(newValue.get());
// 
//         } else {
//             this.optimizationResult = Optional.absent();
// 
//         }
//     }
// 
//     public List<PanelInstance> getPanelInstances() {
//         List<PanelInstance> pis = new ArrayList<>();
//         for (Panel p : panels) {
//             for (int i = 0; i < p.getCount(); i++) {
//                 pis.add(new PanelInstance(p.getSheet(), p.getDimension(), p.getTitle(), i, p.canRotate()));
//             }
//         }
//         return pis;
//     }
// }


// Path: CutletLib/src/main/java/com/cutlet/lib/optimizer/Optimizer.java
import com.cutlet.lib.errors.EmptyProjectException;
import com.cutlet.lib.errors.OptimizationFailedException;
import com.cutlet.lib.model.Project;
import com.google.common.base.Stopwatch;
import java.util.concurrent.TimeUnit;
import java.util.logging.Logger;
import lombok.NonNull;

/*
 * Copyright (C) 2017 rudolf.muehlbauer@gmail.com
 */
package com.cutlet.lib.optimizer;


/**
 *
 * @author rmuehlba
 */
public class Optimizer {
    
    private static final Logger log = Logger.getLogger("Optimizer");
    
    public OptimizationResult optimize(@NonNull Project project, @NonNull OptimizationStrategy strategy) throws OptimizationFailedException {
        
        if (project.getPanels().isEmpty()) {

            throw new EmptyProjectException("Project doesn't have any panels configured; nothing to optimize");
