--[[----------------------------------------------------------------------------

ADOBE CONFIDENTIAL
------------------
Copyright 2025 Adobe
All Rights Reserved.

NOTICE: All information contained herein is, and remains
the property of Adobe and its suppliers, if any. The intellectual
and technical concepts contained herein are proprietary to Adobe
and its suppliers and are protected by all applicable intellectual
property laws, including trade secret and copyright laws.
Dissemination of this information or reproduction of this material
is strictly forbidden unless prior written permission is obtained
from Adobe.

------------------------------------------------------------------------------]]

if true then

	-- To test the DBSCAN implementation, you must define WF_DBSCAN within
	-- WFCoreInit.c. You must also add the following natives files to the
	-- wf_core target:
	--
	-- core/dbscan/WFDBSCANImp.cpp
	-- third_party/dbscan_tp/dbscan.cpp
	-- third_party/dbscan_tp/dbscan.hpp
	-- third_party/dbscan_tp/nanoflann.hpp
	--
	-- This is temporary, and should be removed after the DBSCAN submodule is
	-- integrated into the client repos.

	return {}

end


local WFDBSCANImp = require 'WFDBSCANImp'

--------------------------------------------------------------------------------

local WFDBSCAN = {}

--------------------------------------------------------------------------------

local function invokeDBSCAN( dbscanFunc, pointsByDocId, eps, min_points )

	-- The key in the points table is the docId. We need
	-- a table with integer keys. But we want to maintain the
	-- relationship to the data in a cache, done by hashing the
	-- entry. This is super ugly, but the DBSCAN imp I'm using
	-- doesn't allow me to label data, so this is a temporary
	-- workaround.

	local points = {}

	local docIdByIndex = {}

	for docId, data in pairs( pointsByDocId ) do

		local index = #points + 1

		points[ index ] = data

		docIdByIndex[ index ] = docId

	end

	-- Cluster time.

	local clusters = dbscanFunc( points, eps, min_points )

	--- Convert clusters to docIds

	local clusteredDocIds = {}

	for _, cluster in ipairs( clusters ) do

		local docIdCluster = {}

		for _, index in ipairs( cluster ) do

			local docId = docIdByIndex[ index ]

			if docId then

				docIdCluster[ #docIdCluster + 1 ] = docId

			end

		end

		clusteredDocIds[ #clusteredDocIds + 1 ] = docIdCluster

	end

	return clusteredDocIds

end

--------------------------------------------------------------------------------
-- @mark WFDBSCAN APIs
--------------------------------------------------------------------------------

--[[!

	\brief Performs DBSCAN clustering on a set of 2D points.

	\param pointsByDocId (table) A table where each key is a document ID and the value is an array of point coordinates.
	\param eps (number) The maximum distance between points to be considered neighbors.
		Must be a positive number.
	\param min_points (number) The minimum number of points required to form a cluster.
		Must be at least 1.

	\return (table) An array of clusters, where each cluster is an array of document IDs that belong to that cluster.
		Points that do not belong to any cluster are considered noise and are not included in the result.

--]]

function WFDBSCAN.DBSCAN_2D( pointsByDocId, eps, min_points )

	return invokeDBSCAN( WFDBSCANImp.DBSCAN_2D, pointsByDocId, eps, min_points )

end

--------------------------------------------------------------------------------

--[[!

	\brief Performs DBSCAN clustering on a set of 3D points.

	\param pointsByDocId (table) A table where each key is a document ID and the value is an array of point coordinates.
	\param eps (number) The maximum distance between points to be considered neighbors.
		Must be a positive number.
	\param min_points (number) The minimum number of points required to form a cluster.
		Must be at least 1.

	\return (table) An array of clusters, where each cluster is an array of document IDs that belong to that cluster.
		Points that do not belong to any cluster are considered noise and are not included in the result.

--]]

function WFDBSCAN.DBSCAN_3D( pointsByDocId, eps, min_points )

	return invokeDBSCAN( WFDBSCANImp.DBSCAN_3D, pointsByDocId, eps, min_points )

end

--------------------------------------------------------------------------------

return WFDBSCAN
