private async void Page_Loaded(object sender, RoutedEventArgs e)
        {
            _classicalMusicContext = new ClassicalMusicContext(new Uri("http://www.harrenstein.com/ClassicalMusic/ClassicalMusic.svc"));
            _loadingCancellationTokenSource = new CancellationTokenSource();

            var composerId = (int)Application.Current.Properties["SelectedComposer"];
            var composer = await _classicalMusicContext.Composers.FirstAsync(c => c.ComposerId == composerId, _loadingCancellationTokenSource.Token);

            var compositionId = (int)Application.Current.Properties["SelectedComposition"];
            var composition = composer.Compositions.FirstOrDefault(c => c.CompositionId == compositionId);

            DataContext = composition;

            var compositionArray = new Composition[] { composition };

            CompositionDataGrid.ItemsSource = compositionArray;
            CompositionDataGrid2.ItemsSource = compositionArray;
            CommentDataGrid.ItemsSource = compositionArray;
        }
        private string CompositionToCompositionDisplayName(Composition composition)
        {
            if (composition == null)
            {
                return null;
            }

            var stringBuilder = new StringBuilder();
            stringBuilder.Append(composition.Name);

            var catalogNumber = composition.CatalogNumbers.FirstOrDefault();

            if (catalogNumber != null)
            {
                stringBuilder.Append(", ");
                stringBuilder.Append(catalogNumber.Catalog.Prefix);
                stringBuilder.Append(" ");
                stringBuilder.Append(catalogNumber.Value);
            }

            return stringBuilder.ToString();
        }
        public async static Task ScrapeCompositionDetailPageAsync(string url, Composition composition, ClassicalMusicContext classicalMusicContext)
        {
            var compositionWebpage = composition.Links.FirstOrDefault(l => l.Url.Contains("klassika.info"));

            if (compositionWebpage == null)
            {
                compositionWebpage = new Link();
                compositionWebpage.Compositions.Add(composition);
                compositionWebpage.Url = url;

                composition.Links.Add(compositionWebpage);
            }

            var webClient = new WebClient();
            var htmlSource = await webClient.DownloadStringTaskAsync(new Uri(url));

            var htmlDocument = new HtmlDocument();
            htmlDocument.LoadHtml(htmlSource);

            var generalInformationHeader = htmlDocument.DocumentNode
                .Descendants("h2")
                .FirstOrDefault(n => n.InnerText == "Allgemeine Angaben zum Werk:");

            if (generalInformationHeader != null)
            {
                var generalInformationTable = generalInformationHeader.NextSibling.NextSibling;

                var tableRows = generalInformationTable.Descendants("tr");

                foreach (var tableRow in tableRows)
                {
                    var tableDatas = tableRow
                        .Elements("td")
                        .ToArray();

                    var headerTableData = tableDatas[0];
                    var valueTableData = tableDatas[1];

                    var header = HtmlEntity.DeEntitize(headerTableData.InnerText);
                    var value = HtmlEntity.DeEntitize(valueTableData.InnerText);

                    if (header == "Tonart:")
                    {
                        var key = classicalMusicContext.Keys.FirstOrDefault(k => k.Name == value);

                        if (key == null)
                        {
                            key = new Key();
                            key.Name = value;
                            key.Compositions.Add(composition);

                            composition.Key = key;

                            classicalMusicContext.Keys.Add(key);
                        }

                        if (composition.Key == null)
                        {
                            composition.Key = key;
                        }

                    }
                    else if (header == "Widmung:")
                    {
                        if (composition.Dedication == null)
                        {
                            composition.Dedication = value;
                        }
                    }
                    else if (header == "Besetzung:")
                    {
                        var instrumentation = classicalMusicContext.Instrumentations.FirstOrDefault(i => i.Name == value);

                        if (instrumentation == null)
                        {
                            instrumentation = new Instrumentation();
                            instrumentation.Name = value;
                            instrumentation.Compositions.Add(composition);

                            composition.Instrumentation = instrumentation;

                            classicalMusicContext.Instrumentations.Add(instrumentation);
                        }

                        if (composition.Instrumentation == null)
                        {
                            composition.Instrumentation = instrumentation;
                        }
                    }
                    else if (header == "Uraufführung:")
                    {
                        if (composition.Premiere == null)
                        {
                            composition.Premiere = value;
                        }
                    }
                    else if (header == "Entstehungszeit:")
                    {
                        if (composition.Dates == null)
                        {
                            composition.Dates = value;
                        }
                    }
                    else if (header == "Anlass:")
                    {
                        if (composition.Occasion == null)
                        {
                            composition.Occasion = value;
                        }
                    }
                    else if (header == "Bemerkung:")
                    {
                        if (composition.Comment == null)
                        {
                            composition.Comment = value;
                        }
                    }
                }
            }

            var movementsHeader = htmlDocument.DocumentNode
                .Descendants("h2")
                .FirstOrDefault(n => n.InnerText == "Sätze:");

            if (movementsHeader != null)
            {
                var movementTable = movementsHeader.NextSibling.NextSibling;

                var tableRows = movementTable.Descendants("tr");

                foreach (var tableRow in tableRows)
                {
                    var movementNumberTableData = tableRow
                        .Elements("td")
                        .ElementAt(0);

                    var movementNameTableData = tableRow
                        .Elements("td")
                        .ElementAt(1);

                    short movementNumber;
                    
                    if (!short.TryParse(HtmlEntity.DeEntitize(movementNumberTableData.InnerText).Replace(". Satz:", ""), out movementNumber))
                    {
                        var tableRowsArray = tableRows.ToArray();
                        var tableRowIndex = Array.IndexOf(tableRowsArray, tableRow);

                        movementNumber = Convert.ToInt16(tableRowIndex + 1);
                    }

                    var movementName = HtmlEntity.DeEntitize(movementNameTableData.InnerText);

                    var movement = composition.Movements.FirstOrDefault(m => m.Number == movementNumber);

                    if (movement == null)
                    {
                        movement = new Movement();
                        movement.Name = movementName;
                        movement.Composition = composition;
                        movement.Number = movementNumber;

                        composition.Movements.Add(movement);
                    }
                }
            }
        }
        public async static Task ScrapeCompositionsPageAsync(string url, Composer composer, ClassicalMusicContext classicalMusicContext, IProgress<double> progress = null, CancellationToken? cancellationToken = null)
        {
            var webClient = new WebClient();
            var htmlSource = await webClient.DownloadStringTaskAsync(new Uri(url));

            var htmlDocument = new HtmlDocument();
            htmlDocument.LoadHtml(htmlSource);

            var tables = htmlDocument.DocumentNode.Descendants("table");
            var table = tables.FirstOrDefault(n =>
            {
                var classAttribute = n.Attributes["class"];

                if (classAttribute == null || classAttribute.Value != "wv")
                {
                    return false;
                }

                return true;
            });

            if (table == null)
            {
                return;
            }

            var tableRows = table.Elements("tr").ToArray();
            var increment = 1d;

            foreach (var tableRow in tableRows)
            {
                if (cancellationToken != null && cancellationToken.Value.IsCancellationRequested)
                {
                    return;
                }

                var tableDatas = tableRow.Elements("td").ToArray();

                var nameTableData = tableDatas[1];
                var compositionName = HtmlEntity.DeEntitize(nameTableData.InnerText);

                var compositionAnchor = nameTableData.Element("a");
                var hypertextReference = (HtmlAttribute)null;

                var composition = (Composition)null;

                if (compositionAnchor != null)
                {
                    hypertextReference = compositionAnchor.Attributes["href"];

                    if (hypertextReference != null)
                    {
                        composition = composer.Compositions.FirstOrDefault(c => c.Links.Any(l => l.Url == $"http://www.klassika.info/{hypertextReference.Value}"));
                    }
                }

                var catalogTableData = tableDatas[2];
                var catalogString = HtmlEntity.DeEntitize(catalogTableData.InnerText);

                var dateTableData = tableDatas[4];
                var compositionDate = HtmlEntity.DeEntitize(dateTableData.InnerText);

                var genreTableData = tableDatas[6];
                var genreName = TranslateGenre(HtmlEntity.DeEntitize(genreTableData.InnerText).Replace("(", "").Replace(")", ""));

                if (composition == null)
                {
                    composition = new Composition();
                    composition.Name = compositionName;
                    composition.Composers = new DataServiceCollection<Composer> { composer };
                    composition.Dates = compositionDate == "?" ? null : compositionDate;

                    composer.Compositions.Add(composition);
                }

                var catalogNumberString = (string)null;
                var compositionCatalogString = (string)null;

                if (!string.IsNullOrWhiteSpace(genreName))
                {
                    var genre = classicalMusicContext.Genres.FirstOrDefault(ct => ct.Name == genreName);

                    if (genre == null)
                    {
                        genre = new Genre();
                        genre.Name = genreName;
                        genre.Compositions.Add(composition);

                        classicalMusicContext.Genres.Add(genre);
                    }

                    if (composition.Genre == null)
                    {
                        composition.Genre = genre;
                    }
                }

                if (!string.IsNullOrWhiteSpace(catalogString))
                {
                    var catalogParts = catalogString.Split(new char[] { ' ' }, 2);

                    if (catalogParts.Length == 2)
                    {
                        compositionCatalogString = catalogParts[0];
                        catalogNumberString = catalogParts[1];

                        var catalog = composer.Catalogs.FirstOrDefault(cc => cc.Prefix == compositionCatalogString);

                        if (catalog == null)
                        {
                            catalog = new Catalog();
                            catalog.Prefix = compositionCatalogString;
                            catalog.Composer = composer;

                            composer.Catalogs.Add(catalog);
                        }

                        var catalogNumber = catalog.CatalogNumbers.FirstOrDefault(cn => cn.Value == catalogNumberString);

                        if (catalogNumber == null)
                        {
                            catalogNumber = new CatalogNumber();
                            catalogNumber.Catalog = catalog;
                            catalogNumber.Compositions.Add(composition);
                            catalogNumber.Value = catalogNumberString;

                            catalog.CatalogNumbers.Add(catalogNumber);
                        }
                    }
                }

                if (hypertextReference != null)
                {
                    await ScrapeCompositionDetailPageAsync($"http://www.klassika.info/{hypertextReference.Value}", composition, classicalMusicContext);
                }

                if (progress != null)
                {
                    progress.Report(increment++ / (double)tableRows.Length);
                }

#if DEBUG
                Debug.WriteLine(composition.Name);
#endif
            }
        }