private static void FillDynamicHash <T>(PersonHashtable personHash
                                                , Object possiblePerson)
            where T : class, IPerson
        {
            T person = possiblePerson as T;

            if (person != null)
            {
                if (personHash.ContainsKey(person) == false)
                {
                    personHash.Add(person);
                }
            }
        }
        public static void Main()
        {
            Console.WriteLine("Welcome to the DVDProfiler Actor Linking Transformation Simulation!");
            Console.WriteLine("Version: " + Assembly.GetExecutingAssembly().GetName().Version.ToString());
            Console.WriteLine();
            Console.WriteLine("Please select a \"collection.xml\" and a target location for the output files!");
            Console.WriteLine("(You should see a file dialog. If not, please minimize your other programs.)");

            try
            {
                #region Phase 1: Ask For File Locations

                String collectionFile;
                using (OpenFileDialog ofd = new OpenFileDialog())
                {
                    ofd.Filter           = "Collection.xml|*.xml";
                    ofd.CheckFileExists  = true;
                    ofd.Multiselect      = false;
                    ofd.Title            = "Select Source File";
                    ofd.RestoreDirectory = true;

                    if (ofd.ShowDialog(s_WindowHandle) == DialogResult.Cancel)
                    {
                        Console.WriteLine();
                        Console.WriteLine("Aborted.");

                        return;
                    }

                    collectionFile = ofd.FileName;
                }

                String targetFolder;
                using (FolderBrowserDialog fbd = new FolderBrowserDialog())
                {
                    fbd.Description = "Select Target Folder";

                    if (fbd.ShowDialog(s_WindowHandle) == DialogResult.Cancel)
                    {
                        Console.WriteLine();
                        Console.WriteLine("Aborted.");

                        return;
                    }

                    targetFolder = fbd.SelectedPath;
                }

                #endregion

                #region Phase 2: Read XML

                Console.WriteLine();
                Console.WriteLine("Tranforming data:");

                XmlSerializer xmlSerializer = new XmlSerializer(typeof(Collection));

                Collection collection;
                using (FileStream fs = new FileStream(collectionFile, FileMode.Open, FileAccess.Read, FileShare.Read))
                {
                    collection = (Collection)(xmlSerializer.Deserialize(fs));
                }

                #endregion

                if (collection.DVDList?.Length > 0)
                {
                    #region Phase 3: Create new Online Actor Database

                    PersonHashtable castAndCrewHash = new PersonHashtable(collection.DVDList.Length * 50);

                    foreach (DVD dvd in collection.DVDList)
                    {
                        if (dvd.CastList != null && dvd.CastList.Length > 0)
                        {
                            foreach (Object possibleCast in dvd.CastList)
                            {
                                FillDynamicHash <CastMember>(castAndCrewHash, possibleCast);
                            }
                        }

                        if (dvd.CrewList != null && dvd.CrewList.Length > 0)
                        {
                            foreach (Object possibleCrew in dvd.CrewList)
                            {
                                FillDynamicHash <CrewMember>(castAndCrewHash, possibleCrew);
                            }
                        }
                    }

                    using (FileStream fs = new FileStream(targetFolder + "\\OnlineActorDatabase.txt", FileMode.Create, FileAccess.Write, FileShare.None))
                    {
                        using (StreamWriter sw = new StreamWriter(fs, Encoding.GetEncoding(1252)))
                        {
                            sw.Write("ID".PadRight(7));
                            sw.Write("First Name".PadRight(20));
                            sw.Write("Middle Name".PadRight(20));
                            sw.Write("Last Name".PadRight(20));
                            sw.WriteLine("Birth Year");
                            sw.WriteLine("".PadRight(77, '-'));

                            foreach (KeyValuePair <PersonKey, Int32> kvp in castAndCrewHash)
                            {
                                sw.Write(kvp.Value.ToString().PadLeft(6, '0').PadRight(7));
                                sw.Write(kvp.Key.Person.FirstName.PadRight(20));
                                sw.Write(kvp.Key.Person.MiddleName.PadRight(20));
                                sw.Write(kvp.Key.Person.LastName.PadRight(20));

                                if (kvp.Key.Person.BirthYear != 0)
                                {
                                    sw.WriteLine(kvp.Key.Person.BirthYear);
                                }
                                else
                                {
                                    sw.WriteLine();
                                }
                            }
                        }
                    }

                    #endregion

                    #region Phase 4: Create Profile Files

                    KnownFirstnamePrefixes = InitList(@"Data\KnownFirstnamePrefixes.txt");

                    KnownLastnamePrefixes = InitList(@"Data\KnownLastnamePrefixes.txt");

                    KnownLastnameSuffixes = InitList(@"Data\KnownLastnameSuffixes.txt");

                    StageNames = InitList(@"Data\StageNames.txt");

                    foreach (DVD dvd in collection.DVDList)
                    {
                        using (FileStream fs = new FileStream(targetFolder + "\\" + dvd.ID + "_Cast.txt", FileMode.Create, FileAccess.Write, FileShare.None))
                        {
                            using (StreamWriter sw = new StreamWriter(fs, Encoding.GetEncoding(1252)))
                            {
                                sw.WriteLine(dvd.Title);
                                sw.WriteLine();
                                sw.Write("ID".PadRight(7));
                                sw.Write("First Name".PadRight(20));
                                sw.Write("Middle Name".PadRight(20));
                                sw.Write("Last Name".PadRight(20));
                                sw.WriteLine("Role".PadRight(20));
                                sw.WriteLine("".PadRight(87, '-'));

                                if (dvd.CastList?.Length > 0)
                                {
                                    foreach (Object possibleCast in dvd.CastList)
                                    {
                                        CastMember cast = possibleCast as CastMember;

                                        if (cast != null)
                                        {
                                            sw.Write(castAndCrewHash[cast].ToString().PadLeft(6, '0').PadRight(7));

                                            if (String.IsNullOrEmpty(cast.CreditedAs))
                                            {
                                                sw.Write(cast.FirstName.PadRight(20));
                                                sw.Write(cast.MiddleName.PadRight(20));
                                                sw.Write(cast.LastName.PadRight(20));
                                                sw.WriteLine(cast.Role);
                                            }
                                            else
                                            {
                                                Name name = ParsePersonName(cast.CreditedAs);

                                                sw.Write(name.FirstName.ToString().PadRight(20));
                                                sw.Write(name.MiddleName.ToString().PadRight(20));
                                                sw.Write(name.LastName.ToString().PadRight(20));
                                                sw.WriteLine(cast.Role);
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }

                    #endregion
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine();
                Console.WriteLine("Error: {0}", ex.Message);
            }
            finally
            {
                Console.WriteLine();
                Console.WriteLine("Press <Enter> to exit.");

                Console.ReadLine();
            }
        }