using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.IO;
using System.Threading;

using Codice;
using Codice.Client.BaseCommands;
using Codice.Client.Commands;
using Codice.Client.Commands.WkTree;
using Codice.CM.Common;
using Codice.LogWrapper;
using Codice.Utils;
using GluonGui;
using PlasticGui;
using PlasticGui.WorkspaceWindow;
using Unity.PlasticSCM.Editor.AssetsOverlays.Cache;
using Unity.PlasticSCM.Editor.UI;

using GluonIncomingChangesUpdater = PlasticGui.Gluon.WorkspaceWindow.IncomingChangesUpdater;

namespace Unity.PlasticSCM.Editor.AssetUtils.Processor
{
    internal interface IWorkspaceOperationsMonitor
    {
        void AddAssetsProcessorPathsToAdd(List<string> paths);

        void AddAssetsProcessorPathsToDelete(List<string> paths);

        void AddAssetsProcessorPathsToCheckout(List<string> paths);

        void AddAssetsProcessorPathsToMove(List<UVCSAssetPostprocessor.PathToMove> paths);

        void AddPathsToCheckout(List<string> paths);
    }

    internal class WorkspaceOperationsMonitor : IWorkspaceOperationsMonitor
    {
        // Internal usage. This isn't a public API.
        [EditorBrowsable(EditorBrowsableState.Never)]
        public interface IDisableAssetsProcessor
        {
            void Disable();
        }

        internal WorkspaceOperationsMonitor(
            WorkspaceInfo wkInfo,
            IPlasticAPI plasticApi,
            IAssetStatusCache assetStatusCache,
            IDisableAssetsProcessor disableAssetsProcessor,
            IPendingChangesUpdater pendingChangesUpdater,
            IncomingChangesUpdater developerIncomingChangesUpdater,
            GluonIncomingChangesUpdater gluonIncomingChangesUpdater,
            bool isGluonMode)
        {
            mWkInfo = wkInfo;
            mPlasticAPI = plasticApi;
            mAssetStatusCache = assetStatusCache;
            mDisableAssetsProcessor = disableAssetsProcessor;
            mPendingChangesUpdater = pendingChangesUpdater;
            mDeveloperIncomingChangesUpdater = developerIncomingChangesUpdater;
            mGluonIncomingChangesUpdater = gluonIncomingChangesUpdater;
            mIsGluonMode = isGluonMode;
        }

        internal void RegisterWindow(
            IWorkspaceWindow workspaceWindow,
            ViewHost viewHost)
        {
            mWorkspaceWindow = workspaceWindow;
            mViewHost = viewHost;
        }

        internal void UnRegisterWindow()
        {
            mWorkspaceWindow = null;
            mViewHost = null;
        }

        internal void Start()
        {
            mLog.Debug("Start");

            mCancelToken = new CancelToken();
            mIsEnabled = true;

            Thread thread = new Thread(TaskLoopThread);
            thread.IsBackground = true;
            thread.Name = "Plastic SCM Workspace Operations Monitor thread";
            thread.Start();
        }

        internal void Stop()
        {
            mLog.Debug("Stop");

            SetAsFinished();
        }

        internal void Disable()
        {
            mIsEnabled = false;

            mLog.Debug("Disabled");
        }

        internal void Enable()
        {
            mIsEnabled = true;

            mLog.Debug("Enabled");
        }

        void IWorkspaceOperationsMonitor.AddAssetsProcessorPathsToAdd(
            List<string> paths)
        {
            AddPathsToProcess(
                mAssetsProcessorPathsToAdd, paths,
                mLock, mResetEvent, mIsEnabled);
        }

        void IWorkspaceOperationsMonitor.AddAssetsProcessorPathsToDelete(
            List<string> paths)
        {
            AddPathsToProcess(
                mAssetsProcessorPathsToDelete, paths,
                mLock, mResetEvent, mIsEnabled);
        }

        void IWorkspaceOperationsMonitor.AddAssetsProcessorPathsToCheckout(
            List<string> paths)
        {
            AddPathsToProcess(
                mAssetsProcessorPathsToCheckout, paths,
                mLock, mResetEvent, mIsEnabled);
        }

        void IWorkspaceOperationsMonitor.AddAssetsProcessorPathsToMove(
            List<UVCSAssetPostprocessor.PathToMove> paths)
        {
            AddPathsToMoveToProcess(
                mAssetsProcessorPathsToMove, paths,
                mLock, mResetEvent, mIsEnabled);
        }

        void IWorkspaceOperationsMonitor.AddPathsToCheckout(
            List<string> paths)
        {
            AddPathsToProcess(
                mPathsToCheckout, paths,
                mLock, mResetEvent, mIsEnabled);
        }

        void TaskLoopThread()
        {
            while (true)
            {
                try
                {
                    if (mCancelToken.IsCancelled())
                        break;

                    if (!mIsEnabled)
                    {
                        SleepUntilNextWorkload();
                        continue;
                    }

                    bool hasAssetProcessorOpsPending = false;
                    bool hasCheckoutOpsPending = false;
                    ProcessOperations(
                        mWkInfo,
                        mPlasticAPI,
                        mAssetStatusCache,
                        FilterManager.Get().GetIgnoredFilter(),
                        FilterManager.Get().GetHiddenChangesFilter(),
                        mWorkspaceWindow,
                        mViewHost,
                        mPendingChangesUpdater,
                        mDeveloperIncomingChangesUpdater,
                        mGluonIncomingChangesUpdater,
                        mAssetsProcessorPathsToAdd,
                        mAssetsProcessorPathsToDelete,
                        mAssetsProcessorPathsToCheckout,
                        mAssetsProcessorPathsToMove,
                        mPathsToCheckout,
                        mCancelToken,
                        mLock,
                        mDisableAssetsProcessor,
                        mIsGluonMode,
                        out hasAssetProcessorOpsPending,
                        out hasCheckoutOpsPending);

                    if (mCancelToken.IsCancelled())
                        break;

                    if (hasAssetProcessorOpsPending ||
                        hasCheckoutOpsPending)
                        continue;

                    SleepUntilNextWorkload();
                }
                catch (Exception e)
                {
                    mLog.ErrorFormat(
                        "Error running the tasks loop : {0}", e.Message);
                    mLog.DebugFormat(
                        "Stacktrace: {0}", e.StackTrace);
                }
            }
        }

        void SetAsFinished()
        {
            if (mCancelToken.IsCancelled())
                return;

            mCancelToken.Cancel();

            CleanPendingOperationsToProcess(
                mAssetsProcessorPathsToAdd,
                mAssetsProcessorPathsToDelete,
                mAssetsProcessorPathsToCheckout,
                mAssetsProcessorPathsToMove,
                mPathsToCheckout,
                mLock);

            mResetEvent.Set();
        }

        void SleepUntilNextWorkload()
        {
            mLog.Debug("SleepUntilNextWorkload");

            mResetEvent.Reset();
            mResetEvent.WaitOne();
        }

        static void CleanPendingOperationsToProcess(
            List<string> assetsProcessorPathsToAdd,
            List<string> assetsProcessorPathsToDelete,
            List<string> assetsProcessorPathsToCheckout,
            List<UVCSAssetPostprocessor.PathToMove> assetsProcessorPathsToMove,
            List<string> pathsToCheckout,
            object lockObj)
        {
            CleanPathsToProcess(assetsProcessorPathsToAdd, lockObj);
            CleanPathsToProcess(assetsProcessorPathsToDelete, lockObj);
            CleanPathsToProcess(assetsProcessorPathsToCheckout, lockObj);
            CleanPathsToMoveToProcess(assetsProcessorPathsToMove, lockObj);

            CleanPathsToProcess(pathsToCheckout, lockObj);
        }

        static void ProcessOperations(
            WorkspaceInfo wkInfo,
            IPlasticAPI plasticApi,
            IAssetStatusCache assetStatusCache,
            IIgnoredFilter ignoredFilter,
            IHiddenChangesFilter hiddenChangesFilter,
            IWorkspaceWindow workspaceWindow,
            ViewHost viewHost,
            IPendingChangesUpdater pendingChangesUpdater,
            IncomingChangesUpdater developerIncomingChangesUpdater,
            GluonIncomingChangesUpdater gluonIncomingChangesUpdater,
            List<string> assetsProcessorPathsToAdd,
            List<string> assetsProcessorPathsToDelete,
            List<string> assetsProcessorPathsToCheckout,
            List<UVCSAssetPostprocessor.PathToMove> assetsProcessorPathsToMove,
            List<string> pathsToCheckout,
            CancelToken cancelToken,
            object lockObj,
            IDisableAssetsProcessor disableAssetsProcessor,
            bool isGluonMode,
            out bool hasAssetProcessorOpsPending,
            out bool hasCheckoutOpsPending)
        {
            hasAssetProcessorOpsPending = false;
            hasCheckoutOpsPending = false;

            mLog.Debug("Starting process operations...");

            bool hasAssetProcessorOpsProcessed =
                ProcessAssetProcessorOperations(
                    wkInfo,
                    plasticApi,
                    ignoredFilter,
                    hiddenChangesFilter,
                    assetsProcessorPathsToAdd,
                    assetsProcessorPathsToDelete,
                    assetsProcessorPathsToCheckout,
                    assetsProcessorPathsToMove,
                    cancelToken,
                    lockObj,
                    disableAssetsProcessor);

            if (cancelToken.IsCancelled())
                return;

            bool hasCheckoutOpsProcessed =
                ProcessCheckoutOperation(
                    wkInfo,
                    plasticApi,
                    pathsToCheckout,
                    cancelToken,
                    lockObj);

            mLog.Debug("ProcessOperations - Processed paths ? " +
                (hasAssetProcessorOpsProcessed || hasCheckoutOpsProcessed));

            if (cancelToken.IsCancelled())
                return;

            HasPendingOperationsToProcess(
                assetsProcessorPathsToAdd,
                assetsProcessorPathsToDelete,
                assetsProcessorPathsToCheckout,
                assetsProcessorPathsToMove,
                pathsToCheckout,
                lockObj,
                out hasAssetProcessorOpsPending,
                out hasCheckoutOpsPending);

            bool isAfterAssetProcessorOpNeeded =
                hasAssetProcessorOpsProcessed &&
                !hasAssetProcessorOpsPending;

            bool isAfterCheckoutOpNeeded =
                hasCheckoutOpsProcessed &&
                !hasCheckoutOpsPending;

            if (!isAfterAssetProcessorOpNeeded &&
                !isAfterCheckoutOpNeeded)
                return;

            if (cancelToken.IsCancelled())
                return;

            EditorDispatcher.Dispatch(() =>
            {
                AfterProcessOperations(
                    assetStatusCache,
                    workspaceWindow,
                    viewHost,
                    pendingChangesUpdater,
                    developerIncomingChangesUpdater,
                    gluonIncomingChangesUpdater,
                    isGluonMode);
            });
        }

        static void AfterProcessOperations(
            IAssetStatusCache assetStatusCache,
            IWorkspaceWindow workspaceWindow,
            ViewHost viewHost,
            IPendingChangesUpdater pendingChangesUpdater,
            IncomingChangesUpdater developerIncomingChangesUpdater,
            GluonIncomingChangesUpdater gluonIncomingChangesUpdater,
            bool isGluonMode)
        {
            mLog.Debug("AfterProcessOperations");

            RefreshAsset.VersionControlCache(assetStatusCache);

            if (isGluonMode)
            {
                RefreshViewsAfterProcessOperationsForGluon(
                    viewHost, pendingChangesUpdater, gluonIncomingChangesUpdater);
                return;
            }

            RefreshViewsAfterProcessOperationsForDeveloper(
                workspaceWindow, pendingChangesUpdater, developerIncomingChangesUpdater);
        }

        static bool ProcessAssetProcessorOperations(
            WorkspaceInfo wkInfo,
            IPlasticAPI plasticApi,
            IIgnoredFilter ignoredFilter,
            IHiddenChangesFilter hiddenChangesFilter,
            List<string> assetsProcessorPathsToAdd,
            List<string> assetsProcessorPathsToDelete,
            List<string> assetsProcessorPathsToCheckout,
            List<UVCSAssetPostprocessor.PathToMove> assetsProcessorPathsToMove,
            CancelToken cancelToken,
            object lockObj,
            IDisableAssetsProcessor disableAssetsProcessor)
        {
            bool hasProcessedPaths = false;

            try
            {
                hasProcessedPaths = AssetsProcessorOperations.
                    AddIfNotControlled(
                        wkInfo,
                        plasticApi,
                        ignoredFilter,
                        ExtractPathsToProcess(assetsProcessorPathsToAdd, lockObj),
                        cancelToken);

                if (cancelToken.IsCancelled())
                    return false;

                hasProcessedPaths |= AssetsProcessorOperations.
                    DeleteIfControlled(
                        wkInfo,
                        plasticApi,
                        ExtractPathsToProcess(assetsProcessorPathsToDelete, lockObj),
                        cancelToken);

                if (cancelToken.IsCancelled())
                    return false;

                hasProcessedPaths |= AssetsProcessorOperations.
                    MoveIfControlled(
                        wkInfo,
                        plasticApi,
                        ExtractPathsToMoveToProcess(assetsProcessorPathsToMove, lockObj).AsReadOnly(),
                        cancelToken);

                if (cancelToken.IsCancelled())
                    return false;

                hasProcessedPaths |= AssetsProcessorOperations.
                    CheckoutIfControlledAndChanged(
                        wkInfo,
                        plasticApi,
                        hiddenChangesFilter,
                        ExtractPathsToProcess(assetsProcessorPathsToCheckout, lockObj),
                        cancelToken);
            }
            catch (Exception ex)
            {
                LogException(ex);

                disableAssetsProcessor.Disable();
            }

            return hasProcessedPaths;
        }

        static bool ProcessCheckoutOperation(
            WorkspaceInfo wkInfo,
            IPlasticAPI plasticApi,
            List<string> pathsToProcess,
            CancelToken cancelToken,
            object lockObj)
        {
            List<string> paths = ExtractPathsToProcess(
                pathsToProcess, lockObj);

            List<string> result = new List<string>();

            foreach (string path in paths)
            {
                if (cancelToken.IsCancelled())
                    return false;

                WorkspaceTreeNode node =
                    plasticApi.GetWorkspaceTreeNode(wkInfo, path);

                if (node != null &&
                    !CheckWorkspaceTreeNodeStatus.IsCheckedOut(node))
                    result.Add(path);
            }

            if (cancelToken.IsCancelled())
                return false;

            bool hasPathsToProcess = result.Count > 0;

            if (hasPathsToProcess)
            {
                plasticApi.Checkout(
                    wkInfo,
                    result.ToArray(),
                    CheckoutModifiers.ProcessSymlinks);
            }

            LogProcessedPaths("ProcessCheckoutOperation", result);

            return hasPathsToProcess;
        }

        static void AddPathsToProcess(
            List<string> pathsToProcess,
            List<string> paths,
            object lockObj,
            ManualResetEvent resetEvent,
            bool isEnabled)
        {
            if (!isEnabled)
                return;

            lock (lockObj)
            {
                pathsToProcess.AddRange(paths);
            }

            resetEvent.Set();
        }

        static void AddPathsToMoveToProcess(
            List<UVCSAssetPostprocessor.PathToMove> pathsToProcess,
            List<UVCSAssetPostprocessor.PathToMove> paths,
            object lockObj,
            ManualResetEvent resetEvent,
            bool isEnabled)
        {
            if (!isEnabled)
                return;

            lock (lockObj)
            {
                pathsToProcess.AddRange(paths);
            }

            resetEvent.Set();
        }

        static void CleanPathsToProcess(
            List<string> pathsToProcess,
            object lockObj)
        {
            lock (lockObj)
            {
                pathsToProcess.Clear();
            }
        }

        static void CleanPathsToMoveToProcess(
            List<UVCSAssetPostprocessor.PathToMove> pathsToProcess,
            object lockObj)
        {
            lock (lockObj)
            {
                pathsToProcess.Clear();
            }
        }

        static List<string> ExtractPathsToProcess(
            List<string> pathsToProcess,
            object lockObj)
        {
            List<string> result;

            lock (lockObj)
            {
                result = new List<string>(pathsToProcess);
                pathsToProcess.Clear();
            }

            return result;
        }

        static List<UVCSAssetPostprocessor.PathToMove> ExtractPathsToMoveToProcess(
            List<UVCSAssetPostprocessor.PathToMove> pathsToProcess,
            object lockObj)
        {
            List<UVCSAssetPostprocessor.PathToMove> result;

            lock (lockObj)
            {
                result = new List<UVCSAssetPostprocessor.PathToMove>(pathsToProcess);
                pathsToProcess.Clear();
            }

            return result;
        }

        static void HasPendingOperationsToProcess(
            List<string> assetsProcessorPathsToAdd,
            List<string> assetsProcessorPathsToDelete,
            List<string> assetsProcessorPathsToCheckout,
            List<UVCSAssetPostprocessor.PathToMove> assetsProcessorPathsToMove,
            List<string> pathsToCheckout,
            object lockObj,
            out bool hasAssetProcessorOperations,
            out bool hasCheckoutOperations)
        {
            lock (lockObj)
            {
                hasAssetProcessorOperations =
                    assetsProcessorPathsToAdd.Count > 0 ||
                    assetsProcessorPathsToDelete.Count > 0 ||
                    assetsProcessorPathsToCheckout.Count > 0 ||
                    assetsProcessorPathsToMove.Count > 0;

                hasCheckoutOperations =
                    pathsToCheckout.Count > 0;
            }
        }

        static void RefreshViewsAfterProcessOperationsForDeveloper(
            IWorkspaceWindow workspaceWindow,
            IPendingChangesUpdater pendingChangesUpdater,
            IncomingChangesUpdater developerIncomingChangesUpdater)
        {
            if (pendingChangesUpdater != null)
                pendingChangesUpdater.Update(DateTime.Now);

            if (developerIncomingChangesUpdater != null)
                developerIncomingChangesUpdater.Update(DateTime.Now);

            if (workspaceWindow == null)
                return;

            workspaceWindow.RefreshView(ViewType.BranchExplorerView);
            workspaceWindow.RefreshView(ViewType.HistoryView);
            workspaceWindow.RefreshView(ViewType.LocksView);
        }

        static void RefreshViewsAfterProcessOperationsForGluon(
            ViewHost viewHost,
            IPendingChangesUpdater pendingChangesUpdater,
            GluonIncomingChangesUpdater gluonIncomingChangesUpdater)
        {
            if (pendingChangesUpdater != null)
                pendingChangesUpdater.Update(DateTime.Now);

            if (gluonIncomingChangesUpdater != null)
                gluonIncomingChangesUpdater.Update(DateTime.Now);

            if (viewHost == null)
                return;

            viewHost.RefreshView(ViewType.HistoryView);
            viewHost.RefreshView(ViewType.LocksView);
        }

        static void LogProcessedPaths(
            string operation,
            List<string> paths)
        {
            if (paths.Count == 0)
            {
                mLog.DebugFormat(
                    "{0} - There are no processed paths.",
                    operation);
                return;
            }

            mLog.DebugFormat(
                "{0} - Processed paths: {1}{2}",
                operation, Environment.NewLine,
                string.Join(Environment.NewLine, paths));
        }

        static void LogException(Exception ex)
        {
            mLog.WarnFormat("Message: {0}", ex.Message);

            mLog.DebugFormat(
                "StackTrace:{0}{1}",
                Environment.NewLine, ex.StackTrace);
        }

        internal static class AssetsProcessorOperations
        {
            internal static bool AddIfNotControlled(
                WorkspaceInfo wkInfo,
                IPlasticAPI plasticApi,
                IIgnoredFilter ignoredFilter,
                List<string> paths,
                CancelToken cancelToken)
            {
                List<string> result = new List<string>();

                foreach (string path in paths)
                {
                    if (cancelToken.IsCancelled())
                        return false;

                    string metaPath = MetaPath.GetMetaPath(path);

                    if (plasticApi.GetWorkspaceTreeNode(wkInfo, path) == null &&
                        !ignoredFilter.IsIgnored(path))
                    {
                            result.Add(path);
                    }

                    if (File.Exists(metaPath) &&
                        plasticApi.GetWorkspaceTreeNode(wkInfo, metaPath) == null &&
                        !ignoredFilter.IsIgnored(metaPath))
                    {
                        result.Add(metaPath);
                    }
                }

                if (cancelToken.IsCancelled())
                    return false;

                bool hasPathsToProcess = result.Count > 0;

                if (hasPathsToProcess)
                {
                    IList checkouts;
                    plasticApi.Add(wkInfo, result.ToArray(), GetDefaultAddOptions(), out checkouts);
                }

                LogProcessedPaths("AddIfNotControlled", result);

                return hasPathsToProcess;
            }

            internal static bool DeleteIfControlled(
                WorkspaceInfo wkInfo,
                IPlasticAPI plasticApi,
                List<string> paths,
                CancelToken cancelToken)
            {
                List<string> processedPaths = new List<string>(paths.Count);

                foreach (string path in paths)
                {
                    if (cancelToken.IsCancelled())
                        return false;

                    string metaPath = MetaPath.GetMetaPath(path);

                    if (plasticApi.GetWorkspaceTreeNode(wkInfo, path) != null)
                        processedPaths.Add(path);

                    if (plasticApi.GetWorkspaceTreeNode(wkInfo, metaPath) != null)
                        processedPaths.Add(metaPath);
                }

                if (cancelToken.IsCancelled())
                    return false;

                plasticApi.DeleteControlled(
                    wkInfo, processedPaths, DeleteModifiers.None, null);

                LogProcessedPaths("DeleteIfControlled", processedPaths);

                return processedPaths.Count > 0;
            }

            internal static bool MoveIfControlled(
                WorkspaceInfo wkInfo,
                IPlasticAPI plasticApi,
                ReadOnlyCollection<UVCSAssetPostprocessor.PathToMove> paths,
                CancelToken cancelToken)
            {
                List<string> processedPaths = new List<string>(paths.Count);

                foreach (UVCSAssetPostprocessor.PathToMove pathToMove in paths)
                {
                    if (cancelToken.IsCancelled())
                        return false;

                    if (plasticApi.GetWorkspaceTreeNode(wkInfo, pathToMove.SrcPath) != null)
                    {
                        plasticApi.Move(
                            wkInfo, pathToMove.SrcPath, pathToMove.DstPath,
                            MoveModifiers.None);

                        processedPaths.Add(string.Format("{0} to {1}",
                            pathToMove.SrcPath, pathToMove.DstPath));
                    }

                    if (cancelToken.IsCancelled())
                        return false;

                    string srcMetaPath = MetaPath.GetMetaPath(pathToMove.SrcPath);
                    string dstMetaPath = MetaPath.GetMetaPath(pathToMove.DstPath);

                    if (plasticApi.GetWorkspaceTreeNode(wkInfo, srcMetaPath) != null)
                    {
                        plasticApi.Move(
                            wkInfo, srcMetaPath, dstMetaPath,
                            MoveModifiers.None);

                        processedPaths.Add(string.Format("{0} to {1}",
                            srcMetaPath, dstMetaPath));
                    }
                }

                LogProcessedPaths("MoveIfControlled", processedPaths);

                return processedPaths.Count > 0;
            }

            internal static bool CheckoutIfControlledAndChanged(
                WorkspaceInfo wkInfo,
                IPlasticAPI plasticApi,
                IHiddenChangesFilter hiddenChangesFilter,
                List<string> paths,
                CancelToken cancelToken)
            {
                List<string> result = new List<string>();

                foreach (string path in paths)
                {
                    if (cancelToken.IsCancelled())
                        return false;

                    string metaPath = MetaPath.GetMetaPath(path);

                    WorkspaceTreeNode node = plasticApi.GetWorkspaceTreeNode(wkInfo, path);
                    WorkspaceTreeNode nodeMeta = plasticApi.GetWorkspaceTreeNode(wkInfo, metaPath);

                    if (node != null &&
                        !CheckWorkspaceTreeNodeStatus.IsCheckedOut(node) &&
                        !hiddenChangesFilter.IsHiddenChanged(path) &&
                        ChangedFileChecker.IsChanged(node.LocalInfo, path, wkInfo.IsDynamic, true))
                    {
                        result.Add(path);
                    }

                    if (nodeMeta != null &&
                        !CheckWorkspaceTreeNodeStatus.IsCheckedOut(nodeMeta) &&
                        !hiddenChangesFilter.IsHiddenChanged(metaPath) &&
                        ChangedFileChecker.IsChanged(nodeMeta.LocalInfo, metaPath, wkInfo.IsDynamic, true))
                    {
                        result.Add(metaPath);
                    }
                }

                if (cancelToken.IsCancelled())
                    return false;

                bool hasPathsToProcess = result.Count > 0;

                if (hasPathsToProcess)
                {
                    plasticApi.Checkout(wkInfo, result.ToArray(), CheckoutModifiers.None);
                }

                LogProcessedPaths("CheckoutIfControlledAndChanged", result);

                return hasPathsToProcess;
            }

            static AddOptions GetDefaultAddOptions()
            {
                AddOptions options = new AddOptions();
                options.AddPrivateParents = true;
                options.NeedCheckPlatformPath = true;
                return options;
            }
        }

        object mLock = new object();

        List<string> mAssetsProcessorPathsToAdd = new List<string>();
        List<string> mAssetsProcessorPathsToDelete = new List<string>();
        List<string> mAssetsProcessorPathsToCheckout = new List<string>();
        List<UVCSAssetPostprocessor.PathToMove> mAssetsProcessorPathsToMove = new List<UVCSAssetPostprocessor.PathToMove>();
        List<string> mPathsToCheckout = new List<string>();

        IWorkspaceWindow mWorkspaceWindow;
        ViewHost mViewHost;

        volatile bool mIsEnabled;
        volatile ManualResetEvent mResetEvent = new ManualResetEvent(false);
        CancelToken mCancelToken = new CancelToken();

        readonly bool mIsGluonMode = false;
        readonly GluonIncomingChangesUpdater mGluonIncomingChangesUpdater;
        readonly IncomingChangesUpdater mDeveloperIncomingChangesUpdater;
        readonly IPendingChangesUpdater mPendingChangesUpdater;
        readonly IDisableAssetsProcessor mDisableAssetsProcessor;
        readonly IAssetStatusCache mAssetStatusCache;
        readonly IPlasticAPI mPlasticAPI;
        readonly WorkspaceInfo mWkInfo;

        static readonly ILog mLog = PlasticApp.GetLogger("WorkspaceOperationsMonitor");
    }
}