using System;
using System.Runtime.InteropServices;
using System.Collections.Generic;
using System.Text;
using System.IO;
using Microsoft.Win32.SafeHandles;
using System.Threading;
using IReaper;
using IReaper.Running;
using IReaper.CourseData;
using IReaper.Properties;
namespace IReaper.FileData{
public delegate bool CourseFileTestFunctionDelegate(CourseFileData file);
/// <summary>
/// CourseFileDataStorage
///
/// </summary>
public unsafe class CourseFileDataManager
{
static FileStream recordFile;
readonly static List<CourseFileDataStorage> allstorage = new List<CourseFileDataStorage>();
readonly static List<int> keyList = new List<int>();
static CourseFileDataStorage* updateBuf = (CourseFileDataStorage*)Marshal.AllocHGlobal(sizeof(CourseFileDataStorage));
static RunningCourseFileDataCollection uncompleted = new RunningCourseFileDataCollection(true);
static Queue<long> storageRecycleQueue = new Queue<long>();
//[ThreadStatic]
static byte[] writeBuffer = new byte[sizeof(CourseFileDataStorage)];
static byte[] readBuffer = new byte[sizeof(CourseFileDataStorage)];
static CourseFileDataManager()
{
CheckAndOpen();//
}
#region
/// <summary>
///
/// </summary>
static void CheckAndOpen()
{
if (recordFile == null || recordFile.SafeFileHandle.IsClosed)
{
OpenRecordFile();
}
}
/// <summary>
///
/// </summary>
public static void OpenRecordFile()
{
//
string recodPath = Path.Combine(Settings.Default.RootPath, ".record");
//
FileStream tempRecordFile = null;
try
{
//
tempRecordFile = new FileStream(recodPath, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.Read, sizeof(CourseFileDataStorage), FileOptions.RandomAccess | FileOptions.WriteThrough);
}
catch
{
//
if (tempRecordFile != null)
tempRecordFile.Close();
throw;
}
//
//
CloseRecordFile();
//
recordFile = tempRecordFile;
}
/// <summary>
///
/// </summary>
public static void CloseRecordFile()
{
if (recordFile != null)
recordFile.Close();
}
#endregion
#region
/*
* 2006.7.12
*
* 1.
* 2.
* ----------------------------------------------------------------
* 1.,LoadAllDataDispatch
* 2.
* 3.
*/
/// <summary>
///
/// </summary>
/// <param name="storage"></param>
public static void ApplyNewStorage(ref CourseFileDataStorage storage)
{
if (keyList.Contains(storage.GetHashCode()))
return;
//
lock (recordFile)
{
long index = -1;
lock (storageRecycleQueue)
{
if (storageRecycleQueue.Count > 0)
{
index = storageRecycleQueue.Dequeue();
}
}
if (index < 0)
{
//
index = recordFile.Length;
//
recordFile.SetLength(index + sizeof(CourseFileDataStorage));
}
storage.Index = index;
//
allstorage.Add(storage);
keyList.Add(storage.GetHashCode());
System.Diagnostics.Debug.Assert(storage.Index >= 0);
//
storage.Flush();
}
}
/*
*
*
*/
static CourseFileDataStorage emptyStorage = new CourseFileDataStorage();
static void RemoveStorage(ref CourseFileDataStorage storage)
{
//
if (!keyList.Contains(storage.GetHashCode()))
return;
//
long index = storage.Index;
//
lock (storageRecycleQueue)
{
storageRecycleQueue.Enqueue(index);
}
//
keyList.Remove(storage.GetHashCode());
allstorage.Remove(storage);
//()
storage.Index = -1;
storage.LifetimeStatue = LifetimePosition.TaskCreated;
storage.RunState = RunningStatue.Created;
storage.Read = 0;
storage.Length = 0;
storage.FileName = "";
//,
emptyStorage.Index = index;
WriteCourseFileDataStorage(emptyStorage);
}
/// <summary>
///
/// </summary>
/// <param name="courses"></param>
/// <param name="statue"></param>
/// <returns></returns>
public static List<CourseFileData> CreateFileList(CourseCollection courses, FileStatue statue)
{
//courses
if (courses == null)
return null;
//List<CourseFileData>
List<CourseFileData> list = new List<CourseFileData>();
//loop and add
foreach (Course course in courses)
{
if (IsCourseFileDataMatchFileStatue(course.PPT, statue))
{ list.Add(course.PPT); }
if (IsCourseFileDataMatchFileStatue(course.QA, statue))
{ list.Add(course.QA); }
if (IsCourseFileDataMatchFileStatue(course.Video, statue))
{ list.Add(course.Video); }
if (IsCourseFileDataMatchFileStatue(course.Code, statue))
{ list.Add(course.Code); }
if (IsCourseFileDataMatchFileStatue(course.WMV, statue))
{ list.Add(course.WMV); }
if (IsCourseFileDataMatchFileStatue(course.MP3, statue))
{ list.Add(course.MP3); }
if (IsCourseFileDataMatchFileStatue(course.MP4, statue))
{ list.Add(course.MP4); }
}
return list;
}
/// <summary>
/// CourseFileDataFileStatue
/// </summary>
/// <param name="File"></param>
/// <param name="statue"></param>
/// <returns></returns>
private static bool IsCourseFileDataMatchFileStatue(CourseFileData File, FileStatue statue)
{
bool checkInComplete = (statue & FileStatue.InCompleted) == FileStatue.InCompleted;
bool checkComplete = (statue & FileStatue.Completed) == FileStatue.Completed;
if (checkComplete && CourseFileData.IsCourseFileFinished(File))
return true;
if (checkInComplete && CourseFileData.IsCourseFileExist(File) && !CourseFileData.IsCourseFileFinished(File))
return true;
return false;
}
public static List<CourseFileData> CreateFileList(CourseCollection courses, FileType type, CourseFileTestFunctionDelegate testFunc)
{
//courses
if (courses == null)
return null;
//List<CourseFileData>
List<CourseFileData> list = new List<CourseFileData>();
//loop and add
Course course = null;
for (int i = 0; i < courses.Count; i++)
{
course = courses[i];
switch (type)
{
case FileType.All:
if (course.PPT != null && testFunc(course.PPT))
{
list.Add(course.PPT);
}
if (course.Video != null && testFunc(course.Video))
{
list.Add(course.Video);
}
if (course.Code != null && testFunc(course.Code))
{
list.Add(course.Code);
}
if (course.QA != null && testFunc(course.QA))
{
list.Add(course.QA);
}
if (course.MP3 != null && testFunc(course.MP3))
{
list.Add(course.MP3);
}
if (course.MP4 != null && testFunc(course.MP4))
{
list.Add(course.MP4);
}
if (course.WMV != null && testFunc(course.WMV))
{
list.Add(course.WMV);
}
break;
case FileType.Code:
if (course.Code != null && testFunc(course.Code))
{
list.Add(course.Code);
}
break;
case FileType.PPT:
if (course.PPT != null && testFunc(course.PPT))
{
list.Add(course.PPT);
}
break;
case FileType.Video:
if (course.Video != null && testFunc(course.Video))
{
list.Add(course.Video);
}
break;
case FileType.QA:
if (course.QA != null && testFunc(course.QA))
{
list.Add(course.QA);
}
break;
case FileType.MP3:
if (course.MP3 != null && testFunc(course.MP3))
{
list.Add(course.MP3);
}
break;
case FileType.MP4:
if (course.MP4 != null && testFunc(course.MP4))
{
list.Add(course.MP4);
}
break;
case FileType.Zune:
if (course.WMV != null && testFunc(course.WMV))
{
list.Add(course.WMV);
}
break;
default:
break;
}
}
return list;
}
/// <summary>
///
///
///
/// </summary>
/// <param name="Data"></param>
public static void RemoveFileData(CourseFileData Data)
{
if (Data == null)
return;
//
try
{
if (File.Exists(Data.FilePath))
{
File.Delete(Data.FilePath);
}
//CourseFileData
InitFileData(ref Data);
}
catch (IOException)
{
}
finally
{
//
CourseDataManager.CheckAndRemoveCourseRoot(Data.Owner);
}
}
/// <summary>
/// CourseFileData
/// </summary>
/// <param name="Data"></param>
public static void InitFileData(ref CourseFileData Data)
{
Data.Message = "";
RemoveStorage(ref Data.Storage);
Data.LifetimeStatue = LifetimePosition.TaskCreated;
Data.RunState = RunningStatue.Created;
}
/// <summary>
///
/// </summary>
/// <param name="storage"></param>
public static void UpdateCourseFileDataStorage(CourseFileDataStorage storage)
{
//
if (!keyList.Contains(storage.GetHashCode()))
return;
WriteCourseFileDataStorage(storage);
}
/// <summary>
///
/// </summary>
/// <param name="storage"></param>
private static void WriteCourseFileDataStorage(CourseFileDataStorage storage)
{
if (storage.Index < 0)
return;
lock (recordFile)
{
recordFile.Position = storage.Index;
int* iRead = stackalloc int[1];
byte* buf = (byte*)(&storage);
Utils.WriteFile(recordFile.SafeFileHandle, buf, sizeof(CourseFileDataStorage), iRead, (NativeOverlapped*)0);
}
}
#endregion
#region
/// <summary>
/// ,
/// </summary>
public static void LoadAllData()
{
//
if (recordFile == null || recordFile.SafeFileHandle.IsClosed)
{
//
OpenRecordFile();
}
//allStorage
allstorage.Clear();
//clear keyedlist
keyList.Clear();
//Position
recordFile.Position = 0;
//
CourseFileDataStorage* storage = stackalloc CourseFileDataStorage[1];
byte* buffer = (byte*)storage;
//
int iRead = 0;
//
SafeFileHandle handle = recordFile.SafeFileHandle;
CourseFileDataStorage tpStorage;
while ((iRead = recordFile.Read(readBuffer, 0, sizeof(CourseFileDataStorage))) > 0)
{
if (iRead == sizeof(CourseFileDataStorage))//
{
tpStorage = new CourseFileDataStorage();
fixed (byte* ptrBuffer = &(readBuffer[0]))
{
tpStorage = *(CourseFileDataStorage*)ptrBuffer; ;
}
tpStorage.Index = recordFile.Position - sizeof(CourseFileDataStorage);
/*
* 2006.7.12
* ID0
*
*/
if (tpStorage.ID.Length == 0) //
{
lock (storageRecycleQueue)
{
storageRecycleQueue.Enqueue(tpStorage.Index);
}
continue;
}
if (!keyList.Contains(tpStorage.GetHashCode()))
{
//
allstorage.Add(tpStorage);
keyList.Add(tpStorage.GetHashCode());
}
}
else if (iRead == 0)
break;
}
//
Vacuum();
for (int i = 0; i < allstorage.Count; i++)
{
//
CourseFileDataStorage s = allstorage[i];
LoadStorageChecker(&s);
allstorage[i] = s;
}
}
/// <summary>
///
/// </summary>
/// <param name="storage"></param>
private static void LoadStorageChecker(CourseFileDataStorage* storage)
{
//runstate
if (storage->RunState != RunningStatue.Created &&
storage->RunState != RunningStatue.Error &&
storage->RunState != RunningStatue.Finished)
{
storage->RunState = RunningStatue.Stopped;
}
if (storage->LifetimeStatue == LifetimePosition.DownloadProcessed)
storage->RunState = RunningStatue.Finished;
}
/// <summary>
///
/// </summary>
private static void Vacuum()
{
/* :LoadAllData
*
*
*
*/
//
lock (recordFile)
{
long newSize = sizeof(CourseFileDataStorage) * allstorage.Count;
/* allstorage
* allstorage
*
*
*
*
*/
for (int i = allstorage.Count - 1; i > 0; i--)
{
CourseFileDataStorage storage = allstorage[i];
if (storage.Index < newSize)
continue;
long index = GetNextNestedSpace(newSize);
if (index < 0)
{
recordFile.SetLength(newSize);
return;
}
else
{
storage.Index = index;
WriteCourseFileDataStorage(storage);
allstorage[i] = storage;
}
}
storageRecycleQueue.Clear();
recordFile.SetLength(newSize);
}
}
/// <summary>
/// size
/// </summary>
/// <param name="size"></param>
/// <returns></returns>
private static long GetNextNestedSpace(long size)
{
lock (storageRecycleQueue)
{
while (storageRecycleQueue.Count > 0)
{
long index = storageRecycleQueue.Dequeue();
if (index < size)
return index;
}
}
return -1;
}
/// <summary>
/// storageCourse
/// </summary>
public static void DispathStorage()
{
Dictionary<string, Course> dic = CourseDataManager.AllCourses.KeydList;
CourseFileDataCollection files = Core.CoreData[CoreDataType.CurrentViewedFiles] as CourseFileDataCollection;
for (int i = 0; i < allstorage.Count; i++)
{
CourseFileDataStorage storage = allstorage[i];
if (dic.ContainsKey(storage.ID))
{
Course course = dic[storage.ID];
CourseFileData file = null;
if (course != null)
{
switch (storage.Type)
{
case FileType.Code:
file = course.Code;
break;
case FileType.PPT:
file = course.PPT;
break;
case FileType.Video:
file = course.Video;
break;
case FileType.QA:
file = course.QA;
break;
case FileType.MP3:
file = course.MP3;
break;
case FileType.MP4:
file = course.MP4;
break;
case FileType.Zune:
file = course.WMV;
break;
}
if (file == null)
{ continue; }
/*
* 1.
* 2.
* 3.RunState Created,Finished
*
*/
if (storage.LifetimeStatue == LifetimePosition.DownloadProcessed)
{
if (File.Exists(Path.Combine(Properties.Settings.Default.RootPath,storage.FilePath)))
{
CourseDataManager.CompletedCourses.Add(course);
}
else
{
RemoveStorage(ref storage);
i--;
}
}
else if (storage.RunState != RunningStatue.Created && storage.RunState != RunningStatue.Finished)
{
files.Add(file);
}
/*
*
*
*
*/
else
{
RemoveStorage(ref storage);
}
file.Storage = storage;
}
}
}
bool hasCourse = (bool)Core.CoreData[CoreDataType.HasCourse];
if (hasCourse)
{
Core.CoreData[CoreDataType.Dispatched] = true;
}
}
public static unsafe void GenerateRecordFile(IEnumerable<CourseFileData> files, string Path)
{
//
FileStream oStream = new FileStream(Path,
FileMode.Create,
FileAccess.ReadWrite,
FileShare.None);
try
{
CourseFileDataStorage* storage = stackalloc CourseFileDataStorage[1];
int* iWrite = stackalloc int[1];
byte* buffer = (byte*)storage;
int totalWrote = 0;
//
foreach (CourseFileData cf in files)
{
*storage = cf.Storage;
storage->Index = -1;
storage->RootPath = PathManager.Manager.GetRelativePath(cf, IReaper.PathManager.PathPolicyType.Plain);
storage->Index = totalWrote;
Utils.WriteFile(oStream.SafeFileHandle, buffer, sizeof(CourseFileDataStorage), iWrite, (NativeOverlapped*)0);
totalWrote += *iWrite;
}
}
finally
{
if(oStream != null)
oStream.Close();
}
}
public static CourseFileDataStorage[] LoadExportList(string path)
{
//
if (!File.Exists(path))
return null;
//
FileStream oStream = new FileStream(path,
FileMode.Open,
FileAccess.Read,
FileShare.None);
List<CourseFileDataStorage> result = new List<CourseFileDataStorage>();
try
{
//
CourseFileDataStorage* ptrStorage = stackalloc CourseFileDataStorage[1];
void* buffer = (void*)ptrStorage;
int* iRead = stackalloc int[1];
//load parameters
Dictionary<string, Course> dic = CourseDataManager.AllCourses.KeydList;
//
do
{
//read
Utils.ReadFile(oStream.SafeFileHandle, buffer, sizeof(CourseFileDataStorage), iRead, (NativeOverlapped*)0);
//charge if read full
if (*iRead != sizeof(CourseFileDataStorage))
break;//,
ptrStorage->Index = -1;//prevent from save to .record.
CourseFileDataStorage storage = new CourseFileDataStorage();
storage = *ptrStorage;
result.Add(storage);
} while (true);
return result.ToArray();
}
finally
{
if (oStream != null)
oStream.Close();
}
}
#endregion
public static List<CourseFileDataStorage> AllStorage
{
get { return allstorage; }
}
}
}
|