// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Windows.Forms;
namespace Flax.Stats
{
///
/// Single code frame data
///
public sealed class CodeFrameNode : IDisposable
{
private static string[] ignoredFolders = new[]
{
".vs",
".git",
"obj",
"bin",
"packages",
"thirdparty",
"3rdparty",
"flaxdeps",
"platforms",
"flaxapi",
};
///
/// Array with all child nodes
///
public CodeFrameNode[] Children;
///
/// Amount of lines of code
///
public long[] LinesOfCode;
///
/// Size of the node on the hard drive
///
public long SizeOnDisk;
///
/// Amount of files
///
public int FilesCount;
///
/// Short directory name
///
public string ShortName;
///
/// Gets total amount of lines of code in that node and all child nodes
///
public long TotalLinesOfCode
{
get
{
long result = 0;
for (int i = 0; i < (int)Languages.Max; i++)
{
result += LinesOfCode[i];
}
for (int i = 0; i < Children.Length; i++)
{
result += Children[i].TotalLinesOfCode;
}
return result;
}
}
///
/// Gets total amount of memory used by that node and all child nodes
///
public long TotalSizeOnDisk
{
get
{
long result = SizeOnDisk;
for (int i = 0; i < Children.Length; i++)
{
result += Children[i].TotalSizeOnDisk;
}
return result;
}
}
///
/// Gets total amount of files used by that node and all child nodes
///
public long TotalFiles
{
get
{
long result = FilesCount;
for (int i = 0; i < Children.Length; i++)
{
result += Children[i].TotalFiles;
}
return result;
}
}
///
/// Gets code frame node with given index
///
/// Code frame node index
/// Code frame node
public CodeFrameNode this[int index]
{
get { return Children[index]; }
}
///
/// Gets code frame node with given name
///
/// Code frame node index
/// Code frame node
public CodeFrameNode this[string name]
{
get
{
for (int i = 0; i < Children.Length; i++)
if (Children[i].ShortName == name)
return Children[i];
return null;
}
}
///
/// Init
///
/// Directory name
/// Amount of files
/// Lines of code
/// Size on disk
/// Child nodes
public CodeFrameNode(string name, int filesCnt, long[] lines, long size, CodeFrameNode[] children)
{
if(lines == null || lines.Length != (int)Languages.Max)
throw new InvalidDataException();
ShortName = name;
FilesCount = filesCnt;
Children = children;
LinesOfCode = lines;
SizeOnDisk = size;
}
///
/// Gets total amount of lines of code per language
///
/// Language
/// Result amount of lines
public long GetTotalLinesOfCode(Languages language)
{
long result = 0;
result += LinesOfCode[(int)language];
for (int i = 0; i < Children.Length; i++)
{
result += Children[i].GetTotalLinesOfCode(language);
}
return result;
}
///
/// Capture data from the folder
///
/// Folder path to capture
/// Created code frame of null if cannot create that
public static CodeFrameNode Capture(DirectoryInfo folder)
{
// Get all files from that folder
FileInfo[] files;
try
{
files = folder.GetFiles("*.*");
}
catch (UnauthorizedAccessException)
{
return null;
}
catch (Exception exception)
{
MessageBox.Show(exception.Message);
return null;
}
// Count data
long[] lines = new long[(int)Languages.Max];
for (int i = 0; i < (int)Languages.Max; i++)
{
lines[i] = 0;
}
long size = 0;
for (int i = 0; i < files.Length; i++)
{
// Count files size
size += files[i].Length;
// Get file type index
int index = -1;
switch (files[i].Extension)
{
// C++
case ".h":
case ".cpp":
case ".cxx":
case ".hpp":
case ".hxx":
case ".c":
index = (int)Languages.Cpp;
break;
// C#
case ".cs":
index = (int)Languages.CSharp;
break;
// HLSL
case ".hlsl":
case ".shader":
index = (int)Languages.Hlsl;
break;
}
if (index == -1)
continue;
// Count lines in the source file
long ll = 1;
using (StreamReader streamReader = new StreamReader(files[i].FullName))
{
while (streamReader.ReadLine() != null)
{
ll++;
}
}
lines[index] += ll;
}
// Get all directories
DirectoryInfo[] directories = folder.GetDirectories();
if (directories.Length == 0 && files.Length == 0)
{
// Empty folder
return null;
}
// Process child nodes
List children = new List(directories.Length);
for (int i = 0; i < directories.Length; i++)
{
// Validate name
if(ignoredFolders.Contains(directories[i].Name.ToLower()))
continue;
var child = Capture(directories[i]);
if (child != null)
{
children.Add(child);
}
}
// Create node
return new CodeFrameNode(folder.Name, files.Length, lines, size, children.ToArray());
}
public void CleanupDirectories()
{
var child = Children.ToList();
child.RemoveAll(e => ignoredFolders.Contains(e.ShortName.ToLower()));
Children = child.ToArray();
foreach (var a in Children)
{
a.CleanupDirectories();
}
}
///
/// Clean all data
///
public void Dispose()
{
if (Children != null)
{
// Clear
for (int i = 0; i < Children.Length; i++)
{
Children[i].Dispose();
}
Children = null;
}
}
///
/// To string
///
/// String
public override string ToString()
{
return ShortName;
}
}
}