using System;
using System.Text;
using System.Collections;
using AnticipatingMinds.Genesis.CodeDOM;
using System.Diagnostics;
namespace AnticipatingMinds.Genesis.Effectors{
public abstract class CodeStream
{
#region Nested Classes
public enum TransformationType
{
Insert,
Remove,
Append
}
private class TextTransformation
{
public TransformationType TransformationType;
public object[] Arguments;
}
#endregion
protected CodeStream()
{
}
public virtual void BeginChanges(string changesDescription)
{
transformationsQueue.Clear();
}
public abstract void AddFile(string projectFileName,string fileName,string content);
public abstract void DeleteFile(string projectFileName,string fileName);
public virtual int Find(string fileName, int startIndex, string value)
{
return GetCode(fileName).IndexOf(value,startIndex);
}
public virtual int FindAny(string fileName, int startIndex, string value)
{
return GetCode(fileName).IndexOfAny(value.ToCharArray(),startIndex);
}
public virtual int FindReverse(string fileName, int startIndex, string value)
{
return GetCode(fileName).LastIndexOf(value,startIndex);
}
public virtual int FindReverseAny(string fileName, int startIndex, string value)
{
return GetCode(fileName).LastIndexOfAny(value.ToCharArray(),startIndex);
}
public virtual void Insert(string fileName, int startPosition, string code)
{
Debug.Assert(startPosition != -1,"Insert start index must be defined");
TextTransformation transformation = new TextTransformation();
transformation.TransformationType = TransformationType.Insert;
transformation.Arguments = new object[]{fileName,GetPositionBookmark(fileName,startPosition),code};
transformationsQueue.Add(transformation);
//DumpBookmarks(fileName);
}
public virtual void Append(string fileName,string code)
{
TextTransformation transformation = new TextTransformation();
transformation.TransformationType = TransformationType.Append;
transformation.Arguments = new object[]{fileName,code};
transformationsQueue.Add(transformation);
//DumpBookmarks(fileName);
}
public virtual void Remove(string fileName, int startPosition, int length)
{
Debug.Assert(startPosition != -1,"Remove start index must be defined");
TextTransformation transformation = new TextTransformation();
transformation.TransformationType = TransformationType.Remove;
transformation.Arguments = new object[]{fileName,GetPositionBookmark(fileName,startPosition),length};
transformationsQueue.Add(transformation);
//DumpBookmarks(fileName);
}
public abstract string GetCode(string fileName);
public abstract void SetCode(string fileName,string code);
public virtual void CommitChanges()
{
PerformCodeChanges();
}
public virtual void RollbackChanges()
{
transformationsQueue.Clear();
ClearBookmarks();
}
public void PerformCodeChanges()
{
///We comit changes in two passes - first we remove all
///the code marked for removal
///than we insert & append all the code marked for insertion and appendance.
///Such order helps to resolve some of the bookmark positioning conflicts
foreach(TextTransformation tranformation in transformationsQueue)
if(tranformation.TransformationType == TransformationType.Remove)
{
string fileName = tranformation.Arguments[0] as string;
int startPosition = GetBookmarkPosition(fileName,tranformation.Arguments[1]);
int length = (int)tranformation.Arguments[2];
Debug.Assert(startPosition != -1,"Bookmark position must be present here");
SetCode(fileName,GetCode(fileName).Remove(startPosition,length));
UpdateBookmarkPositions(fileName,startPosition,-length);
}
foreach(TextTransformation tranformation in transformationsQueue)
{
if(tranformation.TransformationType == TransformationType.Append)
{
string fileName = tranformation.Arguments[0] as string;
string code = tranformation.Arguments[1] as string;
SetCode(fileName,GetCode(fileName)+code);
}
if(tranformation.TransformationType == TransformationType.Insert)
{
string fileName = tranformation.Arguments[0] as string;
int startPosition = GetBookmarkPosition(fileName,tranformation.Arguments[1]);
string code = tranformation.Arguments[2] as string;
Debug.Assert(startPosition != -1,"Bookmark position must be present here");
SetCode(fileName,GetCode(fileName).Insert(startPosition,code));
UpdateBookmarkPositions(fileName,startPosition,code.Length);
}
}
transformationsQueue.Clear();
ClearBookmarks();
}
protected object GetPositionBookmark(string fileName,int position)
{
IDictionary bookmarks = GetFileBookmarks(fileName);
foreach(DictionaryEntry entry in bookmarks)
if((int) entry.Value == position)
return entry.Key;
object bookmark = new object();
bookmarks[bookmark] = position;
return bookmark;
}
protected int GetBookmarkPosition(string fileName,object bookmark)
{
IDictionary bookmarks = GetFileBookmarks(fileName);
if(bookmarks.Contains(bookmark))
return (int) bookmarks[bookmark];
return -1;
}
protected void UpdateBookmarkPositions(string fileName,int startPosition, int offset)
{
//DumpBookmarks(fileName);
IDictionary fileBookmarks = GetFileBookmarks(fileName);
ArrayList bookmarks = new ArrayList(fileBookmarks.Keys);
foreach(object bookmark in bookmarks)
if((int) fileBookmarks[bookmark] > startPosition)
fileBookmarks[bookmark] = (int)fileBookmarks[bookmark] + offset;
//DumpBookmarks(fileName);
}
protected IDictionary GetFileBookmarks(string fileName)
{
if(bookmarksPerFile[fileName] == null)
bookmarksPerFile[fileName] = new Hashtable();
return bookmarksPerFile[fileName] as IDictionary;
}
protected void ClearBookmarks()
{
bookmarksPerFile.Clear();
}
private Hashtable bookmarksPerFile = new Hashtable();
private ArrayList transformationsQueue = new ArrayList();
#region Diagnostics
[Conditional("DEBUG")]
private void DumpBookmarks(string fileName)
{
string code = GetCode(fileName);
Debug.WriteLine("--- Bookmarks Dump ---");
foreach(DictionaryEntry bookmarkEntry in GetFileBookmarks(fileName))
{
object bookmark = bookmarkEntry.Key;
int position = (int) bookmarkEntry.Value;
if(position < code.Length-10 && position > 0)
Debug.WriteLine(String.Format("Bookmark: {0} Position: {1} Code: {2}",bookmark.GetHashCode(),position,code.Substring(position,10)));
else
Debug.WriteLine(String.Format("Bookmark: {0} Position: {1}",bookmark.GetHashCode(),position));
}
}
[Conditional("DEBUG")]
private void DumpCode(string fileName)
{
Debug.WriteLine("--- Code Dump ---");
Debug.WriteLine(GetCode(fileName));
}
#endregion Diagnostics
}
}
|