private void UpdateCoverArt()
        {
            _coverUpdateTimer.Stop();
            try
            {
                // get a hook to the DB
                IDBClient db = Database.RetrieveClient();

                //// get the audio library locations
                //IList<Album> albums = _theModule._theDatabase.RetrieveAlbumsWithoutCoverArt(db);

                // get the current timestamp, we'll use this in case anything gets modified while this is happening
                DateTime beforeUpdate = DateTime.Now;

                //_log.Info("Started cover art update at: " + DateTime.Now.ToLocalTime());

                //// recurse through each of the library locations
                //foreach (Album album in albums)
                //{
                //    if (!_theModule._theCore._keepRunning)
                //    {
                //        return;
                //    }

                //    bool artistPresent = (null != album._artist.Name);
                //    bool titlePresent = (null != album._title);
                //    // if this has the imported cover art
                //    if (artistPresent && titlePresent && album._coverArt == AudioModuleConstants.IMPORTED_COVERART)
                //    {
                //        // try to retrieve the cover art from Amazon
                //        var amazon = new AmazonRestService();
                //        string coverArt = amazon.RetrieveImage(album, AudioModuleConstants.IMAGE_FOLDER);

                //        // if successful, store it on the album
                //        if (null != coverArt)
                //        {
                //            // add the cover art with the required prefix
                //            string coverArtPath = AudioModuleConstants.IMAGES_PREFIX + "/" + coverArt;
                //            album._coverArt = coverArtPath;
                //            _theModule._theDatabase.UpdateAddAlbum(db, album);
                //            db.Commit();
                //        }
                //    }
                //}

                TimeSpan elapsedTime = DateTime.Now - beforeUpdate;
                _log.Info("Finished cover art update at: " + DateTime.Now.ToLocalTime() + ".  Took: " +
                          elapsedTime.TotalSeconds + " seconds");

                db.Close();
            }
            catch (Db4oException)
            {
                // TODO
            }
            finally
            {
                _coverUpdateTimer.Start();
            }
        }
        /// <summary>
        /// Read the configuration file, establish what library locations need to be read
        /// </summary>
        private void InitialiseLibraryLocations()
        {
            // get a hook to the DB to use
            IDBClient db = Database.RetrieveClient();

            IList <LibraryLocation> confirmedLocations = new List <LibraryLocation>();

            //// get the list from the config file first
            //foreach (XmlNode locationNode in GetLibraryLocations())
            //{
            //    string name = locationNode.Attributes["Name"].Value;
            //    string path = locationNode.Attributes["Path"].Value;
            //    LibraryLocation location = Database.RetrieveLibraryLocation(db, name, path);

            //    // if this is a new location, add it to the DB
            //    if (null == location)
            //    {
            //        location = new VideoLibraryLocation(name, path);
            //    }

            //    // add it to the ones that should be there
            //    confirmedLocations.Add(location);
            //}

            // now we'll prune the ones which shouldn't be here
            IList <VideoLibraryLocation> locations = Database.RetrieveLibraryLocations(db);

            if (locations.Count != 0)
            {
                foreach (VideoLibraryLocation location in locations)
                {
                    if (!confirmedLocations.Contains(location))
                    {
                        Database.RemoveLibraryLocation(db, location);
                    }
                }
            }

            // wasteful, but we'll just reconfirm them all
            foreach (VideoLibraryLocation location in confirmedLocations)
            {
                Database.UpdateAddLibraryLocation(db, location);
            }

            db.Close();
            // -------------------------------------------------------------------------------------------
        }
        /// <summary>
        /// Read the configuration file, establish what library locations need to be read
        /// </summary>
        private void InitialiseLibraryLocations()
        {
            // get a hook to the DB to use
            IDBClient db = Database.RetrieveClient();

            IList <LibraryLocation> confirmedLocations = new List <LibraryLocation>();

            // get the list from the config file first
            foreach (XmlNode locationNode in GetLibraryLocations())
            {
                string name = locationNode.Attributes["Name"].Value;
                string path = locationNode.Attributes["Path"].Value;

                // either find the existing location or create a new one
                LibraryLocation location = Database.RetrieveLibraryLocation(db, name, path) ??
                                           new AudioLibraryLocation(name, path);


                // add it to the ones that should be there
                confirmedLocations.Add(location);
            }

            // now we'll prune the ones which shouldn't be here
            IList <AudioLibraryLocation> locations = Database.RetrieveLibraryLocations(db);

            if (locations.Count != 0)
            {
                foreach (AudioLibraryLocation location in locations)
                {
                    if (!confirmedLocations.Contains(location))
                    {
                        Database.RemoveLibraryLocation(db, location);
                    }
                }
            }

            // wasteful, but we'll just reconfirm them all
            foreach (AudioLibraryLocation location in confirmedLocations)
            {
                Database.UpdateAddLibraryLocation(db, location);
            }

            db.Close();
        }
        /// <summary>
        /// Update the library when invoked via the timer
        /// </summary>
        private void UpdateLibrary()
        {
            try
            {
                // get a hook to the DB
                IDBClient db = Database.RetrieveClient();

                // retrieve the initial number of tracks
                int beforeTracks = Database.RetrieveNumberOfTracks(db);

                // get the audio library locations
                IList <AudioLibraryLocation> locations = Database.RetrieveLibraryLocations(db);

                // get the current timestamp, we'll use this in case anything gets modified while this is happening
                DateTime beforeUpdate = DateTime.Now;

                _log.Info("Starting library update at: " + beforeUpdate.ToLocalTime());

                try
                {
                    // recurse through each of the library locations
                    foreach (AudioLibraryLocation location in locations)
                    {
                        if (_log.IsDebugEnabled)
                        {
                            _log.Debug("Updating library location: " + location.Path);
                        }

                        // initialise the list of directories to process
                        IList <string> directoriesToProcess = new List <string>();

                        // start traversing down each directory
                        ProcessDirectory(directoriesToProcess, location.Path, location.LastWritten);

                        // if there was any processing needed to be done
                        if (directoriesToProcess.Count > 0)
                        {
                            const int numThreads = 5;
                            _libraryThreadPool = new FixedThreadPool(5, ThreadPriority.Lowest);
                            _log.Debug("Created custom thread pool for library with " + numThreads + " threads");

                            // make all the workers
                            for (int i = 0; i < directoriesToProcess.Count; i++)
                            {
                                var worker = new AudioLibraryWorker();
                                worker.Directory = directoriesToProcess[i];

                                // attach it to a worker for the pool
                                var workerItem = new WorkerItem(worker.WorkerMethod);

                                // add it to the pool
                                _libraryThreadPool.QueueWorkerItem(workerItem);

                                // start the show
                                _libraryThreadPool.Start();
                            }
                        }

                        // reset the reference to when this update run started
                        location.LastWritten = beforeUpdate;

                        // store this updated location back in the DB
                        Database.UpdateAddLibraryLocation(db, location);

                        // commit after each location.  if something goes wrong, we wont have to redo
                        db.Commit();
                    }

                    // get the number of tracks after
                    int afterTracks = Database.RetrieveNumberOfTracks(db);

                    TimeSpan elapsedTime = DateTime.Now - beforeUpdate;
                    _log.Info("Finished library update at: " + DateTime.Now.ToLocalTime() + ".  Took: " +
                              elapsedTime.TotalSeconds + " seconds");
                    _log.Info("Imported " + (afterTracks - beforeTracks) + " tracks");

                    // close the db
                    db.Close();
                }
                catch (DatabaseClosedException)
                {
                    _log.Debug("The database has been closed prematurely");
                }
            }
            catch (Db4oException ex)
            {
                _log.Error("Problem occurred when updating library", ex);
            }
            finally
            {
                _libraryUpdateTimer.Start();
            }
        }
        /// <summary>
        /// Worker method that be threaded for parallel processing of each of the directories
        /// </summary>
        public void WorkerMethod()
        {
            // take a note of the current time
            var stopWatch = new Stopwatch();

            stopWatch.Start();

            // keep track of the number of files for reporting
            var numberOfFiles = 0;

            try
            {
                // get a hook to the DB
                IDBClient db = null;

                // retrieve all the files in the supported extensions
                var files = System.IO.Directory.GetFiles(Directory, string.Empty, SearchOption.TopDirectoryOnly).Where(x => AudioConstants.SUPPORTED_LOSSLESS.Concat(AudioConstants.SUPPORTED_LOSSY).Contains(Path.GetExtension(x)));

                // open the database if there are files to process
                if (numberOfFiles > 0 && db == null)
                {
                    // get a DB connection
                    db = Database.RetrieveClient();

                    // increment our total
                    numberOfFiles += files.Count();

                    // add these to the list
                    foreach (string file in files)
                    {
                        // process them accordingly
                        ProcessTrack(db, file);
                    }
                }

                // attach the correct artist to the album
                if (_tally.Count > 0)
                {
                    // find the artist that appears the most
                    var highestPair = new KeyValuePair <Artist, int>(null, 0);
                    foreach (var pair in _tally)
                    {
                        if (pair.Value > highestPair.Value)
                        {
                            highestPair = pair;
                        }
                    }

                    // if they aren't on at least half the tracks, it's a various artist album
                    if (highestPair.Value >= (_theAlbum.Tracks.Count / 2))
                    {
                        // only change this in the DB if it's changed
                        if (_theAlbum.Artist.Name != highestPair.Key.Name)
                        {
                            _theAlbum.Artist = highestPair.Key;

                            // update the DB reference
                            Database.UpdateAddAlbum(db, _theAlbum);
                        }
                    }
                    else
                    {
                        _theAlbum.Artist = Artist.VARIOUS_ARTISTS;

                        // update the DB reference
                        Database.UpdateAddAlbum(db, _theAlbum);
                    }
                }

                // commit after each directory
                db.Close();
            }
            catch (IOException e)
            {
                _log.Error("File IO problem when processing directory: " + Directory, e);
            }

            if (_log.IsDebugEnabled)
            {
                _log.Debug("Processing directory '" + Directory + "' took " + stopWatch.Elapsed.TotalSeconds +
                           " seconds.");
                _log.Debug("There were " + numberOfFiles + " files, at " + (stopWatch.Elapsed.TotalSeconds / numberOfFiles) +
                           " seconds per file");
            }
        }
        /// <summary>
        /// Update the library when invoked via the timer
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void UpdateLibrary()
        {
            _libraryUpdateTimer.Stop();
            try
            {
                // lower the priority of this thread
                Thread.CurrentThread.Priority = ThreadPriority.Lowest;

                // get a hook to the DB
                IDBClient db = Database.RetrieveClient();


                // get the audio library locations
                IList <VideoLibraryLocation> locations = Database.RetrieveLibraryLocations(db);

                // get the current timestamp, we'll use this in case anything gets modified while this is happening
                DateTime beforeUpdate = DateTime.Now;

                _log.Info("Starting library update at: " + beforeUpdate.ToLocalTime());

                try
                {
                    // recurse through each of the library locations
                    foreach (VideoLibraryLocation location in locations)
                    {
                        if (_log.IsDebugEnabled)
                        {
                            _log.Debug("Updating library location: " + location.Path);
                        }

                        //    // initialise the list of directories to process
                        //    IList<string> directoriesToProcess = new List<string>();

                        //    // start traversing down each directory
                        //    ProcessDirectory(directoriesToProcess, location.Path, location.LastWritten);

                        //    // if there was any processing needed to be done
                        //    if (directoriesToProcess.Count > 0)
                        //    {
                        //        _libraryThreadPool = new FixedThreadPool(5, ThreadPriority.Lowest);
                        //        _log.Debug("Created custom thread pool for library with 5 threads");

                        //        // make all the workers
                        //        for (int i = 0; i < directoriesToProcess.Count; i++)
                        //        {
                        //            if (!_theModule._theCore._keepRunning)
                        //            {
                        //                _libraryThreadPool._keepRunning = false;
                        //                return;
                        //            }

                        //            // create the worker thread
                        //            var worker = new LibraryWorker(_theModule, directoriesToProcess[i]);

                        //            // attach it to a worker for the pool
                        //            var workerItem =
                        //                new WorkerItem(new LibraryWorker.DirectoryWorker(worker.WorkerMethod));

                        //            // add it to the pool
                        //            _libraryThreadPool.QueueWorkerItem(workerItem);

                        //            // start the show
                        //            _libraryThreadPool.Start();
                        //        }
                        //    }

                        // reset the reference to when this update run started
                        location.LastWritten = beforeUpdate;

                        // store this updated location back in the DB
                        Database.UpdateAddLibraryLocation(db, location);

                        // commit after each location.  if something goes wrong, we wont have to redo
                        db.Commit();
                    }

                    TimeSpan elapsedTime = DateTime.Now - beforeUpdate;
                    _log.Info("Finished library update at: " + DateTime.Now.ToLocalTime() + ".  Took: " +
                              elapsedTime.TotalSeconds + " seconds");

                    // close the db
                    db.Close();
                }
                catch (DatabaseClosedException)
                {
                    _log.Debug("The database has been closed prematurely");
                    _libraryThreadPool._keepRunning = false;
                }
            }
            catch (Db4oException ex)
            {
                _log.Error("Problem occurred when updating library", ex);
            }
            finally
            {
                _libraryUpdateTimer.Start();
            }
        }
        public Album GetTracks(CDDBEntry cddbResult)
        {
            // initialise the album to output
            Album newAlbum = null;

            // build up the command string
            var commandBuilder = new StringBuilder();

            commandBuilder.Append("?");
            commandBuilder.Append(FreeDBConstants.COMMAND);
            commandBuilder.Append(FreeDBConstants.COMMAND_READ);
            commandBuilder.Append("+");
            commandBuilder.Append(cddbResult.Genre);
            commandBuilder.Append("+");
            commandBuilder.Append(cddbResult.DiscID);
            commandBuilder.Append("&");
            commandBuilder.Append(GenerateHello());
            commandBuilder.Append("&");
            commandBuilder.Append(GenerateProtocol());

            // make the URL to use
            var urlBuilder = new StringBuilder();

            urlBuilder.Append(FreeDBConstants.URL_FREEDB_MAIN);
            urlBuilder.Append(FreeDBConstants.URL_HTTP_ACCESS);

            // hit up FreeDB for the result
            IList <string> freeDBResponse = Query(urlBuilder.ToString(), commandBuilder.ToString());

            // parse the query
            if (freeDBResponse.Count > 0)
            {
                // extract the response code
                ResponseCode responseCode = ExtractResponseCode(freeDBResponse[0]);

                switch (responseCode)
                {
                case ResponseCode.RESPONSE_CODE_DEFAULT:
                    _log.Error("Problem querying album using command: " + commandBuilder);
                    break;

                case ResponseCode.RESPONSE_CODE_200:
                case ResponseCode.RESPONSE_CODE_210:
                    _log.Debug("Found track/s");

                    // get a hook to the DB
                    IDBClient db = Database.RetrieveClient();

                    // we'll look for an artist to attach this all to
                    Artist theArtist = Database.RetrieveArtistByName(db, cddbResult.ArtistName);

                    // TODO Check for artists, as opposed to just one

                    // if we don't we'll create one
                    if (null == theArtist)
                    {
                        theArtist = new Artist(cddbResult.ArtistName);
                    }

                    db.Close();

                    // we'll create an album for this with invalid data, we'll fill that out after
                    newAlbum = new Album(cddbResult.Title, theArtist, null, 1900, Compression.Undecided);

                    // a list to keep track of the track lengths in seconds
                    IList <int> trackLengths = new List <int>();

                    // keep track of the track offsets for track lengths
                    int lastTrackOffset = 0;

                    // break up each of the results
                    foreach (string responseLine in freeDBResponse)
                    {
                        // extract the track lengths
                        if (responseLine.Contains("#\t"))
                        {
                            // parse the next offset
                            int newOffset = Int32.Parse(responseLine.Substring(2));

                            // stop the first one being processed
                            if (lastTrackOffset > 0)
                            {
                                int seconds = (newOffset - lastTrackOffset) / 75;
                                trackLengths.Add(seconds);
                            }

                            // store the new offset
                            lastTrackOffset = newOffset;
                        }

                        // extract the total number of seconds so we can calculate the last tracks length
                        if (responseLine.Contains("# Disc length"))
                        {
                            // parse the total length of the album in seconds
                            int totalLength = Int32.Parse(responseLine.Substring(15, 4));

                            int secondsToDate = lastTrackOffset / 75;

                            // extract the length of the last track from this to find out the length of the final track
                            int lastTrackLength = totalLength - secondsToDate;

                            // add this to the lengths
                            trackLengths.Add(lastTrackLength);
                        }

                        // extract the year
                        if (responseLine.Contains("DYEAR"))
                        {
                            string year = responseLine.Substring(6);
                            newAlbum.ReleaseYear = Int32.Parse(year);
                        }

                        // extract a track
                        if (responseLine.Contains("TTITLE"))
                        {
                            // marker for where to parse string to
                            int    indexOfSpace = responseLine.IndexOf('=', 6);
                            string numberString = responseLine.Substring(6, (indexOfSpace - 6));

                            int trackNumber = Int32.Parse(numberString) + 1;

                            string trackTitle = responseLine.Substring(indexOfSpace + 1);
                            // create this with no path as it's not currently set
                            var artists = new List <Artist>();
                            artists.Add(theArtist);
                            var newTrack = new Track(trackNumber, artists, newAlbum,
                                                     new Duration(new TimeSpan(0, 0, trackLengths[trackNumber - 1])),
                                                     trackTitle, null);
                            newAlbum.AddTrack(newTrack);
                        }
                    }
                    break;

                default:
                    _log.Error("Response came back we weren't expecting, handle it");
                    break;
                }
            }

            // pass back the resulting album
            return(newAlbum);
        }