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

            await _classicalMusicContext.Composers.LoadAsync(_loadingCancellationTokenSource.Token);

            var composerViewSource = (CollectionViewSource)FindResource("composerViewSource");
            composerViewSource.Source = _classicalMusicContext.Composers;
        }
        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;
        }
        public ComposerPage()
        {
            InitializeComponent();

            _logicalComparer = new LogicalComparer();
            _classicalMusicContext = new ClassicalMusicContext(new Uri("http://www.harrenstein.com/ClassicalMusic/ClassicalMusic.svc"));
            _classicalMusicContext.MergeOption = MergeOption.OverwriteChanges;
            _sampleDictionary = new Dictionary<IWaveProvider, Sample>();
            _mp3Player = new Mp3Player();

            _mp3Player.CurrentTimeChanged += Mp3Player_CurrentTimeChanged;
            _mp3Player.TotalTimeChanged += Mp3Player_TotalTimeChanged;
            _mp3Player.TrackChanged += Mp3Player_TrackChanged;
            _mp3Player.PlaybackStateChanged += Mp3Player_PlaybackStateChanged;
            _mp3Player.VolumeChanged += Mp3Player_VolumeChanged;
            _mp3Player.IsMutedChanged += Mp3Player_IsMutedChanged;
            _mp3Player.CanPlayChanged += Mp3Player_CanPlayChanged;
            _mp3Player.CanSkipBackChanged += Mp3Player_CanSkipBackChanged;
            _mp3Player.CanSkipForwardChanged += Mp3Player_CanSkipForwardChanged;

            Loaded += ComposerPage_Loaded;
        }
        public TimelinePage()
        {
            InitializeComponent();

            if (!DesignerProperties.GetIsInDesignMode(this))
            {
                _classicalMusicContext = new ClassicalMusicContext(new Uri("http://www.harrenstein.com/ClassicalMusic/ClassicalMusic.svc"));

                CloseCommand = new DelegateCommand(Exit);
                GoToCommand = new DelegateCommand(GoToEra);
                RebuildThumbnailCacheCommand = new DelegateCommand(RebuildThumbnailCache);
                FullScreenCommand = new DelegateCommand(ExpandToFullScreen);
                ChangeResolutionCommand = new DelegateCommand(ChangeResolution);

                timeline.Ruler = new TimeRuler();
                timeline.Ruler.TimeRulerUnit = TimeRulerUnit.Day;
                timeline.Ruler.TimeUnitWidth = 0.04109589041;
                timeline.Resolution = TimeResolution.Decade;
                timeline.Dates = new ExtendedDateTimeInterval(new ExtendedDateTime(476, 1, 1), ExtendedDateTime.Now);

                Loaded += TimelinePage_Loaded;
            }
        }
        private static BitmapImage CreateThumbnail(Composer composer)
        {
            BitmapImage thumbnail = null;
            var thumbnailPath = $@"{Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData, Environment.SpecialFolderOption.Create)}\Music Timeline\Resources\Thumbnails\{composer.ComposerId}.jpg";
            var context = new ClassicalMusicContext(new Uri("http://www.harrenstein.com/ClassicalMusic/ClassicalMusic.svc"));
            var image = context.Execute<ComposerImage>(new Uri($"http://www.harrenstein.com/ClassicalMusic/ClassicalMusic.svc/Composers({composer.ComposerId})/ComposerImages")).Select(c => c.Bytes).FirstOrDefault();

            if (image != null)
            {
                thumbnail = new BitmapImage();
                thumbnail.CacheOption = BitmapCacheOption.None;
                thumbnail.BeginInit();
                thumbnail.DecodePixelHeight = 40;
                thumbnail.StreamSource = new MemoryStream(image);
                thumbnail.EndInit();
                thumbnail.Freeze();

                var encoder = new JpegBitmapEncoder();
                encoder.QualityLevel = 60;
                encoder.Frames.Add(BitmapFrame.Create(thumbnail));

                using (var stream = new FileStream(thumbnailPath, FileMode.Create))
                {
                    encoder.Save(stream);
                }

                _thumbnailCache[composer.ComposerId] = thumbnail;

                return thumbnail;
            }
            else if (!_thumbnailCache.TryGetValue(0, out thumbnail))
            {
                thumbnailPath = $@"pack://application:,,,/Resources/Composers/Unknown.jpg";
                var thumbnailUri = new Uri(thumbnailPath, UriKind.Absolute);

                thumbnail = new BitmapImage(thumbnailUri);

                _thumbnailCache[0] = thumbnail;

                return thumbnail;
            }
            else
            {
                return thumbnail;
            }
        }
        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);

            DataContext = composer;

            ComposerDataGrid.ItemsSource = new Composer[] { composer };            

            if (!string.IsNullOrEmpty(composer.Details.Biography))
            {
                BiographyRichTextBox.Document = StringToFlowDocument(composer.Details.Biography);
            }

            await _classicalMusicContext.Locations.LoadAsync(_loadingCancellationTokenSource.Token);

            var locationViewSource = (CollectionViewSource)FindResource("locationViewSource");
            locationViewSource.Source = _classicalMusicContext.Locations.Local;

            await _classicalMusicContext.Eras.LoadAsync(_loadingCancellationTokenSource.Token);

            var eraViewSource = (CollectionViewSource)FindResource("eraViewSource");
            eraViewSource.Source = _classicalMusicContext.Eras.Local;

            await _classicalMusicContext.Nationalities.LoadAsync(_loadingCancellationTokenSource.Token);

            var nationalityViewSource = (CollectionViewSource)FindResource("nationalityViewSource");
            nationalityViewSource.Source = _classicalMusicContext.Nationalities.Local;

            await _classicalMusicContext.Composers.LoadAsync(_loadingCancellationTokenSource.Token);

            var composerViewSource = (CollectionViewSource)FindResource("composerViewSource");
            composerViewSource.Source = _classicalMusicContext.Composers.Local;

            await _classicalMusicContext.Keys.LoadAsync(_loadingCancellationTokenSource.Token);

            var keyViewSource = (CollectionViewSource)FindResource("keyViewSource");
            keyViewSource.Source = _classicalMusicContext.Keys.Local;
        }
        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
            }
        }
        public async static Task ScrapeComposerDetailPageAsync(string url, Composer composer, ClassicalMusicContext classicalMusicContext, IProgress<double> progress = null, CancellationToken? cancellationToken = null)
        {
            var composerLink = composer.Links.FirstOrDefault(l => l.Url.Contains("klassika.info"));

            if (composerLink == null)
            {
                composerLink = new Link();
                composerLink.Composers.Add(composer);
                composerLink.Url = url;

                composer.Links.Add(composerLink);
            }

            var urlParts = url.Split('/');

            if (urlParts.Length < 2)
            {
                return;
            }

            var composerKey = urlParts.ElementAt(urlParts.Length - 2);

            await ScrapeCompositionsPageAsync($"http://www.klassika.info/Komponisten/{composerKey}/wv_abc.html", composer, classicalMusicContext, progress, cancellationToken);
        }
        public async static Task ScrapeComposersPageAsync(ClassicalMusicContext classicalMusicContext)
        {
            for (char c = 'A'; c <= 'Z'; c++)
            {
                var webClient = new WebClient();
                var htmlSource = await webClient.DownloadStringTaskAsync(new Uri($"http://www.klassika.info/Komponisten/lindex_{c}.html"));

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

                var column1 = htmlDocument.GetElementbyId("personen_s1v3");
                var column2 = htmlDocument.GetElementbyId("personen_s2v3");

                var column1Anchors = column1.Elements("a");
                var column2Anchors = column2.Elements("a");

                var anchors = column1Anchors.Concat(column2Anchors);

                foreach (var anchor in anchors)
                {
                    var hypertextReference = anchor.Attributes["href"];

                    if (hypertextReference == null)
                    {
                        continue;
                    }

                    var composerNameAndDate = HtmlEntity.DeEntitize(anchor.InnerText);
                    var composerNameAndDateParts = composerNameAndDate.Split(new string[] { " (" }, 2, StringSplitOptions.None);
                    var composerName = composerNameAndDateParts.Length == 2 ? composerNameAndDateParts[0] : composerNameAndDate;
                    var composer = classicalMusicContext.Composers.FirstOrDefault(co => co.Name == composerName);

                    if (composer == null)
                    {
                        composer = new Composer();
                        composer.Name = composerName;

                        classicalMusicContext.Composers.Add(composer);
                    }

                    await ScrapeComposerDetailPageAsync($"http://www.klassika.info/{hypertextReference.Value}", composer, classicalMusicContext);
                }
            }

            classicalMusicContext.SaveChanges();
        }
        public static void ScrapeComposer(string url, Composer composer, ClassicalMusicContext dbContext)
        {
            if (url == null)
            {
                return;
            }

            var urlParts = url.Split('#');

            if (urlParts.Length != 2)
            {
                return;
            }

            string source = null;

            using (var webClient = new WebClient())
            {
                webClient.Proxy = null;

                try
                {
                    source = webClient.DownloadString(url);
                }
                catch (WebException e)
                {
                    MessageBox.Show(e.Message);

                    return;
                }
            }

            var htmlSegments = source.Split(new string[] { "<p>" }, StringSplitOptions.RemoveEmptyEntries);

            var composerHtmlSegment = htmlSegments.FirstOrDefault(s => s.Contains($"name=\"{urlParts[1]}\""));

            if (composerHtmlSegment == null)
            {
                return;
            }

            var hasInfluencedSplit = composerHtmlSegment.Split(new string[] { "instruc1.htm#e9" }, StringSplitOptions.RemoveEmptyEntries);

            if (hasInfluencedSplit.Length > 1)
            {
                var influencedComposerUrls = Regex.Matches(hasInfluencedSplit[1], "(?<=href=\").*?(?=\")").OfType<Match>().Select(m => "http://people.wku.edu/charles.smith/music/" + m.Value);

                foreach (var influencedComposerUrl in influencedComposerUrls)
                {
                    var influencedComposerLink = dbContext.Links.Where(l => l.Url == influencedComposerUrl).FirstOrDefault();

                    if (influencedComposerLink == null)
                    {
                        continue;
                    }

                    var influencedComposer = influencedComposerLink.Composers.FirstOrDefault();

                    if (!composer.Influenced.Contains(influencedComposer))
                    {
                        composer.Influenced.Add(influencedComposer);
                        influencedComposer.Influences.Add(composer);
                    }
                }
            }

            var influencesSplit = hasInfluencedSplit[0].Split(new string[] { "instruc1.htm#e8" }, StringSplitOptions.RemoveEmptyEntries);

            if (influencesSplit.Length > 1)
            {
                var influenceComposerUrls = Regex.Matches(influencesSplit[1], "(?<=href=\").*?(?=\")").OfType<Match>().Select(m => "http://people.wku.edu/charles.smith/music/" + m.Value);

                foreach (var influenceComposerUrl in influenceComposerUrls)
                {
                    var influenceComposerLink = dbContext.Links.Where(l => l.Url == influenceComposerUrl).FirstOrDefault();

                    if (influenceComposerLink == null)
                    {
                        continue;
                    }

                    var influenceComposer = influenceComposerLink.Composers.FirstOrDefault();

                    if (!composer.Influences.Contains(influenceComposer))
                    {
                        composer.Influences.Add(influenceComposer);
                        influenceComposer.Influenced.Add(composer);
                    }
                }
            }
        }