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

WFAsyncFileUtils.lua

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

ADOBE CONFIDENTIAL
------------------
Copyright 2016 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.

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

	-- RxLua
local Rx = require 'Rx'
local Observable = Rx.Observable

	-- WF.core.rxlua
local WFRxNativeObservable = require 'WFRxNativeObservable'

	-- WF.core.os
local KSData = require 'KSData'
local WFAsyncFileUtilsImp = require 'WFAsyncFileUtilsImp'

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

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


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

local logger = WFLogger 'WFAsyncFileUtils'
local check = assert( WFArguments.check )
KSData.registerArgumentChecker()


--============================================================================--
--[[!
	\class WFAsyncFileUtils

	\brief This namespace provides asynchronous file system operations.
]]--

-- @mark WFAsyncFileUtils namespace

local WFAsyncFileUtils = {}

--------------------------------------------------------------------------------
--[[!
	\brief Copies a file from one path to another. If a file already exists at the
		destination path, chooses a new name in the destination folder so as not to
		overwrite the existing file.

	If source and destination strings are identical, this function is a no-op.

	This observable will schedule the copy when the subscription happens.

	\param src (string) The absolute path to the file to copy.
	\param dst (string) The absolute path to the desired destination path.
	\param tryHardLink (optional boolean) Mac & iOS only: Optional flag which if true will
		cause this routine to try a hard link before making a copy.
	\param allowDuplication (optional boolean) If the source and destination paths are same, then
		duplicate the source file.

	\return Observable that sends the complete path to the new file once it
		completes.  Or sends an error tuple if unable to complete this operation.
		The first value in the error will be consistent across platforms, the
		second value will be a platform specific error message.

]]--

function WFAsyncFileUtils.copyToUniquelyNamedFile( src, dst, hardLink, allowDuplication )

	check( '+string', '+string', '?boolean', '?boolean' )
	
	if src == dst and not allowDuplication then
		return Observable.just( src )
	end

	return WFRxNativeObservable( WFAsyncFileUtilsImp.copyToUniquelyNamedFile, src, dst, hardLink )
		:catch( function( errorTable )
			return Observable.throw( errorTable.copyError, errorTable.platformError )
		end )

end

--------------------------------------------------------------------------------
--[[!
	\brief Similar to copyToUniquelyNamedFile, but moves the file.

	\param src (string) The absolute path to the file to copy.
	\param dst (string) The absolute path to the desired destination path.

	\return Observable that sends the complete path to the moved file once it
		completes.  Or sends an error tuple if unable to complete this operation.
		The first value in the error will be consistent across platforms, the
		second value will be a platform specific error message.

]]--

function WFAsyncFileUtils.moveToUniquelyNamedFile( src, dst )

	check( '+string', '+string' )
	
	if src == dst then
		logger:warnf( "Attempting to move a file to itself: %s", src )
		return Observable.just( src )
	end

	return WFRxNativeObservable( WFAsyncFileUtilsImp.moveToUniquelyNamedFile, src, dst )
		:catch( function( errorTable )
			return Observable.throw( errorTable.moveError, errorTable.platformError )
		end )

end

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

--[[!
	\brief Move a file, will not overwrite any file that already exists at the destination.
	
	\param src (string) The absolute path to the file to copy.
	\param dst (string) The absolute path to the desired destination path.

	\return Observable that sends the complete path to the moved file once it
		completes.  Or sends an error tuple if unable to complete this operation.
		The first value in the error will be consistent across platforms, the
		second value will be a platform specific error message.
]]--
function WFAsyncFileUtils.moveFile( src, dst )
	
	check( '+string', '+string' )
	
	if src == dst then
		logger:warnf( "Attempting to move a file to itself: %s", src )
		return Observable.just( src )
	end
	
	return WFRxNativeObservable( WFAsyncFileUtilsImp.moveFile, src, dst )
		:catch( function( errorTable )
			return Observable.throw( errorTable.moveError, errorTable.platformError )
		end )
end

--------------------------------------------------------------------------------
--[[!
	\brief Calculates the size of all files at a given path. If the path is a file, it
		returns the file size. If the path is a directory, it should return the size of 
		all files underneath that directory.
		
	If the path does not exist, it will return 0

	This observable will schedule the calculation when the subscription happens.

	\param path (string) The absolute path to calculate size for.

	\return Observable that sends the size of all files at the specified path.

]]--

function WFAsyncFileUtils.calculatePathSize( path )

	check( '+string' )
	
	return WFRxNativeObservable( WFAsyncFileUtilsImp.calculatePathSize, path )
	
end

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

--[[!
	\brief Reads the file at a given path into a KSData object. If the path does not
	exist or is not a file it will return nil.
	
	\param path (string) The path to read
	
	\return Observable that reads the file at the specified path. Returns data 
		as a KSData object

]]--
function WFAsyncFileUtils.readFile( path )
	
	check( '+string' )
	
	return WFRxNativeObservable( WFAsyncFileUtilsImp.readFile, path )

end

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

--[[!
	\brief Writes the data in a KSData object to a file at the given path.
	
	\param data (KSData) The data to write
	
	\return Observable that returns true if successful
		
]]--
function WFAsyncFileUtils.saveToFile( data, path )

	check( 'KSData', '+string' )
	
	return WFRxNativeObservable( WFAsyncFileUtilsImp.saveToFile, data, path )
		:catch( function( errorTable )
			return Observable.throw( errorTable.saveError, errorTable.platformError )
		end )

end

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

--[[!
	\brief Writes the data in a KSData object to a file. 
		If a file already exists at the destination path, 
		chooses a new name in the destination folder so as 
		not to overwrite the existing file.
	
	\param data (KSData) The data to write
	
	\return Observable that sends the complete path to the new file once it
		completes.  Or sends an error tuple if unable to complete this operation.
		The first value in the error will be consistent across platforms, the
		second value will be a platform specific error message.
		
]]--
function WFAsyncFileUtils.saveToUniquelyNamedFile( data, path )

	check( 'KSData', '+string' )
	
	return WFRxNativeObservable( WFAsyncFileUtilsImp.saveToUniquelyNamedFile, data, path )
		:catch( function( errorTable )
			return Observable.throw( errorTable.saveError, errorTable.platformError )
		end )

end
--------------------------------------------------------------------------------

return WFAsyncFileUtils
