/// <summary>
        /// Creates an instance of a new scan controller
        /// </summary>
        /// <param name="targetFiles">The files you want to scan</param>
        /// <param name="signatures">The signature controller to scan with</param>
        /// <param name="cache">The cache controller to log results with</param>
        public ScanController(Queue <string> targetFiles, SignatureController signatures)
        {
            // Pass the parameters
            this.TargetFiles = targetFiles;
            this.Signatures  = signatures;

            // Initiaize private properties
            this.ScannerThreads = new List <Thread>();

            // Set some defaults
            this.MaxThreads = Environment.ProcessorCount;
            this.Pause      = false;
            this.Cancel     = false;

            //if (PatternAnalyzer.matcher == null)
            //{
            //    PatternAnalyzer.matcher = new AhoCorasick.Trie<byte, Signature>();

            //    foreach (Signature s in signatures.Signatures)
            //    {
            //        PatternAnalyzer.matcher.Add(s.Pattern.ToList(), s);
            //    }

            //    PatternAnalyzer.matcher.Build();
            //}
        }
        public void Run()
        {
            // Create master thread to manage running threads
            Thread t = new Thread(() =>
            {
                // Create local copies of databases to work with
                SignatureController localSignatures = this.Signatures;
                TargetProcess = Process.ProcessQueue();

                bool loadProcess = false;
                //MaxThreads = 1;
                //MaxThreads /=2;

                // While we are not canceling the whole scan...
                while (!Cancel)
                {
                    while (Pause)
                    {
                        Thread.Sleep(500);

                        // exit
                        if (Cancel == true)
                        {
                            // exit
                            return;
                        }
                    }

                    //detmine number of threads to use when scanning
                    if (Settings.ReducePriority)
                    {
                        this.MaxThreads = Environment.ProcessorCount / 2;
                    }
                    else
                    {
                        this.MaxThreads = Environment.ProcessorCount;
                    }

                    // If all scans have finished and there is nothing left to scan...
                    if (RunningThreads == 0 && TargetFiles.Count() == 0 && TargetProcess.Count() == 0)
                    {
                        // All files have been scanned... time to implement a process scanner....


                        // Attempt to raise event for scan complete
                        // Raise the event
                        ThreatScanComplete?.Invoke(this);

                        // And then exit the loop
                        break;
                    }
                    else if (TargetFiles.Count() == 0 && !loadProcess)
                    {
                        loadProcess = true;
                        // Get a queue of new process...
                        TargetProcess = Process.ProcessQueue();
                    }
                    else
                    {
                        // Check for existing dead threads in the thread list

                        //var dead = ScannerThreads.FirstOrDefault(th => th.ThreadState == ThreadState.Stopped);

                        // // while there are dead threads to remove...
                        // while (dead != null && !Cancel)
                        // {
                        //     // Remove dead thread
                        //     ScannerThreads.Remove(dead);

                        //     // Check for more
                        //     dead = ScannerThreads.FirstOrDefault(th => th.ThreadState == ThreadState.Stopped);
                        // }

                        if (ScannerThreads.Count > 0)
                        {
                            for (int i = 0; i < ScannerThreads.Count; i++)
                            {
                                //if(ScannerThreads[i].ThreadState == ThreadState.Stopped)
                                ScannerThreads[i].Join();
                                ScannerThreads.Remove(ScannerThreads[i]);
                            }
                        }

                        // Clean garbage left behind by scans...
                        GC.Collect();

                        // All target files were scanned... start a process scanning...
                        if (TargetFiles.Count == 0)
                        {
                            // Loop through the process queue time..
                            while (RunningThreads < MaxThreads && TargetProcess.Count > 0 && !Cancel)
                            {
                                // Get next process
                                var target = TargetProcess.Dequeue();

                                // Create a scanner for it..
                                Thread scan = new Thread(() =>
                                {
                                    try
                                    {
                                        // Check white list against process before scanning it
                                        if (Settings.WhiteList.Contains(NativeMethods.GetExecutablePath(target)))
                                        {
                                            return;
                                        }

                                        // Heuristically analyze file first
                                        var heur = BerzerkAPI.IO.Heuristic.Analyze(API.NativeMethods.GetExecutablePath(target));
                                        if (heur != null)
                                        {
                                            ThreatDetectedArgs args = new Controllers.ThreatDetectedArgs()
                                            {
                                                Detection = heur, FilePath = API.NativeMethods.GetExecutablePath(target)
                                            };
                                            ThreatDetected?.Invoke(this, args);
                                        }
                                        else
                                        {
                                            // create a scan of the process
                                            Signature res = Process.ScanProcess(target, ref localSignatures);

                                            // Scan the file and get results
                                            //Signature result = BerzerkAPI.IO.File.ScanFile(target, ref localSignatures, ref localCache);
                                            ScanResultArgs result = BerzerkAPI.IO.File.ScanFile(NativeMethods.GetExecutablePath(target), localSignatures);

                                            // accumulate the total scanned data in MB
                                            ScannedData += (result.Size / 1024) / 1024;

                                            // Check results
                                            if (result.Detection != null)
                                            {
                                                // Attempt to raise detection event

                                                // Create event args
                                                ThreatDetectedArgs args = new ThreatDetectedArgs()
                                                {
                                                    Detection = result.Detection, FilePath = NativeMethods.GetExecutablePath(target)
                                                };
                                                // Raise event ?
                                                ThreatDetected?.Invoke(this, args);
                                            }
                                        } // end of heuristic else

                                        // Try to scan the process
                                        //var result = BerzerkAPI.IO.Process.ScanProcess(target, ref localSignatures);

                                        //// If a threat was found in the process
                                        //if(result != null)
                                        //{
                                        //    ThreatDetectedArgs args = new Controllers.ThreatDetectedArgs()
                                        //    {
                                        //        Detection = result,
                                        //        FilePath = NativeMethods.GetExecutablePath(target)
                                        //    };

                                        //    ThreatDetected?.Invoke(this, args);
                                        //}
                                    }
                                    catch (Exception ex)
                                    {
#if DEBUG
                                        Console.WriteLine(ex.Message);
#endif
                                    }
                                    //ScannerThreads.Remove(Thread.CurrentThread);
                                });


                                // Add thread to list
                                ScannerThreads.Add(scan);

                                // Run thread in bg
                                scan.IsBackground = true;
                                scan.SetApartmentState(ApartmentState.MTA);

                                // Run the scan
                                scan.Start();
                                // scan.Join();
                            }
                        }

                        // Now that we have freed space in the thread list, we need to create new threads
                        // Loop while there is room left for more threads
                        // And while there are files left to scan
                        while (RunningThreads < MaxThreads && TargetFiles.Count > 0 && !Cancel)
                        {
                            // Get the next scannable file
                            string target = TargetFiles.Dequeue();


                            // Create new scan thrad for the next file
                            Thread scan = new Thread(() =>
                            {
                                try
                                {
                                    // Scan the file and get results
                                    //Signature result = BerzerkAPI.IO.File.ScanFile(target, ref localSignatures, ref localCache);
                                    ScanResultArgs result = BerzerkAPI.IO.File.ScanFile(target, localSignatures);

                                    // accumulate the total scanned data in MB
                                    ScannedData += (result.Size / 1024) / 1024;

                                    // Check results
                                    if (result.Detection != null)
                                    {
                                        // Attempt to raise detection event

                                        // Create event args
                                        ThreatDetectedArgs args = new ThreatDetectedArgs()
                                        {
                                            Detection = result.Detection, FilePath = target
                                        };
                                        // Raise event ?
                                        ThreatDetected?.Invoke(this, args);
                                    }

                                    // Sleep thread before ending it to provide some timeout for the cpu
                                    //Thread.Sleep(20);
                                }
                                catch (Exception ex) // debugging purposes
                                {
                                    // something went wrong...
#if DEBUG
                                    Console.WriteLine(ex.Message);
#endif
                                }
                                //ScannerThreads.Remove(Thread.CurrentThread);
                            });

                            // Add thread to list
                            ScannerThreads.Add(scan);

                            // Run thread in bg
                            scan.IsBackground = true;
                            scan.SetApartmentState(ApartmentState.MTA);

                            // Run the scan
                            scan.Start();
                            //scan.Join();
                        }
                    }
                }
            });

            // Set the thread to run in the bg and run it
            t.IsBackground = true;
            t.Start();
        }