class GeoFunctions {

    @Description("Returns a LineString from an array of points")
    @ScalarFunction("ST_LineString")
    @SqlType(GEOMETRY_TYPE_NAME)
    public static Slice stLineString(@SqlType("array(" + GEOMETRY_TYPE_NAME + ")") Block input)
    {
        MultiPath multipath = new Polyline();
        OGCPoint previousPoint = null;
        for (int i = 0; i < input.getPositionCount(); i++) {
            Slice slice = GEOMETRY.getSlice(input, i);

            if (slice.getInput().available() == 0) {
                throw new PrestoException(INVALID_FUNCTION_ARGUMENT, format("Invalid input to ST_LineString: null point at index %s", i + 1));
            }

            OGCGeometry geometry = deserialize(slice);
            if (!(geometry instanceof OGCPoint)) {
                throw new PrestoException(INVALID_FUNCTION_ARGUMENT, format("ST_LineString takes only an array of valid points, %s was passed", geometry.geometryType()));
            }
            OGCPoint point = (OGCPoint) geometry;

            if (point.isEmpty()) {
                throw new PrestoException(INVALID_FUNCTION_ARGUMENT, format("Invalid input to ST_LineString: empty point at index %s", i + 1));
            }

            if (previousPoint == null) {
                multipath.startPath(point.X(), point.Y());
            }
            else {
                if (point.Equals(previousPoint)) {
                    throw new PrestoException(INVALID_FUNCTION_ARGUMENT,
                            format("Invalid input to ST_LineString: consecutive duplicate points at index %s", i + 1));
                }
                multipath.lineTo(point.X(), point.Y());
            }
            previousPoint = point;
        }
        OGCLineString linestring = new OGCLineString(multipath, 0, null);
        return serialize(linestring);
    }

    private  GeoFunctions();

}