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

KSPrefs.lua

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

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

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

WARNING [epoley 2010-10-29]: Warning: Cocoa preferences do not behave as expected
in the simulator if you quit with command-Q (or equivalent) instead of properly
terminating the app by clicking the back button. As far as I can tell, there
is no such issue on the device.

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

	-- Rx
local Rx = require 'Rx'
local BehaviorSubject = Rx.BehaviorSubject

	-- WF.core.rxlua	
local WFRxEventBridge = require 'WFRxEventBridge'
local WFRxWeakObservableTable = require 'WFRxWeakObservableTable'

	-- wichitafoundation.core.utils
local WFCloseSupport = require 'WFCloseSupport'
local WFPlatformInfo = require 'WFPlatformInfo'

	-- wichitafoundation.os.prefs
local KSPrefsImp = require 'KSPrefsImp' -- platform core API


--============================================================================--

-- @mark Preference observables

local prefsWeakObservableTable = WFRxWeakObservableTable( 
	function( key )
		return BehaviorSubject( KSPrefsImp.getValue( key ) )
	end )

local didStartWatchingPrefs = false

local asKSEvent = WFRxEventBridge

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

local function installSystemNotificationHook()

	assert( not didStartWatchingPrefs )
	didStartWatchingPrefs = true

	KSPrefsImp.startWatchingPrefs()
	
	require 'KSSystemNotifications'.onNotificationDo( 'KSPrefsImp_userDefaultsDidChange',
	
		function()
	
			-- As far as I know, we don't have a way to know *which* preference
			-- was changed, so we just iterate through all prefs and refresh.
			-- I wish there was a faster way.
		
			for k, _ in pairs( prefsWeakObservableTable:activeKeys() ) do
			
				local obs = prefsWeakObservableTable:observableForKey( k )
			
				if WFCloseSupport.hasBeenOrWillBeClosed( obs ) then
					obs:dispose()
				else
					obs:onNext( KSPrefsImp.getValue( k ) )
				end
			
			end
		
		end )

end

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

local function pref( k )

	if not prefsWeakObservableTable:hasObservableForKey( k ) then

		if not didStartWatchingPrefs then
			installSystemNotificationHook()
		end
		
	end
	
	local obs = prefsWeakObservableTable:observableForKey( k )
	
	return obs:distinctUntilChanged()

end

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

local function prefB( k )

	return pref( k )
		:call( asKSEvent )
		:holdB( KSPrefsImp.getValue( k ) )
		:autoCloseRelayB()
end

--============================================================================--

-- @mark One-off access to prefs values (classic interface)

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

local KSPrefs = {}

local prefsMetatable = {}

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

function prefsMetatable.__index( t, k )

	if type( k ) ~= 'string' then
		error( "KSPrefs: preference keys must be string", 2 )
	end
	
	if k == 'prefB' then
		return prefB
	end

	if k == 'pref' then
		return pref
	end

	return KSPrefsImp.getValue( k )

end

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

function prefsMetatable.__newindex( t, k, v )

	if type( k ) ~= 'string' then
		error( "KSPrefs: preference keys must be string", 2 )
	end
	
	if k == 'prefB' then
		error( "KSPrefs: can not set prefB", 2 )
	end
	
	if k == 'pref' then
		error( "KSPrefs: can not set pref", 2 )
	end

	local existingValue = KSPrefsImp.getValue( k )
	
	if existingValue ~= v then
		KSPrefsImp.setValue( k, v )
	end

	if prefsWeakObservableTable:hasObservableForKey( k ) then
		local localPref = prefsWeakObservableTable:observableForKey( k )
		localPref:onNext( v )
	end

end

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

--[[!
	MAC/IOS ONLY
	
	\brief Delete all KSPrefs for either the specified app bundle Id, or the current app.

	\param maybeBundleId (optional, string) The app bundle id for which the preferences
		will be deleted. If nil, the current app's preferences will be deleted.
	
	\return <void>
--]]

function KSPrefs.deleteAllPreferencesForBundle( maybeBundleId )

	if KSPrefsImp.deleteAllPreferencesForBundle then
		KSPrefsImp.deleteAllPreferencesForBundle( maybeBundleId )
	end

end

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

--[[!
	WINDOWS ONLY
	
	\brief Delete all KSPrefs in the specified prefs file, or for the current app.

	\param maybePrefsFile (optional, string)
	
	\return <void>
--]]

function KSPrefs.deleteAllPrefs( maybePrefsFile )

	if WFPlatformInfo.isWindows then
	
		local KSPrefsImpLua = require 'KSPrefsImpLua'
		local prefsToDelete = KSPrefsImpLua.deletePrefsFile( maybePrefsFile )
		
		for key, _ in pairs( prefsToDelete ) do
			KSPrefs[ key ] = nil
		end
		
	end

end

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

return setmetatable( KSPrefs, prefsMetatable )
