// Path: src/main/java/nl/esciencecenter/ahn/pointcloud/core/Selection.java
// @ValidSelection
// public class Selection {
//     @NotNull
//     @JsonProperty
//     @ApiModelProperty(value="Most left or minimum x coordinate", example = "124931.360")
//     private Double left;
// 
//     @NotNull
//     @JsonProperty
//     @ApiModelProperty(value="Most bottom or minimum y coordinate", example = "484567.840")
//     private Double bottom;
// 
//     @NotNull
//     @JsonProperty
//     @ApiModelProperty(value="Most right or maximum x coordinate", example = "126241.760")
//     private Double right;
// 
//     @NotNull
//     @JsonProperty
//     @ApiModelProperty(value="Most top or maximum x coordinate", example = "485730.400")
//     private Double top;
// 
//     public Selection(Double left, Double bottom, Double right, Double top) {
//         this.left = left;
//         this.bottom = bottom;
//         this.right = right;
//         this.top = top;
//     }
// 
//     protected Selection() {
//     }
// 
//     public Double getLeft() {
//         return left;
//     }
// 
//     public Double getBottom() {
//         return bottom;
//     }
// 
//     public Double getRight() {
//         return right;
//     }
// 
//     public Double getTop() {
//         return top;
//     }
// 
//     public void setLeft(Double left) {
//         this.left = left;
//     }
// 
//     public void setBottom(Double bottom) {
//         this.bottom = bottom;
//     }
// 
//     public void setRight(Double right) {
//         this.right = right;
//     }
// 
//     public void setTop(Double top) {
//         this.top = top;
//     }
// 
//     @Override
//     public boolean equals(Object o) {
//         if (this == o) {return true;}
//         if (o == null || getClass() != o.getClass()) {return false;}
//         Selection selection = (Selection) o;
//         return Objects.equals(getLeft(), selection.getLeft()) &&
//                 Objects.equals(getBottom(), selection.getBottom()) &&
//                 Objects.equals(getRight(), selection.getRight()) &&
//                 Objects.equals(getTop(), selection.getTop());
//     }
// 
//     @Override
//     public int hashCode() {
//         return Objects.hash(getLeft(), getBottom(), getRight(), getTop());
//     }
// }
// 
// Path: src/main/java/nl/esciencecenter/ahn/pointcloud/core/Size.java
// public class Size {
//     @NotNull
//     @Range(min=0)
//     @ApiModelProperty(value="Approximate number of points in selection", example = "10193813")
//     private long rawPoints = 0;
// 
//     @NotNull
//     @Range(min=0)
//     @ApiModelProperty(value="Approximate number of points in selection which will be returned", example = "9234324")
//     private long returnedPoints = 0;
// 
//     @NotNull
//     @Range(min=0, max=24)
//     @ApiModelProperty(value=" Level in octree pyramid to fetch points from. Lower number means less points", example="8")
//     private int level;
// 
//     private Size() {
//     }
// 
//     public Size(long rawPoints, long returnedPoints, int level) {
//         this.rawPoints = rawPoints;
//         this.returnedPoints = returnedPoints;
//         this.level = level;
//     }
// 
//     /**
//      * @return Number of points of selection based on 100% of the available points.
//      */
//     public long getRawPoints() {
//         return rawPoints;
//     }
// 
//     /**
//      * @return Number of points which can be returned when maximum of points is taken into account.
//      */
//     public long getReturnedPoints() {
//         return returnedPoints;
//     }
// 
//     /**
//      * @return Level in octree at which the returned points will be taken from.
//      */
//     public int getLevel() {
//         return level;
//     }
// 
//     /**
//      * @return Ratio of returned points vs all points
//      */
//     @JsonProperty("coverage")
//     @ApiModelProperty(value="Ratio of points returned with given level", example="0.9058")
//     public float getCoverage() {
//         if (rawPoints == 0) {
//             return 1;
//         }
//         return (float) returnedPoints / (float) rawPoints;
//     }
// 
//     @JsonProperty("coverage")
//     public void setCoverage(float coverage) {
//         // dummy setter, as it is a computed property
//     }
// 
//     @Override
//     public boolean equals(Object o) {
//         if (this == o) { return true;}
//         if (o == null || getClass() != o.getClass()) {return false;}
//         Size size = (Size) o;
//         return Objects.equals(rawPoints, size.rawPoints) &&
//                 Objects.equals(returnedPoints, size.returnedPoints)  &&
//                 Objects.equals(level, size.level);
//     }
// 
//     @Override
//     public int hashCode() {
//         return Objects.hash(rawPoints, returnedPoints, level);
//     }
// 
// 
//     @Override
//     public String toString() {
//         return "Size{" +
//             "rawPoints=" + rawPoints +
//             ", returnedPoints=" + returnedPoints +
//             ", level=" + level +
//             '}';
//     }
// }


import nl.esciencecenter.ahn.pointcloud.core.Selection;
import nl.esciencecenter.ahn.pointcloud.core.Size;
import org.skife.jdbi.v2.DBI;
package nl.esciencecenter.ahn.pointcloud.db;


public class PointCloudStore {
    private final DBI dbi;
    private final long pointsLimit;
    private final int srid;

    public PointCloudStore(DBI dbi, int srid, long pointsLimit) {
        this.dbi = dbi;
        this.srid = srid;
        this.pointsLimit = pointsLimit;
    }

    /**
     * Retrieve approximate number of points within selection.
     *
     * @param selection Selection in a pointcloud
     * @return number of points
     */
// Path: src/main/java/nl/esciencecenter/ahn/pointcloud/core/Selection.java
// @ValidSelection
// public class Selection {
//     @NotNull
//     @JsonProperty
//     @ApiModelProperty(value="Most left or minimum x coordinate", example = "124931.360")
//     private Double left;
// 
//     @NotNull
//     @JsonProperty
//     @ApiModelProperty(value="Most bottom or minimum y coordinate", example = "484567.840")
//     private Double bottom;
// 
//     @NotNull
//     @JsonProperty
//     @ApiModelProperty(value="Most right or maximum x coordinate", example = "126241.760")
//     private Double right;
// 
//     @NotNull
//     @JsonProperty
//     @ApiModelProperty(value="Most top or maximum x coordinate", example = "485730.400")
//     private Double top;
// 
//     public Selection(Double left, Double bottom, Double right, Double top) {
//         this.left = left;
//         this.bottom = bottom;
//         this.right = right;
//         this.top = top;
//     }
// 
//     protected Selection() {
//     }
// 
//     public Double getLeft() {
//         return left;
//     }
// 
//     public Double getBottom() {
//         return bottom;
//     }
// 
//     public Double getRight() {
//         return right;
//     }
// 
//     public Double getTop() {
//         return top;
//     }
// 
//     public void setLeft(Double left) {
//         this.left = left;
//     }
// 
//     public void setBottom(Double bottom) {
//         this.bottom = bottom;
//     }
// 
//     public void setRight(Double right) {
//         this.right = right;
//     }
// 
//     public void setTop(Double top) {
//         this.top = top;
//     }
// 
//     @Override
//     public boolean equals(Object o) {
//         if (this == o) {return true;}
//         if (o == null || getClass() != o.getClass()) {return false;}
//         Selection selection = (Selection) o;
//         return Objects.equals(getLeft(), selection.getLeft()) &&
//                 Objects.equals(getBottom(), selection.getBottom()) &&
//                 Objects.equals(getRight(), selection.getRight()) &&
//                 Objects.equals(getTop(), selection.getTop());
//     }
// 
//     @Override
//     public int hashCode() {
//         return Objects.hash(getLeft(), getBottom(), getRight(), getTop());
//     }
// }
// 
// Path: src/main/java/nl/esciencecenter/ahn/pointcloud/core/Size.java
// public class Size {
//     @NotNull
//     @Range(min=0)
//     @ApiModelProperty(value="Approximate number of points in selection", example = "10193813")
//     private long rawPoints = 0;
// 
//     @NotNull
//     @Range(min=0)
//     @ApiModelProperty(value="Approximate number of points in selection which will be returned", example = "9234324")
//     private long returnedPoints = 0;
// 
//     @NotNull
//     @Range(min=0, max=24)
//     @ApiModelProperty(value=" Level in octree pyramid to fetch points from. Lower number means less points", example="8")
//     private int level;
// 
//     private Size() {
//     }
// 
//     public Size(long rawPoints, long returnedPoints, int level) {
//         this.rawPoints = rawPoints;
//         this.returnedPoints = returnedPoints;
//         this.level = level;
//     }
// 
//     /**
//      * @return Number of points of selection based on 100% of the available points.
//      */
//     public long getRawPoints() {
//         return rawPoints;
//     }
// 
//     /**
//      * @return Number of points which can be returned when maximum of points is taken into account.
//      */
//     public long getReturnedPoints() {
//         return returnedPoints;
//     }
// 
//     /**
//      * @return Level in octree at which the returned points will be taken from.
//      */
//     public int getLevel() {
//         return level;
//     }
// 
//     /**
//      * @return Ratio of returned points vs all points
//      */
//     @JsonProperty("coverage")
//     @ApiModelProperty(value="Ratio of points returned with given level", example="0.9058")
//     public float getCoverage() {
//         if (rawPoints == 0) {
//             return 1;
//         }
//         return (float) returnedPoints / (float) rawPoints;
//     }
// 
//     @JsonProperty("coverage")
//     public void setCoverage(float coverage) {
//         // dummy setter, as it is a computed property
//     }
// 
//     @Override
//     public boolean equals(Object o) {
//         if (this == o) { return true;}
//         if (o == null || getClass() != o.getClass()) {return false;}
//         Size size = (Size) o;
//         return Objects.equals(rawPoints, size.rawPoints) &&
//                 Objects.equals(returnedPoints, size.returnedPoints)  &&
//                 Objects.equals(level, size.level);
//     }
// 
//     @Override
//     public int hashCode() {
//         return Objects.hash(rawPoints, returnedPoints, level);
//     }
// 
// 
//     @Override
//     public String toString() {
//         return "Size{" +
//             "rawPoints=" + rawPoints +
//             ", returnedPoints=" + returnedPoints +
//             ", level=" + level +
//             '}';
//     }
// }


// Path: src/main/java/nl/esciencecenter/ahn/pointcloud/db/PointCloudStore.java
import nl.esciencecenter.ahn.pointcloud.core.Selection;
import nl.esciencecenter.ahn.pointcloud.core.Size;
import org.skife.jdbi.v2.DBI;

package nl.esciencecenter.ahn.pointcloud.db;


public class PointCloudStore {
    private final DBI dbi;
    private final long pointsLimit;
    private final int srid;

    public PointCloudStore(DBI dbi, int srid, long pointsLimit) {
        this.dbi = dbi;
        this.srid = srid;
        this.pointsLimit = pointsLimit;
    }

    /**
     * Retrieve approximate number of points within selection.
     *
     * @param selection Selection in a pointcloud
     * @return number of points
     */
    public Size getApproximateNumberOfPoints(Selection selection) {