#pragma once
#ifndef REAL_BUILD
# include "externals.hh"
#endif


/*= T_FilesWatcher / T_WatchedFiles ==========================================*/

/* So we need to be able to watch for files being created, updated and deleted.
 * Watching for updates & deletions is pretty easy. For files being created,
 * one has to watch the parent directory. In addition, the case where a file
 * is being updated by rotation (move old, write new, rm old) needs to be
 * handled correctly as it is what vim does.
 */

struct T_FilesWatcher;
struct T_WatchedFiles;
using F_OnFileChanges = std::function< void( void ) >;

struct T_FilesWatcher
{
	friend struct T_WatchedFiles;

	T_FilesWatcher( T_FilesWatcher const& ) = delete;
	T_FilesWatcher( T_FilesWatcher&& ) = delete;

	T_FilesWatcher( );
	~T_FilesWatcher( );

	void check( );

    private:
	struct T_WatchSet_ {
		T_FilesWatcher* watcher;
		F_OnFileChanges callback;
		bool triggered;

		T_WatchSet_( T_FilesWatcher* watcher ,
				F_OnFileChanges callback ) noexcept;
		~T_WatchSet_( );
	};
	using P_WatchSet_ = T_OwnPtr< T_WatchSet_ >;

	struct T_File_ {
		int wd;
		T_Array< T_WatchSet_* > watchers;
		void trigger( );
	};

	int fd;
	T_KeyValueTable< T_String , T_File_ > fileWatchers_;
	T_KeyValueTable< int , T_String > inotify_;
	T_Array< T_String > missing_;
	T_Array< T_WatchSet_* > watched_;

	void watchFile( T_String const& path ,
			T_WatchSet_* const watcher );
	void unwatchAll( T_WatchSet_* const watcher );
};

/*----------------------------------------------------------------------------*/

struct T_WatchedFiles
{
	friend struct T_FilesWatcher;

	T_WatchedFiles( ) = delete;
	T_WatchedFiles( T_WatchedFiles const& ) = delete;

	T_WatchedFiles( T_WatchedFiles&& ) noexcept;
	T_WatchedFiles( T_FilesWatcher& watcher ,
			const F_OnFileChanges callback );

	void clear( );
	bool watch( T_String const& file );

    private:
	T_FilesWatcher::P_WatchSet_ watchSet_;
};
using P_WatchedFiles = T_OwnPtr< T_WatchedFiles >;