// Path: id-registry/src/main/java/com/palominolabs/benchpress/job/id/Identifiable.java
// public interface Identifiable {
// 
//     /**
//      * @return the id to use to store this in a registry. Id must be unique among all plugins that are currently
//      * enabled, so using a reverse domain or similar is suggested.
//      */
//     @Nonnull
//     String getRegistryId();
// }
// 
// Path: job/src/main/java/com/palominolabs/benchpress/job/json/Task.java
// public final class Task {
//     private final String taskType;
// 
//     private final JsonNode configNode;
// 
//     /**
//      * @param taskType   task type
//      * @param configNode config json. This claims ownership of the node object.
//      */
//     @JsonCreator
//     public Task(@JsonProperty("type") String taskType, @JsonProperty("config") JsonNode configNode) {
//         this.taskType = taskType;
//         this.configNode = configNode;
//     }
// 
//     /**
//      * Don't mess with this JsonNode; just read from it.
//      *
//      * @return json node representing the config data. {@link ComponentFactory} implementations should deserialize as
//      * they see fit.
//      */
//     @JsonProperty("config")
//     public JsonNode getConfigNode() {
//         return this.configNode;
//     }
// 
//     /**
//      * Should match the {@link Identifiable} implementation on a {@link ComponentFactory}
//      *
//      * @return the task type
//      */
//     @JsonProperty("type")
//     public String getTaskType() {
//         return taskType;
//     }
// }
// 
// Path: job/src/main/java/com/palominolabs/benchpress/job/task/JobSlicer.java
// public interface JobSlicer {
// 
//     /**
//      * Split this job into slices, one for each worker.
//      *
//      * @param jobId        the job id being sliced
//      * @param workers      The number of slices to create
//      * @param progressUrl  The URL to send progress reports to
//      * @param finishedUrl  The URL to send finished report to
//      * @param objectReader objectReader configured like objectWriter
//      * @param objectWriter objectWriter to use to serialize slice task config
//      * @return List of the slices
//      * @throws IOException if slicing fails
//      */
//     @Nonnull
//     List<Task> slice(UUID jobId, int workers, String progressUrl, String finishedUrl,
//                      ObjectReader objectReader, ObjectWriter objectWriter) throws IOException;
// }


import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectReader;
import com.fasterxml.jackson.databind.ObjectWriter;
import com.fasterxml.jackson.databind.util.TokenBuffer;
import com.palominolabs.benchpress.job.id.Identifiable;
import com.palominolabs.benchpress.job.json.Task;
import com.palominolabs.benchpress.job.task.JobSlicer;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import javax.annotation.Nonnull;
package com.palominolabs.benchpress.example.multidb.task;


/**
 * Convenience base class for TaskFactoryFactory / JobSlicer implementations that use TaskConfigBase subclasses.
 */
public abstract class JobSlicerBase implements JobSlicer {

    @Nonnull
    @Override
    public List<Task> slice(UUID jobId, int workers, String progressUrl, String finishedUrl,
                            ObjectReader objectReader, ObjectWriter objectWriter) throws IOException {

        TaskConfigBase c = getConfig();

        List<Task> tasks = new ArrayList<>();

        int quantaPerSlice = (int) Math.ceil(c.getNumQuanta() / workers);
        for (int sliceId = 0; sliceId < workers; sliceId++) {
            int newQuanta;
            // TODO
            if (sliceId == workers) {
                newQuanta = quantaPerSlice;
            } else {
                newQuanta = c.getNumQuanta() - quantaPerSlice * (workers - 1);
            }

            TaskConfigBase newConfig = c.withNewQuanta(newQuanta);

            TokenBuffer tokBuf = new TokenBuffer(objectReader, false);
            objectWriter.writeValue(tokBuf, newConfig);
            JsonParser jp = tokBuf.asParser();
            JsonNode newJsonNode =
                    objectReader.readValue(jp, JsonNode.class);
            jp.close();

// Path: id-registry/src/main/java/com/palominolabs/benchpress/job/id/Identifiable.java
// public interface Identifiable {
// 
//     /**
//      * @return the id to use to store this in a registry. Id must be unique among all plugins that are currently
//      * enabled, so using a reverse domain or similar is suggested.
//      */
//     @Nonnull
//     String getRegistryId();
// }
// 
// Path: job/src/main/java/com/palominolabs/benchpress/job/json/Task.java
// public final class Task {
//     private final String taskType;
// 
//     private final JsonNode configNode;
// 
//     /**
//      * @param taskType   task type
//      * @param configNode config json. This claims ownership of the node object.
//      */
//     @JsonCreator
//     public Task(@JsonProperty("type") String taskType, @JsonProperty("config") JsonNode configNode) {
//         this.taskType = taskType;
//         this.configNode = configNode;
//     }
// 
//     /**
//      * Don't mess with this JsonNode; just read from it.
//      *
//      * @return json node representing the config data. {@link ComponentFactory} implementations should deserialize as
//      * they see fit.
//      */
//     @JsonProperty("config")
//     public JsonNode getConfigNode() {
//         return this.configNode;
//     }
// 
//     /**
//      * Should match the {@link Identifiable} implementation on a {@link ComponentFactory}
//      *
//      * @return the task type
//      */
//     @JsonProperty("type")
//     public String getTaskType() {
//         return taskType;
//     }
// }
// 
// Path: job/src/main/java/com/palominolabs/benchpress/job/task/JobSlicer.java
// public interface JobSlicer {
// 
//     /**
//      * Split this job into slices, one for each worker.
//      *
//      * @param jobId        the job id being sliced
//      * @param workers      The number of slices to create
//      * @param progressUrl  The URL to send progress reports to
//      * @param finishedUrl  The URL to send finished report to
//      * @param objectReader objectReader configured like objectWriter
//      * @param objectWriter objectWriter to use to serialize slice task config
//      * @return List of the slices
//      * @throws IOException if slicing fails
//      */
//     @Nonnull
//     List<Task> slice(UUID jobId, int workers, String progressUrl, String finishedUrl,
//                      ObjectReader objectReader, ObjectWriter objectWriter) throws IOException;
// }


// Path: examples/multi-db/job-default-base/src/main/java/com/palominolabs/benchpress/example/multidb/task/JobSlicerBase.java
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectReader;
import com.fasterxml.jackson.databind.ObjectWriter;
import com.fasterxml.jackson.databind.util.TokenBuffer;
import com.palominolabs.benchpress.job.id.Identifiable;
import com.palominolabs.benchpress.job.json.Task;
import com.palominolabs.benchpress.job.task.JobSlicer;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import javax.annotation.Nonnull;

package com.palominolabs.benchpress.example.multidb.task;


/**
 * Convenience base class for TaskFactoryFactory / JobSlicer implementations that use TaskConfigBase subclasses.
 */
public abstract class JobSlicerBase implements JobSlicer {

    @Nonnull
    @Override
    public List<Task> slice(UUID jobId, int workers, String progressUrl, String finishedUrl,
                            ObjectReader objectReader, ObjectWriter objectWriter) throws IOException {

        TaskConfigBase c = getConfig();

        List<Task> tasks = new ArrayList<>();

        int quantaPerSlice = (int) Math.ceil(c.getNumQuanta() / workers);
        for (int sliceId = 0; sliceId < workers; sliceId++) {
            int newQuanta;
            // TODO
            if (sliceId == workers) {
                newQuanta = quantaPerSlice;
            } else {
                newQuanta = c.getNumQuanta() - quantaPerSlice * (workers - 1);
            }

            TaskConfigBase newConfig = c.withNewQuanta(newQuanta);

            TokenBuffer tokBuf = new TokenBuffer(objectReader, false);
            objectWriter.writeValue(tokBuf, newConfig);
            JsonParser jp = tokBuf.asParser();
            JsonNode newJsonNode =
                    objectReader.readValue(jp, JsonNode.class);
            jp.close();

            Task task = new Task(getTaskType(), newJsonNode);