using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using Xah.MediaCatalogerLib.Model;
using Xah.MediaCatalogerLib.Model.Files;
namespace Xah.MediaCatalogerLib.TreeProcess
{
public class FolderProcessor : ICancelable
{
public delegate void OnProcessStepStatusCb(string name, bool stop, int index, int total);
public event OnProcessStepStatusCb OnProcessStepStatus;
public enum FileOperation { Add, Skip, Remove }
public delegate void OnFileOperationCb(FileOperation operation, string path);
public event OnFileOperationCb OnFileOperation;
public delegate void OnFileProcessedProgressCb(int index, int total);
public event OnFileProcessedProgressCb OnFileProcessedProgress;
private readonly TreeFolderItem treeRoot;
private readonly MediaCatalog db;
private readonly MediaFolder folder;
private ICancelable currentVisitor;
private Thread thread;
private bool cancelled = false;
private int totalFileCount = 0;
private int processedFileCount = 0;
public bool IsFinished
{
get { return (thread == null) || (thread.ThreadState == ThreadState.Stopped); }
}
#region ICancelable Members
public bool IsCancelled
{
get { return cancelled; }
}
public void Cancel()
{
cancelled = true;
if (currentVisitor != null)
currentVisitor.Cancel();
if (thread != null)
thread.Join();
}
#endregion
public FolderProcessor(MediaCatalog db, MediaFolder folder)
{
this.db = db;
this.folder = folder;
this.treeRoot = new TreeFolderItem(folder.Location);
}
public void Process()
{
if (thread != null) return;
thread = new Thread(new ThreadStart(ProcessThread));
thread.Start();
}
private void ProcessThread()
{
const int TotalSteps = 4;
int stepIndex = 1;
string stepName = String.Empty;
/////////////////////////////////////////////////////////////////
// 1. POPULATE
stepName = "Populate";
FireProcessStepStatus(stepName, false, stepIndex, TotalSteps);
PopulateTreeVisitor constructor = new PopulateTreeVisitor(folder.Extensions);
currentVisitor = constructor;
treeRoot.Accept(constructor);
FireProcessStepStatus(stepName, true, stepIndex++, TotalSteps);
if (IsCancelled) return;
/////////////////////////////////////////////////////////////////
// 2. LIST FILES
stepName = "List Files";
FireProcessStepStatus(stepName, false, stepIndex, TotalSteps);
FileListerTreeVisitor lister = new FileListerTreeVisitor();
currentVisitor = lister;
treeRoot.Accept(lister);
totalFileCount = lister.Files.Count;
FireProcessStepStatus(stepName, true, stepIndex++, TotalSteps);
if (IsCancelled) return;
/////////////////////////////////////////////////////////////////
// 3. REMOVE
stepName = "Remove Non-existing Files";
FireProcessStepStatus(stepName, false, stepIndex, TotalSteps);
if (folder.ExistsLocation)
{
// Remove non existing file records related with folder
List<string> filePaths = lister.Files.Select(x => x.Path).AsParallel().ToList();
List<MediaFile> deleteList = folder.Files.Where(x => !filePaths.Contains(x.Path)).AsParallel().ToList();
if (deleteList.Count > 0)
{
deleteList.ForEach(x =>
{
FireFileOperation(FileOperation.Remove, x.Path);
x.Remove(db);
});
db.SaveChanges();
}
}
FireProcessStepStatus(stepName, true, stepIndex++, TotalSteps);
/////////////////////////////////////////////////////////////////
// 4. ADD
stepName = "Add New Files";
FireProcessStepStatus(stepName, false, stepIndex, TotalSteps);
System.Diagnostics.Stopwatch stopwatch = System.Diagnostics.Stopwatch.StartNew();
AFileProcessorTreeVisitor processor = AFileProcessorTreeVisitor.Create(db, folder);
currentVisitor = processor;
processor.OnFileProcessed += new AFileProcessorTreeVisitor.OnFileProcessedCb(Processor_OnFileProcessed);
treeRoot.Accept(processor);
stopwatch.Stop();
System.Diagnostics.Trace.TraceInformation("Add New Files FileProcessorTreeVisitor Stop ({0} elapsed)", stopwatch.Elapsed.ToString());
FireProcessStepStatus(stepName, true, stepIndex++, TotalSteps);
}
private void Processor_OnFileProcessed(TreeFileItem fileItem)
{
processedFileCount++;
if (OnFileProcessedProgress != null)
OnFileProcessedProgress(processedFileCount, totalFileCount);
FileOperation operation = (fileItem.Tag == null) ? FileOperation.Skip : FileOperation.Add;
FireFileOperation(operation, fileItem.Path);
}
private void FireFileOperation(FileOperation operation, string path)
{
if (OnProcessStepStatus != null)
OnFileOperation(operation, path);
}
private void FireProcessStepStatus(string name, bool stop, int index, int total)
{
if (OnProcessStepStatus != null)
OnProcessStepStatus(name, stop, index, total);
}
}
}