bool RuntimeObjectSystem::Initialise( ICompilerLogger * pLogger, SystemTable* pSystemTable  )
{
	m_pCompilerLogger = pLogger;
	m_pSystemTable = pSystemTable;

	m_pBuildTool->Initialise(m_pCompilerLogger);

	// We start by using the code in the current module
	IPerModuleInterface* pPerModuleInterface = PerModuleInterface::GetInstance();
    pPerModuleInterface->SetModuleFileName( "Main Exe" );

	m_pObjectFactorySystem->SetLogger( m_pCompilerLogger );
    m_pObjectFactorySystem->SetRuntimeObjectSystem( this );

    FileSystemUtils::Path initialDir = FileSystemUtils::GetCurrentPath();
    m_FoundSourceDirectoryMappings[initialDir] = initialDir;

	SetupObjectConstructors(pPerModuleInterface);

	//add this dir to list of include dirs
	FileSystemUtils::Path includeDir = FindFile(__FILE__);
	includeDir = includeDir.ParentPath();
	AddIncludeDir(includeDir.c_str());

	//also add the runtime compiler dir to list of dirs
	includeDir = includeDir.ParentPath() / Path("RuntimeCompiler");
	AddIncludeDir(includeDir.c_str());

	return true;
}
void FileMonitor::ProcessChangeNotification( FileSystemUtils::Path& file )
{
    // Notify any listeners and add to change list if this is a watched file/dir
    
    // Again - this isn't correct, just a hack
    bool bPathIsDir = !file.HasExtension();
    FileSystemUtils::Path pathDir = bPathIsDir ? file : file.ParentPath();

    TDirList::iterator dirIt = GetWatchedDirEntry(pathDir);    
    if (dirIt != m_DirWatchList.end())
    {
        // Is directory itself being watched?
        // Unsure here - no need to notify as folder will get it's own notification come through?
        // Bit below feels redundant
        if (dirIt->bWatchDirItself)
        {
            if (dirIt->pListener != NULL)
            {
                dirIt->pListener->OnFileChange(pathDir);
            }
            else
            {
                m_FileChangedList.push_back(pathDir);
                m_bChangeFlag = true;
            }
        }
#ifdef _MSC_VER
        auto pos = file.m_string.find("~");
        if (pos != file.m_string.npos)
        {
            file.m_string = file.m_string.substr(0, pos);
        }
#endif
        // Is this one of the files being watched in the directory?
        TFileList::iterator fileIt = GetWatchedFileEntry(file, dirIt->fileWatchList);
        if (fileIt != dirIt->fileWatchList.end())
        {
            if (fileIt->pListener != NULL)
            {
                fileIt->pListener->OnFileChange(file);
            }
            else
            {
                m_FileChangedList.push_back(file);
                m_bChangeFlag = true;
            }
        }
    }
}
void FileMonitor::Watch( const FileSystemUtils::Path& filename, IFileMonitorListener *pListener /*= NULL*/ )
{
    FileSystemUtils::Path filepath = filename.DelimitersToOSDefault();


    // Is this a directory path or a file path?
    // Actually, we can't tell from a path, in general
    // foo/bar could be a filename with no extension
    // It seems reasonable to inspect the path using FileSystemUtils, check it actually exists
    // (it should, surely? otherwise error?) and determine whether it is a file or a folder
    // but for now - we cheat by assuming files have extensions
    bool bPathIsDir = !filepath.HasExtension();

    FileSystemUtils::Path pathDir = bPathIsDir ? filepath : filepath.ParentPath();
    TDirList::iterator dirIt = GetWatchedDirEntry(pathDir);    
    if (dirIt == m_DirWatchList.end())
    {
        // New directory entry
        m_DirWatchList.push_back( WatchedDir(pathDir) );
        dirIt = --(m_DirWatchList.end());
        StartWatchingDir(*dirIt);
    }
    assert(dirIt != m_DirWatchList.end());

    if (bPathIsDir)
    {
        if (!dirIt->bWatchDirItself)
        {
            assert(!dirIt->pListener);
            dirIt->pListener = pListener;
            dirIt->bWatchDirItself = true;
        }
    }
    else
    {
        // Add file to directory's watch list (if it's not already there)
        TFileList::iterator fileIt = GetWatchedFileEntry(filepath, dirIt->fileWatchList);
        if (fileIt == dirIt->fileWatchList.end())
        {
            dirIt->fileWatchList.push_back(WatchedFile(filepath, pListener));
        }
    }
}
FileSystemUtils::Path RuntimeObjectSystem::FindFile( const FileSystemUtils::Path& input )
{
    FileSystemUtils::Path requestedDirectory = input;
    FileSystemUtils::Path filename;
    FileSystemUtils::Path foundFile = input;
    bool bIsFile = input.HasExtension();
    if( bIsFile )
    {
        requestedDirectory = requestedDirectory.ParentPath();
        filename = input.Filename();
    }
    requestedDirectory.ToOSCanonicalCase();
    filename.ToOSCanonicalCase();
    foundFile.ToOSCanonicalCase();

    // Step 1: Try input directory
    if( requestedDirectory.Exists() )
    {
        m_FoundSourceDirectoryMappings[ requestedDirectory ] = requestedDirectory;
    }
    else
    {
        // Step 2: Attempt to find a pre-existing mapping
        bool bFoundMapping = false;
        if( m_FoundSourceDirectoryMappings.size() )
        {
            FileSystemUtils::Path testDir = requestedDirectory;
            FileSystemUtils::Path foundDir;
            unsigned int depth = 0;
            bool bFound = false;
            while( testDir.HasParentPath() )
            {
                TFileMapIterator itrFind = m_FoundSourceDirectoryMappings.find( testDir );
                if( itrFind != m_FoundSourceDirectoryMappings.end() )
                {
                    foundDir = itrFind->second;
                    bFound = true;
                    break;
                }

                testDir = testDir.ParentPath();
                ++depth;
            }

            if( bFound )
            {
                if( depth )
                {
                    // not an exact match
                    FileSystemUtils::Path directory = requestedDirectory;
                    directory.m_string.replace( 0, testDir.m_string.length(), foundDir.m_string );
                    if( directory.Exists() )
                    {
                        foundFile = directory / filename;
                        if( foundFile.Exists() )
                        {
                            m_FoundSourceDirectoryMappings[ requestedDirectory ] = directory;
                            if( m_pCompilerLogger ) {  m_pCompilerLogger->LogInfo( "Found Directory Mapping: %s to %s\n", requestedDirectory.c_str(), directory.c_str() ); }
                            bFoundMapping = true;
                        }
                    }

                }
                else
                {
                    // exact match
                    foundFile = foundDir / filename;
                    bFoundMapping = true;
                }
            }
            
            if( !bFoundMapping )
            {
                // Step 3: Attempt to find a mapping from a known path
                TFileList requestedSubPaths;
                FileSystemUtils::Path requestedSubPath = requestedDirectory;
                while( requestedSubPath.HasParentPath() )
                {
                    requestedSubPaths.push_back( requestedSubPath );
                    requestedSubPath = requestedSubPath.ParentPath();
                }

                TFileMapIterator itr = m_FoundSourceDirectoryMappings.begin();
                while( ( itr != m_FoundSourceDirectoryMappings.end() ) && !bFoundMapping )
                {
                    FileSystemUtils::Path existingPath = itr->second;
                    while( ( existingPath.HasParentPath() ) && !bFoundMapping )
                    {
                        // check all potentials
                        for( size_t i=0; i<requestedSubPaths.size(); ++i )
                        {
                            FileSystemUtils::Path toCheck = existingPath / requestedSubPaths[i].Filename();
                            if( toCheck.Exists() )
                            {
                                // potential mapping
                                FileSystemUtils::Path directory = requestedDirectory;
                                directory.m_string.replace( 0, requestedSubPaths[i].m_string.length(), toCheck.m_string );
                                if( directory.Exists() )
                                {
                                    foundFile = directory / filename;
                                    if( foundFile.Exists() )
                                    {
                                        m_FoundSourceDirectoryMappings[ requestedDirectory ] = directory;
                                        if( m_pCompilerLogger ) {  m_pCompilerLogger->LogInfo( "Found Directory Mapping: %s to %s\n", requestedDirectory.c_str(), directory.c_str() ); }
                                        bFoundMapping = true;
                                        break;
                                    }
                                }
                            }
                        }
                        existingPath = existingPath.ParentPath();
                    }
                    ++itr;
                }
            }
        }
    }

    if( !foundFile.Exists() )
    {
        if( m_pCompilerLogger ) {  m_pCompilerLogger->LogWarning( "Could not find Directory Mapping for: %s\n", input.c_str() ); }
        ++m_NumNotFoundSourceFiles;
    }
    return foundFile;
}
void RuntimeObjectSystem::SetupRuntimeFileTracking(const IAUDynArray<IObjectConstructor*>& constructors_)
{
#ifndef RCCPPOFF
	// for optimization purposes we skip some actions when running for the first time (i.e. no previous constructors)
	static bool bFirstTime = true;

	for (size_t i = 0, iMax = constructors_.Size(); i < iMax; ++i)
	{
		const char* pFilename = constructors_[i]->GetFileName(); // GetFileName returns full path including GetCompiledPath()
		if( !pFilename )
		{
			continue;
		}
		Path filePath = pFilename;
        filePath = filePath.GetCleanPath();
        filePath = FindFile( filePath );

        unsigned short projectId = constructors_[ i ]->GetProjectId();
        ProjectSettings& project = GetProject( projectId );
        AddToRuntimeFileList( filePath.c_str( ), projectId );

		if( !bFirstTime )
		{
 			//remove old include file mappings for this file
            TFileToFilesIterator itrCurr = project.m_RuntimeIncludeMap.begin( );
            while( itrCurr != project.m_RuntimeIncludeMap.end( ) )
			{
				if( itrCurr->second == filePath )
				{
                    TFileToFilesIterator itrErase = itrCurr;
                    ++itrCurr;
                    project.m_RuntimeIncludeMap.erase( itrErase );
				}
				else
				{
					++itrCurr;
				}
			}

            //remove previous link libraries for this file
            project.m_RuntimeLinkLibraryMap.erase( filePath );

            //remove previous source dependencies
            project.m_RuntimeSourceDependencyMap.erase( filePath );
		}

        //we need the compile path for some platforms where the __FILE__ path is relative to the compile path
		FileSystemUtils::Path compileDir = constructors_[i]->GetCompiledPath();

		//add include file mappings
		for (size_t includeNum = 0; includeNum <= constructors_[i]->GetMaxNumIncludeFiles(); ++includeNum)
		{
			const char* pIncludeFile = constructors_[i]->GetIncludeFile(includeNum);
			if( pIncludeFile )
			{
                FileSystemUtils::Path pathInc = compileDir / pIncludeFile;
                pathInc = FindFile( pathInc.GetCleanPath() );
				TFileToFilePair includePathPair;
				includePathPair.first = pathInc;
				includePathPair.second = filePath;
                AddToRuntimeFileList( pathInc.c_str(), projectId );
                project.m_RuntimeIncludeMap.insert( includePathPair );
			}
		}
            

 		//add link library file mappings
		for (size_t linklibraryNum = 0; linklibraryNum <= constructors_[i]->GetMaxNumLinkLibraries(); ++linklibraryNum)
		{
			const char* pLinkLibrary = constructors_[i]->GetLinkLibrary(linklibraryNum);
			if( pLinkLibrary )
			{
                // We do not use FindFiles for Linked Libraries as these are searched for on
                // the library paths, which are themselves searched for.
				TFileToFilePair linklibraryPathPair;
				linklibraryPathPair.first = filePath;
				linklibraryPathPair.second = pLinkLibrary;
                project.m_RuntimeLinkLibraryMap.insert( linklibraryPathPair );
			}
		}

        //add source dependency file mappings
		for (size_t num = 0; num <= constructors_[i]->GetMaxNumSourceDependencies(); ++num)
		{
			SourceDependencyInfo sourceDependency = constructors_[i]->GetSourceDependency(num);
			FileSystemUtils::Path pathInc[2];	// array of potential include files for later checks
			if( sourceDependency.filename )
			{
				FileSystemUtils::Path pathSrc;
				if( sourceDependency.relativeToPath )
				{
					pathSrc = sourceDependency.relativeToPath;
					if( pathSrc.HasExtension() )
					{
						pathInc[1] = compileDir / pathSrc;
						pathSrc =  compileDir / pathSrc.ParentPath() / sourceDependency.filename;
					}
					else
					{
						pathSrc =  compileDir / pathSrc / sourceDependency.filename;
					}
				}
				else
				{
					pathSrc = compileDir / sourceDependency.filename;
				}
                pathSrc.ToOSCanonicalCase();
                pathSrc = pathSrc.DelimitersToOSDefault();
                pathSrc = pathSrc.GetCleanPath();
				pathInc[0] = pathSrc;
				if( sourceDependency.extension )
				{
					pathSrc.ReplaceExtension( sourceDependency.extension );
				}
				pathSrc = FindFile( pathSrc.GetCleanPath() );
				TFileToFilePair sourcePathPair;
				sourcePathPair.first = filePath;
				sourcePathPair.second = pathSrc;
                project.m_RuntimeSourceDependencyMap.insert( sourcePathPair );
                
                // if the include file with a source dependancy is logged as an runtime include, then we mark this .cpp as compile dependencies on change
				for( int inc=0; inc<2; ++inc )
				{
					TFileToFilesEqualRange range = project.m_RuntimeIncludeMap.equal_range( pathInc[inc] );
					if( range.first != range.second )
					{
						// add source file to runtime file list
						AddToRuntimeFileList( pathSrc.c_str(), projectId );

						// also add this as a source dependency, so it gets force compiled on change of header (and not just compiled)
						TFileToFilePair includePathPair;
						includePathPair.first = pathInc[inc];
						includePathPair.second = pathSrc;
						project.m_RuntimeIncludeMap.insert( includePathPair );
					}
				}
			}
		}
	}

    bFirstTime = false;
#endif
}