/*
******************************************************************************
This file is part of BigWoo.NET.
BigWoo.NET is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
BigWoo.NET is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with BigWoo.NET; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
architected and written by
matt raffel
matt.raffel@mindspring.com
copyright (c) 2008 by matt raffel unless noted otherwise
******************************************************************************
*/
#region using statements
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Security.AccessControl;
using CodeCounter.Library;
#endregion
namespace CodeCounter
{
///
/// This is the class that processes a file. If manages the "conversation" with the
/// ICodeCounterLogic implementation occuring during reading through the file.
///
public class CodeCounterEngine
{
#region private data
private FileInfo _fileInfo = null;
private long _statementLines = 0L;
private long _totalLines = 0L;
private long _codeLines = 0L;
private long _commentLines = 0L;
private long _errors = 0L;
private CodeCounterLogicImplementerList _implementerList = null;
#endregion
#region properties
///
/// FileInfo instance of the file we want to count code.
///
public FileInfo File
{
get { return _fileInfo; }
set { _fileInfo = value; }
}
#endregion
#region event firing helpers
///
/// Fires the OnStartEvent if there are listeners. This
/// event is fired once per file.
///
/// CodeCounterUpdateEventArgs
private void FireOnStartEvent(CodeCounterUpdateEventArgs startArgs)
{
if (null != OnStart)
{
OnStart(this, startArgs);
}
}
///
/// Fires OnUpdate event if there are listeners. This event
/// is fired approx every 250 lines read in the file.
///
/// CodeCounterUpdateEventArgs
private void FireOnUpdateEvent(CodeCounterUpdateEventArgs updateArgs)
{
if (null != OnUpdate)
OnUpdate(this, updateArgs);
}
///
/// Fires OnFinish event if there are listeners. This event
/// is fired once per file
///
/// CodeCounterFinishedEventArgs
private void FireOnFinishedEvent(CodeCounterFinishedEventArgs finishedArgs)
{
if (null != OnFinish)
OnFinish(this, finishedArgs);
}
#endregion
#region private methods
///
/// Find the ICodeCounterLogic implementation that can work with the file type we
/// have found.
///
/// Thrown if no logic is found for the given file type
/// Thrown if no logic is defined in the config file
/// ICodeCounterLogic
private ICodeCounterLogic GetFileProcessor(FileInfo info)
{
if (null == _implementerList)
{
_implementerList = CodeCounterLogicImplementerList.LoadFromConfigFile();
if (0 == _implementerList.Count)
throw new ConfigurationFileException("No code counter logic found.");
}
ICodeCounterLogic handler = null;
foreach (CodeCounterLogicImplementer implementer in _implementerList)
{
ICodeCounterLogic potentialHandler = implementer.Implementer;
if (true == potentialHandler.CanProcessFile(info.Name))
{
handler = potentialHandler;
break;
}
}
if (null == handler)
throw FileTypeNotSupportedException.CreateException(info);
return handler;
}
///
/// Each count is file specific. It is up to the consumer to process
/// those values
///
private void InitializeCounters()
{
_statementLines = 0L;
_totalLines = 0L;
_codeLines = 0L;
_commentLines = 0L;
_errors = 0L;
}
#endregion
#region public methods
///
/// The heart of the counting of lines
///
public void Count()
{
// nothing to process if we have no file name
if (null == _fileInfo)
return;
// ensures member data is reset to default
InitializeCounters();
long linesRead = 0L;
// event arg initialization
CodeCounterFinishedEventArgs finishedArgs = new CodeCounterFinishedEventArgs(_fileInfo, CodeCounterFunctionTypes.Error);
CodeCounterUpdateEventArgs startArgs = new CodeCounterUpdateEventArgs(_fileInfo, CodeCounterFunctionTypes.ProcessingFiles);
CodeCounterUpdateEventArgs updateEventArg = new CodeCounterUpdateEventArgs(_fileInfo, CodeCounterFunctionTypes.ProcessingFiles);
try
{
// let console know we found a file
FireOnStartEvent(startArgs);
// find the appropriate handler for the type
ICodeCounterLogic processor = GetFileProcessor(_fileInfo);
bool _processorDeterminesEmpty = processor.EngineCanDetermineBlankLines();
// allow the ICodeCounterLogic implementation a chance to
// do something with the file
processor.PrefileProcessing(_fileInfo.FullName);
// now we can read through each line and count what it contains
using (TextReader fileReader = _fileInfo.OpenText())
{
string line = "";
while (null != (line = fileReader.ReadLine()))
{
linesRead++;
long mod = (linesRead % 250L);
if (0L == mod)
{
updateEventArg.Lines = linesRead;
FireOnUpdateEvent(updateEventArg);
}
string trimmed = line.Trim();
// when the processor does not know or care how empty lines are determined
// we will do it by testing for null or empty line.
if ((true == _processorDeterminesEmpty) && (true == string.IsNullOrEmpty(trimmed)))
continue;
// now we are ready to let the implemention decide what the line is
CodeCounterLineType lineType = processor.LineType(trimmed);
switch (lineType)
{
case CodeCounterLineType.Statement:
case CodeCounterLineType.Code:
_codeLines++;
break;
case CodeCounterLineType.StatementAndComment:
case CodeCounterLineType.CodeAndComment:
_codeLines++;
_commentLines++;
break;
case CodeCounterLineType.CommentOnly:
_commentLines++;
break;
default:
break;
}
if (CodeCounterLineType.EmptyLine != lineType)
_totalLines++;
}
// yay we are done
fileReader.Close();
// allow the counter implemenation any final moments
processor.PostfileProcessing(_fileInfo.FullName);
finishedArgs.Function = CodeCounterFunctionTypes.Summarizing;
}
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine(ex.Message);
finishedArgs.Function = CodeCounterFunctionTypes.Error;
finishedArgs.AdditionalData = ex;
}
finally
{
finishedArgs.FileInfo = _fileInfo;
finishedArgs.CodeLines = _codeLines;
finishedArgs.CommentLines = _commentLines;
finishedArgs.StatementLines = _statementLines;
finishedArgs.Lines = _totalLines;
_fileInfo = null;
FireOnFinishedEvent(finishedArgs);
}
}
#endregion
#region event member delcaration
public event CodeCounterUpdateEvent OnStart;
public event CodeCounterUpdateEvent OnUpdate;
public event CodeCounterFinishedEvent OnFinish;
#endregion
}
}