SET client_min_messages TO warning;

DROP TABLE IF EXISTS raster_clip;
CREATE TABLE raster_clip (
	rid integer,
	rast raster
);
DROP TABLE IF EXISTS geom_clip;
CREATE TABLE geom_clip (
	gid integer,
	geom geometry
);
DROP TABLE IF EXISTS raster_clip_out;
CREATE TABLE raster_clip_out (
	tid integer,
	rid integer,
	gid integer,
	rast raster, touched boolean
);

CREATE OR REPLACE FUNCTION make_test_raster(
	rid integer,
	width integer DEFAULT 2,
	height integer DEFAULT 2,
	ul_x double precision DEFAULT 0,
	ul_y double precision DEFAULT 0,
	skew_x double precision DEFAULT 0,
	skew_y double precision DEFAULT 0,
	initvalue double precision DEFAULT 1,
	nodataval double precision DEFAULT 0
)
	RETURNS void
	AS $$
	DECLARE
		x int;
		y int;
		rast raster;
	BEGIN
		rast := ST_MakeEmptyRaster(width, height, ul_x, ul_y, 1, -1, skew_x, skew_y, 0);
		rast := ST_AddBand(rast, 1, '8BUI', initvalue, nodataval);

		INSERT INTO raster_clip VALUES (rid, rast);

		RETURN;
	END;
	$$ LANGUAGE 'plpgsql';

-- Define three rasters
-- The first one 1 band with a novalue defined and one pixel set to nodata value
SELECT make_test_raster(1, 4, 4, 0, 0, 0, 0, 1, 0);
UPDATE raster_clip SET rast = ST_SetValue(rast, 3, 2, NULL) WHERE rid = 1;

-- The second one 3 bands with a novalue defined for the first two band but not set for the third band and one pixel set to nodata value in every band
SELECT make_test_raster(2, 4, 4, 0, 0, 0, 0, 10, 0);
UPDATE raster_clip SET rast = ST_SetValue(rast, 3, 2, NULL) WHERE rid = 2;
UPDATE raster_clip SET rast = ST_AddBand(rast, '8BUI'::text, 2, 0) WHERE rid = 2;
UPDATE raster_clip SET rast = ST_SetValue(rast, 2, 3, 2, NULL) WHERE rid = 2;
UPDATE raster_clip SET rast = ST_AddBand(rast, '8BUI'::text, 3, NULL) WHERE rid = 2;

-- The third one 1 band skewed 40 degree, (Can't test this yet as ST_AsRaster() still produces badly aligned raster. See ticket #1574)
--SELECT make_test_raster(3, 4, 4, 0, 0, 0, 0, 1, 0);
--UPDATE raster_clip SET rast = ST_SetSkew(rast, -0.15, -0.15) WHERE rid = 3;
--UPDATE raster_clip SET rast = ST_SetValue(rast, 3, 2, NULL) WHERE rid = 3;

-- Add a first polygon small and outside the extent of the raster
INSERT INTO geom_clip VALUES (1, ST_Buffer(ST_SetSRID(ST_MakePoint(-1, 1), 0), 0.2));
-- Add a second polygon small, inside the extent of the raster but in the nodata value pixel
INSERT INTO geom_clip VALUES (2, ST_Buffer(ST_SetSRID(ST_MakePoint(2.5, -1.5), 0), 0.2));
-- Add a second polygon small but inside the extent of the raster
INSERT INTO geom_clip VALUES (3, ST_Buffer(ST_SetSRID(ST_MakePoint(1.5, -1.5), 0), 0.2));
-- Add a third polygon big cutting the raster
INSERT INTO geom_clip VALUES (4, ST_Buffer(ST_SetSRID(ST_MakePoint(4, -2.5), 0), 2.8));
-- Add a fourth polygon englobing the two first rasters
INSERT INTO geom_clip VALUES (5, ST_Buffer(ST_SetSRID(ST_MakePoint(2, -2), 0), 3));

DROP FUNCTION make_test_raster(integer, integer, integer, double precision, double precision, double precision, double precision, double precision, double precision);

-- Test 1 without trimming, without defining a nodata value
INSERT INTO raster_clip_out
SELECT 1, rid, gid, ST_Clip(rast, geom, false, touched => t1::boolean), t1::boolean AS touched
FROM raster_clip, geom_clip, generate_series(0,1) AS t1;

-- Test 2 with trimming, without defining a nodata value
INSERT INTO raster_clip_out
SELECT 2, rid, gid, ST_Clip(rast, geom, true, touched => t1::boolean), t1::boolean AS touched
FROM raster_clip, geom_clip, generate_series(0,1) AS t1;

-- Test 3 without trimming, defining a nodata value
INSERT INTO raster_clip_out
SELECT 3, rid, gid, ST_Clip(rast, geom, ARRAY[255, 254, 253], false, touched => t1::boolean), t1::boolean AS touched
FROM raster_clip, geom_clip, generate_series(0,1) AS t1;

-- Test 4 with trimming, defining a nodata value
INSERT INTO raster_clip_out
SELECT 4, rid, gid, ST_Clip(rast, geom, ARRAY[255, 254, 253], true, touched => t1::boolean), t1::boolean AS touched
FROM raster_clip, geom_clip, generate_series(0,1) AS t1;

-- Display the metadata of the resulting rasters
SELECT
	tid,
	rid,
	gid,
	round(upperleftx::numeric, 3) AS upperleftx,
	round(upperlefty::numeric, 3) AS upperlefty,
	width,
	height,
	round(scalex::numeric, 3) AS scalex,
	round(scaley::numeric, 3) AS scaley,
	round(skewx::numeric, 3) AS skewx,
	round(skewy::numeric, 3) AS skewy,
	srid,
	numbands,
	pixeltype,
	round(nodatavalue::numeric, 3) AS nodatavalue, touched
FROM (
	SELECT  tid,
	        rid,
		gid,
		md.*,
		bmd.*, touched
	FROM raster_clip_out
		LEFT JOIN LATERAL ST_Metadata(rast) AS md ON true
		LEFT JOIN LATERAL ST_BandMetadata(rast, 1) AS bmd ON true
) AS r;

-- Display the pixels and the values of the resulting rasters (raster 1)
SELECT
	tid,
	rid,
	gid,
	(gvxy).x,
	(gvxy).y,
	(gvxy).val,
	ST_AsText((gvxy).geom) geom, touched
FROM (SELECT tid, rid, gid, gvxy, touched
      FROM raster_clip_out, ST_PixelAsPolygons(rast) AS gvxy
      WHERE rid = 1
) foo
ORDER BY 1, 2, 3, 4, 5, 7,8;

-- Display the pixels and the values of the resulting rasters (raster 2, 3 bands)
SELECT
	tid,
	rid,
	gid,
	band,
	(gvxy).x,
	(gvxy).y,
	touched,
	(gvxy).val,
	ST_AsText((gvxy).geom) geom, count(1) OVER(PARTITION BY tid,rid,gid, band,touched) AS numpp
FROM (SELECT tid, rid, gid, band, gvxy, touched
      FROM raster_clip_out, generate_series(1, 3) band,
				ST_PixelAsPolygons(rast, band) AS gvxy
      WHERE rid = 2
) foo
ORDER BY 1, 2, 3, 4, 5, 6, 7, 8;

DROP TABLE IF EXISTS geom_clip;
DROP TABLE IF EXISTS raster_clip;
DROP TABLE IF EXISTS raster_clip_out;

-- #5148 mask raster not aligned to input raster
SELECT
	ST_UpperLeftX(rast) AS x,
	ST_UpperLeftY(rast) AS y,
	ST_Width(rast) AS w,
	ST_Height(rast) AS h
FROM ST_Clip(
	ST_AddBand(
		ST_MakeEmptyRaster(100, 100, 0, 0.001, 1e-5, -1e-5, 0, 0, 0),
		1, '8BUI', 1, 0
	),
	ST_GeomFromText('POLYGON((0 0.0009999, 0.0001 0.0009999, 0.0001 0.0009, 0 0.0009, 0 0.0009999))')
) AS rast;

-- #6048 clipping a sparse band selection should populate dense output bands
WITH test_rast AS (
	SELECT ST_AddBand(
		ST_AddBand(
			ST_AddBand(
				ST_SetSRID(
					ST_MakeEmptyRaster(4, 4, 0, 4, 1, -1, 0, 0),
					4326
				),
				'8BUI'::text, 11, 1
			),
			'8BUI'::text, 22, 2
		),
		'8BUI'::text, 33, 3
	) AS rast
), test_geom AS (
	SELECT ST_SetSRID(ST_MakeEnvelope(1, 1, 3, 3), 4326) AS geom
)
SELECT '#6048.1',
	ST_Width(rast),
	ST_Height(rast),
	ST_NumBands(rast),
	ST_BandNoDataValue(rast, 1)::int,
	ST_Value(rast, 1, 2, 2)::int
FROM (
	SELECT _ST_Clip(rast, ARRAY[3], geom, ARRAY[255, 255, 255], FALSE) AS rast
	FROM test_rast, test_geom
) AS clipped;

WITH test_rast AS (
	SELECT ST_AddBand(
		ST_AddBand(
			ST_AddBand(
				ST_SetSRID(
					ST_MakeEmptyRaster(4, 4, 0, 4, 1, -1, 0, 0),
					4326
				),
				'8BUI'::text, 11, 1
			),
			'8BUI'::text, 22, 2
		),
		'8BUI'::text, 33, 3
	) AS rast
), test_geom AS (
	SELECT ST_SetSRID(ST_MakeEnvelope(1, 1, 3, 3), 4326) AS geom
)
SELECT '#6048.2',
	ST_NumBands(rast),
	ST_BandNoDataValue(rast, 1)::int,
	ST_BandNoDataValue(rast, 2)::int,
	ST_Value(rast, 1, 2, 2)::int,
	ST_Value(rast, 2, 2, 2)::int
FROM (
	SELECT _ST_Clip(rast, ARRAY[3, 1], geom, ARRAY[253, 251], FALSE) AS rast
	FROM test_rast, test_geom
) AS clipped;
