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

WFTestFileUtils.lua

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

ADOBE CONFIDENTIAL
------------------
Copyright 2015 Adobe Systems Incorporated
All Rights Reserved.

NOTICE: All information contained herein is, and remain the property of
Adobe Systems Incorporated and its suppliers, if any. The intellectual and
technical concepts contained herein are proprietary to Adobe Systems
Incorporated and its suppliers and may be covered by U.S. and Foreign
Patents, patents in process, and are protected by trade secret or copyright
law.  Dissemination of this information or reproduction of this material is
strictly forbidden unless prior written permission is obtained from
Adobe Systems Incorporated.

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

	-- WF.core.logging
local WFLogger = require 'WFLogger'

	-- WF.core.os
local KSPathUtils = require 'KSPathUtils'
local WFFileUtils = require 'WFFileUtils'
local WFPlatformInfo = require 'WFPlatformInfo'

	-- WF.core.utils
local KSIdGenerator = require 'KSIdGenerator'

local logger = WFLogger "WFTestFileUtils"
--	:setLevel( 'debug' )

--============================================================================--
--[[!
	\class WFTestFileUtils
	\brief This class provides a way to verify tests don't leave behind files.
		Every test should delete any files it creates.
]]--

local WFTestFileUtils = {}

local checkFoldersAfterClassTearDown = false
	-- default to check folders after every test

local dynamicFoldersToScan = {}

local ignoredFilePatterns = {
	'^oz%-user%-',
		-- oz user is difficult to close see ozUserMethods:logoutP
}

local ignoredDirectoryNames = {
}

if WFPlatformInfo.isiOS then
	ignoredFilePatterns[ #ignoredFilePatterns + 1 ] = '^Cache.db'
		-- iOS NSUrlCache may create a Cache.db file
	ignoredFilePatterns[ #ignoredFilePatterns + 1 ] = '^test.log'
		-- We create a test.log in the documents folder on iOS, no API to delete.

	ignoredDirectoryNames[ #ignoredFilePatterns + 1 ] = '/fsCachedData/'
		-- iOS NSUrlCache may create a fsCachedData folder with random named files
end

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

local function ignoreFile( path )

	local fileName = KSPathUtils.leafName(path)
	for _, ignoreFile in pairs( ignoredFilePatterns ) do
		if string.match(fileName, ignoreFile) then
			return true
		end
	end

	for _, ignorePath in pairs( ignoredDirectoryNames ) do
		if string.match(path, ignorePath) then
			return true
		end
	end

	return false

end

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

--local function getMetricsFolder()
--
--	local WFDeviceInfo = require 'WFDeviceInfo'
--	local home = KSPathUtils.getStandardFilePath( "home" )
--
--	local metricsHome
--	local platform
--	local metrics = {}
--	metrics[ "platform" ] = WFPlatformInfo.getAppDeviceClass()
--	metrics[ "os" ] = WFPlatformInfo.getOS and WFPlatformInfo.getOS()
--
--	if WFPlatformInfo.isiOS then
--		metricsHome = KSPathUtils.child( "/Users", WFDeviceInfo.userName() )
--		platform = metrics[ "os" ]
--	else
--		metricsHome = home
--		platform = metrics[ "platform" ]
--	end
--
--	local metricsFolder = KSPathUtils.child( metricsHome, "WFPerformanceTestMetrics" )
--
--	return KSPathUtils.child( metricsFolder, platform )
--
--end

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

local WFFolderWalker

local function searchAndDeleteFilesInFolder( folder, folderWalkerOptions )

	if WFPlatformInfo.isAndroid then
		return nil
		-- WFFolderWalker isn't implemented on Android
	end

	WFFolderWalker = WFFolderWalker or require 'WFFolderWalker'

	local firstFileFound

	for path in WFFolderWalker( folder, folderWalkerOptions ) do

		logger:debugf( "WFFolderWalker delete path: %s", path )

		pcall( WFFileUtils.deleteFile, path )
			-- Delete the file so every test doesn't generate an error.

		if not firstFileFound and not ignoreFile( path ) then
			firstFileFound = path
		end

	end

	return firstFileFound

end

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

function WFTestFileUtils.checkForUndeletedFiles( testName )

	if checkFoldersAfterClassTearDown and testName ~= "tearDownClass" then
		return nil
	end

	checkFoldersAfterClassTearDown = false

	local foldersToScan = {}

	for k, _ in pairs(dynamicFoldersToScan) do
		table.insert(foldersToScan, k)
	end

	-- Mac: ~/Pictures/Adobe Revel/Adobe Revel Library.rvl
	-- iOS: ~/Library/Developer/CoreSimulator/Devices/C7719AEB-B9D3-4B44-A5F3-3F0FA85365D4/data/Containers/Data/Application/15EE7DF5-2152-4FB6-A2CE-1251FBBCFEB3/Documents
	-- Win: \Users\<user>\AppData\Local\Adobe\unknownApplication
	-- And: /data/data/com.adobe.wichitafoundation/files/carouselDocuments
	table.insert( foldersToScan, KSPathUtils.getStandardFilePath( "carouselDocuments" ) )

	-- Mac: ~/Library/Caches/Adobe Revel
	-- iOS: ~Library/Developer/CoreSimulator/Devices/C7719AEB-B9D3-4B44-A5F3-3F0FA85365D4/data/Containers/Data/Application/15EE7DF5-2152-4FB6-A2CE-1251FBBCFEB3/Library/Caches
	-- Win: \Users\<user>\AppData\Local\Adobe\unknownApplication\caches
	-- And: /data/data/com.adobe.wichitafoundation/files/carouselCaches
	table.insert( foldersToScan, KSPathUtils.getStandardFilePath( "carouselCaches" ) )

	-- ~/WFPerformanceTestMetrics/mac"
--	table.insert( foldersToScan, getMetricsFolder() )
		-- Disabled because:
		-- Performance tests intentionally leave files in this directory.
		-- You can uncomment this to see if any performance tests are misnamed.

	-- Mac: ~/Library/Caches/Adobe/WF Unit Tests
	-- iOS: ~/Library/Developer/CoreSimulator/Devices/C7719AEB-B9D3-4B44-A5F3-3F0FA85365D4/data/Containers/Data/Application/15EE7DF5-2152-4FB6-A2CE-1251FBBCFEB3/Library/Caches/Adobe/WF Unit Tests
	-- Win: ~/Library/Caches/Adobe/WichitaFoundation
	-- And: /data/data/com.adobe.wichitafoundation/files/caches/Adobe/com.adobe.wichitafoundation
	local cachePath = KSPathUtils.getStandardFilePath( 'caches' )
	local adobeCachePath = KSPathUtils.child(cachePath, 'Adobe' )
	local appIdentifier = WFPlatformInfo.getAppIdentifier()
	if appIdentifier then
		local userInfoCachePathParent = KSPathUtils.child( adobeCachePath, appIdentifier )
		table.insert( foldersToScan, userInfoCachePathParent )
	else
		logger:errorf( "checkForUndeletedFiles expecting getAppIdentifier() to be set" )
	end

	local numStandardFolders = #foldersToScan

	local firstFileFound

	for index, folder in ipairs( foldersToScan ) do

		if testName == 'tearDownClass' and not checkFoldersAfterClassTearDown 
		or testName == 'setUpClass' then

			-- delete entire folders on class teardown in case the server has built
			-- up too many subfolders which we can't scan through fast enough.
			-- (Build machines had 100k empty folders)

			pcall( WFFileUtils.delete, folder )

			if index <= numStandardFolders then
				pcall( WFFileUtils.mkdir, folder )
					-- Android caches the results from getStandardFilePath in
					-- WFCoreEnv::KSPathUtils_getStandardFilePath so recreate.
			end

		else

			local folderWalkerOptions

			if WFPlatformInfo.isiOS or WFPlatformInfo.isMac then
				folderWalkerOptions = { includeHiddenFiles = true }
			end

			logger:debugf( "checkForUndeletedFiles start: %s", folder )

			local success, firstFileFoundOrError = pcall( searchAndDeleteFilesInFolder,
				folder, folderWalkerOptions )

			if success then

				if not firstFileFound then
					firstFileFound = firstFileFoundOrError
				end

			else

				logger:debugf( "checkForUndeletedFiles failed, error: %s", firstFileFoundOrError )

			end

			logger:debugf( "checkForUndeletedFiles end, firstFileFound: %s", firstFileFoundOrError )

		end

	end

	return firstFileFound

end

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

function WFTestFileUtils.addTestFolder( folder )

	dynamicFoldersToScan[ folder ] = true

end

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

function WFTestFileUtils.createTestFolder( rxTest, testName )

	if testName == nil then
		testName = rxTest:testName()
	end

	local dstPath = KSPathUtils.child( KSPathUtils.getStandardFilePath( 'carouselDocuments' ),
		testName .. '-' .. KSIdGenerator.uuidInLowercaseHex() )

	pcall( WFFileUtils.mkdir, dstPath )

	WFTestFileUtils.addTestFolder( dstPath )

	rxTest:finally( function()
		WFFileUtils.delete( dstPath )
	end )

	return dstPath

end

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

function WFTestFileUtils.checkForUndeletedFilesAfterClassTeardown()

	checkFoldersAfterClassTearDown = true

end

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

return WFTestFileUtils
