# Any suggestions on how to clean up this convoluted file look-up method?

I'm working on set of methods that locate DVR surveillance footage, based on timestaps.

The files are in the following format:

<drive>\<year>\<month>\<day>\<camera>\<hour>-<minute>-<second>.<extension>

Example: Z:\2011\07\02\000001\00-13-15.mkv through Z:\2011\07\02\000001\23-45-13.mkv

The videos are in 15ish minute increments, that start roughly around the turn of the hour. The edge case, as you could imagine, is around that turn of the hour mark. I have come up with two methods that get the job done, but are extremely convoluted, and frankly ugly.

Can any one think of a less complex way to do this?

EDIT: After some thought, I refactored it into three methods. Splitting out the path building as I had with the file name. It's better, but I still feel it can be simpler. This also resolves the 'change of day' issue I had mentioned below.

    public static string GetSecurityFootage(DateTime timeStamp, Camera camera)
{
string storageLoc = Initialization.DvrStorageLocation;

// Just bail if we don't have a valid storage location.
if (!Directory.Exists(storageLoc))
{
return "";
}

// Get path and file name based on timestamp.
string path = GetVideoPath(timeStamp, camera, storageLoc);
string fileName = GetVideo(timeStamp, path.ToString());

if (fileName != "" && File.Exists(path + fileName))
{
path = path + fileName;
}

// Try the end of the last hour/day.
else
{
// Subtract from time minutes +1 to set time to last hour.
timeStamp = timeStamp.AddMinutes(-(timeStamp.Minute + 1));

path = GetVideoPath(timeStamp, camera, storageLoc);
fileName = GetVideo(timeStamp, path.ToString());

if (fileName != "" && File.Exists(path + fileName))
{
path = path + fileName;
}
else
{
// If it's not it the last hour, we do not have footage.
return "";
}
}

return path;
}

private static string GetVideoPath(DateTime timeStamp, Camera camera, string storageLoc)
{
string pathSep = Path.DirectorySeparatorChar.ToString();
string cameraPath = "";

string year = timeStamp.Year.ToString();
string month = timeStamp.Month.ToString();
string day = timeStamp.Day.ToString();

StringBuilder path = new StringBuilder();

// Paths are preceded by 0.
if (day.Length == 1)
{
day = "0" + day;
}

if (month.Length == 1)
{
month = "0" + month;
}

switch (camera)
{
case Camera.Patio:
cameraPath = "000001";
break;

case Camera.Counter:
cameraPath = "000002";
break;

case Camera.Shed:
cameraPath = "000003";
break;

case Camera.Cafe:
cameraPath = "000004";
break;

case Camera.Lobby:
cameraPath = "000005";
break;

default:
cameraPath = "000002";  //default to counter.
break;
}

// Path to video.
path.Append(storageLoc);

if (!storageLoc.Trim().EndsWith(pathSep))
{
path.Append(pathSep);
}

path.Append(year);
path.Append(pathSep);
path.Append(month);
path.Append(pathSep);
path.Append(day);
path.Append(pathSep);
path.Append(cameraPath);
path.Append(pathSep);

// The path doesn't exist, we will not have footage.
if (!Directory.Exists(path.ToString()))
{
return "";
}

return path.ToString();
}

private static string GetVideo(DateTime timeStamp, string path)
{
string hour = timeStamp.Hour.ToString();
int minute = timeStamp.Minute; //leave as int for comparison.

string fileName = "";

if (hour.Length == 1)
{
hour = "0" + hour;
}

// Get all the files in the dir, but just the file names.
var files = Directory.GetFiles(path.ToString()).Select(f => Path.GetFileName(f));

// All files that start with the correct hour.
var q = from f in files
where f.Trim().StartsWith(hour)
orderby f
select f;

// Now, loop the files for the higest that is still less than the minute we're looking for.
foreach (var file in q)
{
int min = 0;
int.TryParse(file.Substring(3, 2), out min);

// Set file name for each loop; when done the highest should always be the last one set.
if (min <= minute)
{
fileName = file;
}
}

return fileName;
}


I guess there is no strike-through... disregard the following:

One thing that is noticeable is that for the change of day, it will fail to find the footage. This isn't a huge deal, this is only a convenience feature for our POS. In this case, the user will just have to browse to the video manually. The change of hour is important, otherwise this feature is useless 1/4 of the time.

Looking at how you try to solve this problem, you try to guess the expected file name of this point in time. Allow me to suggest another approach which is more natural and simpler IMHO.

If all these videos are sorted, a footage is in a video if it's timestamp is within the time of this video, e.g. if you have a video Z:\2011\07\02\000001\13-45-13.mkv and the next video is Z:\2011\07\02\000001\14-00-32.mkv, and you are looking for the footage at 2011-07-02 13:52:07, you know that the footage it's in the first one.

To do this, you need to

1. Sort the videos by their starting date (which you will get by parsing the name).
2. Search for the video containing this footage timestamp.

This also handles all your edge cases :).

1. Don't do path.ToString() when path is already a string.
2. String.format is more readable than StringBuilder in your case.