public void Run()
        {
            var client = new MyApiFilmsClient(_token);

            var movieCollectorThread =
                new Thread(
                    () => MovieCollector(_movieService, _personService, client, _queue)
                    )
            {
                Name = "MovieCollectorThread"
            };
            var personCollectorThread =
                new Thread(
                    () => PersonCollector(_personService, _movieService, client, _queue)
                    )
            {
                Name = "PersonCollectorThread"
            };
            var relationshipMakerThread =
                new Thread(
                    () => RelationshipMaker(_movieService, _personService, _queue)
                    )
            {
                Name = "RelationshipMakerThread"
            };

            movieCollectorThread.Start();
            personCollectorThread.Start();
            relationshipMakerThread.Start();

            movieCollectorThread.Join();
            personCollectorThread.Join();
            relationshipMakerThread.Join();
        }
        public void Run()
        {
            var client = new MyApiFilmsClient(_token);

            var movieCollectorThread =
                new Thread(
                    () => MovieCollector(_movieService, _personService, client, _queue)
                    ) {Name = "MovieCollectorThread"};
            var personCollectorThread =
                new Thread(
                    () => PersonCollector(_personService, _movieService, client, _queue)
                    ) {Name = "PersonCollectorThread"};
            var relationshipMakerThread =
                new Thread(
                    () => RelationshipMaker(_movieService, _personService, _queue)
                    ) { Name = "RelationshipMakerThread" };

            movieCollectorThread.Start();
            personCollectorThread.Start();
            relationshipMakerThread.Start();

            movieCollectorThread.Join();
            personCollectorThread.Join();
            relationshipMakerThread.Join();
        }
        private static void PersonCollector(IPersonService personService, IMovieService movieService,
                                            MyApiFilmsClient client, ConcurrentQueue queue)
        {
            while (queue.IncompleteMoviesWaiting() || queue.IncompletePersonsWaiting())
            {
                if (!queue.IncompletePersonsWaiting())
                {
                    continue;
                }
                // ApiPerson is an alias for FilmIndustryNetwork.MyApiFilms.Entities.Person
                // This is to distinguish between FilmIndustryNetwork.MyApiFilms.Entities.Person
                // and FilmIndustryNetwork.Entities.Person
                ApiPerson apiPerson;
                var       name = queue.PopIncompletePerson();

                if (name == "---")
                {
                    continue;
                }

                try
                {
                    apiPerson =
                        client.GetDataAsObject <PersonResponse>(name, DataSetType.Person)?.Data?.Names?.FirstOrDefault();

                    if (apiPerson == null)
                    {
                        throw new Exception();
                    }
                }
                catch (MyApiFilmsTimeoutException e)
                {
                    // TODO: setup logging
                    FillQueueFromList(null, personService, new [] { name }, queue, 1);
                    continue;
                }
                catch (NoMyApiFilmsResponseException e)
                {
                    // TODO: setup logging
                    continue;
                }
                catch (Exception)
                {
                    // TODO: setup logging
                    FillQueueFromList(null, personService, new[] { name }, queue, 1);
                    continue;
                }

                var person = new Person
                {
                    Bio            = apiPerson.Bio,
                    BirthName      = apiPerson.BirthName,
                    DateOfBirth    = apiPerson.DateOfBirth,
                    Id             = apiPerson.IdIMDB,
                    Name           = apiPerson.Name,
                    NeedsApiLookup = false,
                    PlaceOfBirth   = apiPerson.PlaceOfBirth,
                    UrlPhoto       = apiPerson.UrlPhoto
                };

                FillQueueFromList(movieService, null, apiPerson.Filmographies
                                  .Where(x => x.Section == "Actor" || x.Section == "Director" || x.Section == "Writer")
                                  .SelectMany(f => f.Filmography.Select(m => m.Title)).ToList(), queue, 0);

                AddRelationshipsToQueue(
                    apiPerson.Filmographies
                    .Where(x => x.Section == "Actor")
                    .SelectMany(f => f.Filmography
                                .Where(mm => mm.Remarks != null && !mm.Remarks.Contains("(TV Series)"))
                                .Select(m => m.IMDBId)), new[] { person.Name }, queue,
                    RelationTypes.ActedIn);
                AddRelationshipsToQueue(
                    apiPerson.Filmographies
                    .Where(x => x.Section == "Director")
                    .SelectMany(f => f.Filmography
                                .Where(mm => mm.Remarks != null && !mm.Remarks.Contains("(TV Series)"))
                                .Select(m => m.IMDBId)), new[] { person.Name }, queue,
                    RelationTypes.DirectorFor);
                AddRelationshipsToQueue(
                    apiPerson.Filmographies
                    .Where(x => x.Section == "Writer")
                    .SelectMany(f => f.Filmography
                                .Where(mm => mm.Remarks != null && !mm.Remarks.Contains("(TV Series)"))
                                .Select(m => m.IMDBId)), new[] { person.Name }, queue,
                    RelationTypes.WriterOf);

                if (personService.GetPersonByNameAsync(person.Name).Result != null)
                {
                    continue;
                }

                personService.AddPersonAsync(person).Wait();
            }
        }
        private static void MovieCollector(IMovieService movieService, IPersonService personService,
                                           MyApiFilmsClient client, ConcurrentQueue queue)
        {
            while (queue.IncompleteMoviesWaiting() || queue.IncompletePersonsWaiting())
            {
                if (!queue.IncompleteMoviesWaiting())
                {
                    continue;
                }
                // ApiMovie is an alias for FilmIndustryNetwork.MyApiFilms.Entities.Movie
                // This is to distinguish between FilmIndustryNetwork.MyApiFilms.Entities.Movie
                // and FilmIndustryNetwork.Entities.Movie
                ApiMovie apiMovie;
                var      title = queue.PopIncompleteMovie();

                if (title == "---")
                {
                    continue;
                }

                try
                {
                    apiMovie =
                        client.GetDataAsObject <MovieResponse>(title, DataSetType.Movie)?.Data?.Movies?.FirstOrDefault();

                    if (apiMovie == null)
                    {
                        throw new Exception();
                    }

                    if (apiMovie.Type.Contains("TV"))
                    {
                        continue;
                    }
                }
                catch (MyApiFilmsTimeoutException e)
                {
                    // TODO: setup logging
                    FillQueueFromList(movieService, null, new [] { title }, queue, 0);
                    continue;
                }
                catch (NoMyApiFilmsResponseException e)
                {
                    // TODO: setup logging
                    continue;
                }
                catch (Exception)
                {
                    // TODO: setup logging
                    FillQueueFromList(movieService, null, new[] { title }, queue, 0);
                    continue;
                }

                var newMovie = new Movie
                {
                    Countries        = apiMovie.Countries,
                    FilmingLocations = apiMovie.FilmingLocations,
                    Genres           = apiMovie.Genres,
                    Id             = apiMovie.IdIMDB,
                    Languages      = apiMovie.Languages,
                    Plot           = apiMovie.Plot,
                    NeedsApiLookup = false,
                    Rated          = apiMovie.Rated,
                    Rating         = apiMovie.Rating,
                    Title          = apiMovie.Title,
                    Year           = apiMovie.Year
                };

                FillQueueFromList(null, personService, apiMovie.Actors.Select(x => x.ActorName).ToList(), queue, 1);
                FillQueueFromList(null, personService, apiMovie.Directors.Select(x => x.Name).ToList(), queue, 1);
                FillQueueFromList(null, personService, apiMovie.Writers.Select(x => x.Name).ToList(), queue, 1);

                AddRelationshipsToQueue(new[] { apiMovie.IdIMDB }, apiMovie.Actors.Select(x => x.ActorName).ToList(), queue,
                                        RelationTypes.ActedIn);
                AddRelationshipsToQueue(new[] { apiMovie.IdIMDB }, apiMovie.Directors.Select(x => x.Name).ToList(), queue,
                                        RelationTypes.DirectorFor);
                AddRelationshipsToQueue(new[] { apiMovie.IdIMDB }, apiMovie.Writers.Select(x => x.Name).ToList(), queue,
                                        RelationTypes.WriterOf);

                var existingMovie = movieService.GetMovieByIdAsync(newMovie.Id).Result;

                if (existingMovie != null)
                {
                    continue;
                }

                movieService.AddMovieAsync(newMovie).Wait();
            }
        }
        private static void PersonCollector(IPersonService personService, IMovieService movieService, 
            MyApiFilmsClient client, ConcurrentQueue queue)
        {
            while (queue.IncompleteMoviesWaiting() || queue.IncompletePersonsWaiting())
            {
                if (!queue.IncompletePersonsWaiting()) continue;
                // ApiPerson is an alias for FilmIndustryNetwork.MyApiFilms.Entities.Person
                // This is to distinguish between FilmIndustryNetwork.MyApiFilms.Entities.Person
                // and FilmIndustryNetwork.Entities.Person
                ApiPerson apiPerson;
                var name = queue.PopIncompletePerson();

                if (name == "---") continue;

                try
                {
                    apiPerson =
                        client.GetDataAsObject<PersonResponse>(name, DataSetType.Person)?.Data?.Names?.FirstOrDefault();

                    if (apiPerson == null) throw new Exception();
                }
                catch (MyApiFilmsTimeoutException e)
                {
                    // TODO: setup logging
                    FillQueueFromList(null, personService, new [] {name}, queue, 1);
                    continue;
                }
                catch (NoMyApiFilmsResponseException e)
                {
                    // TODO: setup logging
                    continue;
                }
                catch (Exception)
                {
                    // TODO: setup logging
                    FillQueueFromList(null, personService, new[] { name }, queue, 1);
                    continue;
                }

                var person = new Person
                {
                    Bio = apiPerson.Bio,
                    BirthName = apiPerson.BirthName,
                    DateOfBirth = apiPerson.DateOfBirth,
                    Id = apiPerson.IdIMDB,
                    Name = apiPerson.Name,
                    NeedsApiLookup = false,
                    PlaceOfBirth = apiPerson.PlaceOfBirth,
                    UrlPhoto = apiPerson.UrlPhoto
                };

                FillQueueFromList(movieService, null, apiPerson.Filmographies
                    .Where(x => x.Section == "Actor" || x.Section == "Director" || x.Section == "Writer")
                    .SelectMany(f => f.Filmography.Select(m => m.Title)).ToList(), queue, 0);

                AddRelationshipsToQueue(
                    apiPerson.Filmographies
                        .Where(x => x.Section == "Actor")
                        .SelectMany(f => f.Filmography
                                          .Where(mm => mm.Remarks != null && !mm.Remarks.Contains("(TV Series)"))
                                          .Select(m => m.IMDBId)), new[] {person.Name}, queue,
                    RelationTypes.ActedIn);
                AddRelationshipsToQueue(
                    apiPerson.Filmographies
                        .Where(x => x.Section == "Director")
                        .SelectMany(f => f.Filmography
                                          .Where(mm => mm.Remarks != null && !mm.Remarks.Contains("(TV Series)"))
                                          .Select(m => m.IMDBId)), new[] { person.Name }, queue,
                    RelationTypes.DirectorFor);
                AddRelationshipsToQueue(
                    apiPerson.Filmographies
                        .Where(x => x.Section == "Writer")
                        .SelectMany(f => f.Filmography
                                          .Where(mm => mm.Remarks != null && !mm.Remarks.Contains("(TV Series)"))
                                          .Select(m => m.IMDBId)), new[] { person.Name }, queue,
                    RelationTypes.WriterOf);

                if (personService.GetPersonByNameAsync(person.Name).Result != null) continue;

                personService.AddPersonAsync(person).Wait();
            }
        }
        private static void MovieCollector(IMovieService movieService, IPersonService personService, 
            MyApiFilmsClient client, ConcurrentQueue queue)
        {
            while (queue.IncompleteMoviesWaiting() || queue.IncompletePersonsWaiting())
            {
                if (!queue.IncompleteMoviesWaiting()) continue;
                // ApiMovie is an alias for FilmIndustryNetwork.MyApiFilms.Entities.Movie
                // This is to distinguish between FilmIndustryNetwork.MyApiFilms.Entities.Movie
                // and FilmIndustryNetwork.Entities.Movie
                ApiMovie apiMovie;
                var title = queue.PopIncompleteMovie();

                if (title == "---") continue;

                try
                {
                    apiMovie =
                        client.GetDataAsObject<MovieResponse>(title, DataSetType.Movie)?.Data?.Movies?.FirstOrDefault();

                    if (apiMovie == null) throw new Exception();

                    if (apiMovie.Type.Contains("TV")) continue;
                }
                catch (MyApiFilmsTimeoutException e)
                {
                    // TODO: setup logging
                    FillQueueFromList(movieService, null, new [] {title}, queue, 0);
                    continue;
                }
                catch (NoMyApiFilmsResponseException e)
                {
                    // TODO: setup logging
                    continue;
                }
                catch (Exception)
                {
                    // TODO: setup logging
                    FillQueueFromList(movieService, null, new[] { title }, queue, 0);
                    continue;
                }

                var newMovie = new Movie
                {
                    Countries = apiMovie.Countries,
                    FilmingLocations = apiMovie.FilmingLocations,
                    Genres = apiMovie.Genres,
                    Id = apiMovie.IdIMDB,
                    Languages = apiMovie.Languages,
                    Plot = apiMovie.Plot,
                    NeedsApiLookup = false,
                    Rated = apiMovie.Rated,
                    Rating = apiMovie.Rating,
                    Title = apiMovie.Title,
                    Year = apiMovie.Year
                };

                FillQueueFromList(null, personService, apiMovie.Actors.Select(x => x.ActorName).ToList(), queue, 1);
                FillQueueFromList(null, personService, apiMovie.Directors.Select(x => x.Name).ToList(), queue, 1);
                FillQueueFromList(null, personService, apiMovie.Writers.Select(x => x.Name).ToList(), queue, 1);

                AddRelationshipsToQueue(new[] {apiMovie.IdIMDB}, apiMovie.Actors.Select(x => x.ActorName).ToList(), queue,
                    RelationTypes.ActedIn);
                AddRelationshipsToQueue(new[] {apiMovie.IdIMDB}, apiMovie.Directors.Select(x => x.Name).ToList(), queue,
                    RelationTypes.DirectorFor);
                AddRelationshipsToQueue(new[] {apiMovie.IdIMDB}, apiMovie.Writers.Select(x => x.Name).ToList(), queue,
                    RelationTypes.WriterOf);

                var existingMovie = movieService.GetMovieByIdAsync(newMovie.Id).Result;

                if (existingMovie != null) continue;

                movieService.AddMovieAsync(newMovie).Wait();
            }
        }