class GeoFunctions {

    @Description("Returns the Point value that is the mathematical centroid of a Geometry")
    @ScalarFunction("ST_Centroid")
    @SqlType(GEOMETRY_TYPE_NAME)
    public static Slice stCentroid(@SqlType(GEOMETRY_TYPE_NAME) Slice input)
    {
        OGCGeometry geometry = deserialize(input);
        validateType("ST_Centroid", geometry, EnumSet.of(POINT, MULTI_POINT, LINE_STRING, MULTI_LINE_STRING, POLYGON, MULTI_POLYGON));
        GeometryType geometryType = GeometryType.getForEsriGeometryType(geometry.geometryType());
        if (geometryType == GeometryType.POINT) {
            return input;
        }

        int pointCount = ((MultiVertexGeometry) geometry.getEsriGeometry()).getPointCount();
        if (pointCount == 0) {
            return serialize(createFromEsriGeometry(new Point(), geometry.getEsriSpatialReference()));
        }

        Point centroid;
        switch (geometryType) {
            case MULTI_POINT:
                centroid = computePointsCentroid((MultiVertexGeometry) geometry.getEsriGeometry());
                break;
            case LINE_STRING:
            case MULTI_LINE_STRING:
                centroid = computeLineCentroid((Polyline) geometry.getEsriGeometry());
                break;
            case POLYGON:
                centroid = computePolygonCentroid((Polygon) geometry.getEsriGeometry());
                break;
            case MULTI_POLYGON:
                centroid = computeMultiPolygonCentroid((OGCMultiPolygon) geometry);
                break;
            default:
                throw new PrestoException(INVALID_FUNCTION_ARGUMENT, "Unexpected geometry type: " + geometryType);
        }
        return serialize(createFromEsriGeometry(centroid, geometry.getEsriSpatialReference()));
    }

    private  GeoFunctions();

}