/// <summary>
        /// Get a track with basic information using ID to looking in database
        /// </summary>
        /// <param name="_ID"></param>
        /// <returns></returns>
        public static Track GetBasicTrackFromID(string _ID)
        {
            Track _track = new Track();

            _track.ID = _ID;

            using (dc = new MusicDBDataContext(Properties.Settings.Default.MusicConnectionString))
            {
                // Looking in database
                var query = (from bh in dc.BAIHATs
                             join tua in dc.TUAs on bh.Ma_Tua equals tua.Ma_Tua
                             join casi in dc.CASIs on bh.Ma_CaSi equals casi.Ma_CaSi
                             join album in dc.ALBUMs on bh.Ma_Album equals album.Ma_Album
                             join csAlbum in dc.CASIs on bh.Ma_CaSiAlbum equals csAlbum.Ma_CaSi
                             join theloai in dc.THELOAIs on bh.Ma_TheLoai equals theloai.Ma_TheLoai
                             join chitiet in dc.CHITIETBAIHATs on bh.Ma_BaiHat equals chitiet.Ma_BaiHat
                             where bh.Ma_BaiHat == _ID
                             select new
                {
                    DuongDan = bh.DuongDan,
                    Tua = tua.Ten_Tua,
                    CaSi = casi.Ten_CaSi,
                    Album = album.Ten_Album,
                    CasiAlbum = csAlbum.Ten_CaSi,
                    TheLoai = theloai.Ten_TheLoai,
                    ThLuong = chitiet.ThoiLuong,
                    Rating = chitiet.Rating,
                    CoAnhBia = chitiet.CoAnhBia,
                    Year = chitiet.NamPhatHanh,
                    PlayCount = chitiet.SoLanNghe,
                    NgayThem = chitiet.NgayThemVaoCSDL,
                    LanNgheCuoi = chitiet.LanNgheCuoi
                }).First();

                // Getting information
                _track.Location    = query.DuongDan;
                _track.Title       = query.Tua;
                _track.Artist      = query.CaSi;
                _track.Album       = query.Album;
                _track.AlbumArtist = query.CasiAlbum;
                _track.Genre       = query.TheLoai;
                _track.Duration    = query.ThLuong;
                _track.IsFavourite = query.Rating;
                _track.HasCoverArt = query.CoAnhBia;
                if (!string.IsNullOrWhiteSpace(query.Year))
                {
                    _track.Year = uint.Parse(query.Year);
                }
                _track.PlayCount  = query.PlayCount;
                _track.DateAdded  = query.NgayThem;
                _track.LastPlayed = query.LanNgheCuoi;
            }

            return(_track);
        }
        // DELETE


        /// <summary>
        /// Delete a track in DB
        /// </summary>
        /// <param name="_track"></param>
        public static void DeleteOneTrack(Track _track)
        {
            using (dc = new MusicDBDataContext(Properties.Settings.Default.MusicConnectionString))
            {
                // Deleting in ChiTiet first
                dc.CHITIETBAIHATs.DeleteOnSubmit(dc.CHITIETBAIHATs.Single(ctiet => ctiet.Ma_BaiHat == _track.ID));
                dc.BAIHATs.DeleteOnSubmit(dc.BAIHATs.Single(bh => bh.Ma_BaiHat == _track.ID));

                dc.SubmitChanges();
            }
        }
 /// <summary>
 /// Update Artist from Track (view) to DB
 /// </summary>
 /// <param name="dc"></param>
 /// <param name="_track"></param>
 public static void UpdateArtist(MusicDBDataContext dc, Track _track)
 {
     if (dc.CASIs.Any(casi => casi.Ten_CaSi == _track.Artist))
     {
         dc.BAIHATs.Single(bh => bh.Ma_BaiHat == _track.ID).Ma_CaSi = dc.CASIs.Single(casi => casi.Ten_CaSi == _track.Artist).Ma_CaSi;
     }
     else
     {
         Writer.Write2_CASI1(_track, dc);
         dc.BAIHATs.Single(bh => bh.Ma_BaiHat == _track.ID).Ma_CaSi = dc.CASIs.Single(casi => casi.Ten_CaSi == _track.Artist).Ma_CaSi;
     }
     dc.SubmitChanges();
 }
 /// <summary>
 /// Update Title from Track (view) to DB
 /// </summary>
 /// <param name="dc"></param>
 /// <param name="_track"></param>
 public static void UpdateTitle(MusicDBDataContext dc, Track _track)
 {
     if (dc.TUAs.Any(tua => tua.Ten_Tua == _track.Title))
     {
         dc.BAIHATs.Single(bh => bh.Ma_BaiHat == _track.ID).Ma_Tua = dc.TUAs.Single(tua => tua.Ten_Tua == _track.Title).Ma_Tua;
     }
     else
     {
         Writer.Write2_TUA(_track, dc);
         dc.BAIHATs.Single(bh => bh.Ma_BaiHat == _track.ID).Ma_Tua = dc.TUAs.Single(tua => tua.Ten_Tua == _track.Title).Ma_Tua;
     }
     dc.SubmitChanges();
 }
        /// <summary>
        /// Push other details to CHITIETBAIHAT
        /// </summary>
        /// <param name="_track"></param>
        /// <param name="bh"></param>
        /// <param name="dc"></param>
        public static void Write2_CHITIETBAIHAT(Track _track, MusicDBDataContext dc, BAIHAT bh)
        {
            CHITIETBAIHAT chitiet = new CHITIETBAIHAT();

            chitiet.Ma_BaiHat       = bh.Ma_BaiHat;
            chitiet.ThoiLuong       = _track.Duration;
            chitiet.CoAnhBia        = _track.HasCoverArt;
            chitiet.NgayThemVaoCSDL = _track.DateAdded;
            chitiet.NamPhatHanh     = _track.Year.ToString();

            dc.CHITIETBAIHATs.InsertOnSubmit(chitiet);
            dc.SubmitChanges();
        }
 /// <summary>
 /// Update Genre from Track (view) to DB
 /// </summary>
 /// <param name="dc"></param>
 /// <param name="_track"></param>
 public static void UpdateGenre(MusicDBDataContext dc, Track _track)
 {
     if (dc.THELOAIs.Any(tl => tl.Ten_TheLoai == _track.Genre))
     {
         dc.BAIHATs.Single(bh => bh.Ma_BaiHat == _track.ID).Ma_TheLoai = dc.THELOAIs.Single(tl => tl.Ten_TheLoai == _track.Genre).Ma_TheLoai;
     }
     else
     {
         Writer.Write2_THELOAI(_track, dc);
         dc.BAIHATs.Single(bh => bh.Ma_BaiHat == _track.ID).Ma_TheLoai = dc.THELOAIs.Single(tl => tl.Ten_TheLoai == _track.Genre).Ma_TheLoai;
     }
     dc.SubmitChanges();
 }
 /// <summary>
 /// Update Album from Track (view) to DB
 /// </summary>
 /// <param name="dc"></param>
 /// <param name="_track"></param>
 public static void UpdateAlbum(MusicDBDataContext dc, Track _track)
 {
     if (dc.ALBUMs.Any(album => album.Ten_Album == _track.Album))
     {
         dc.BAIHATs.Single(bh => bh.Ma_BaiHat == _track.ID).Ma_Album = dc.ALBUMs.Single(album => album.Ten_Album == _track.Album).Ma_Album;
     }
     else
     {
         Writer.Write2_ALBUM(_track, dc);
         dc.BAIHATs.Single(bh => bh.Ma_BaiHat == _track.ID).Ma_Album = dc.ALBUMs.Single(album => album.Ten_Album == _track.Album).Ma_Album;
     }
     dc.SubmitChanges();
 }
        /// <summary>
        /// Update last time play that 'track'
        /// </summary>
        /// <param name="track"></param>
        public static void UpdateLastTimePlay(Track track)
        {
            using (dc = new MusicDBDataContext(Properties.Settings.Default.MusicConnectionString))
            {
                CHITIETBAIHAT _ctiet = dc.CHITIETBAIHATs.Single(ctiet => ctiet.Ma_BaiHat == track.ID);

                if (_ctiet != null)
                {
                    _ctiet.LanNgheCuoi = DateTime.Now;
                }

                dc.SubmitChanges();
            }
        }
        /// <summary>
        /// Update Favourite Only
        /// </summary>
        /// <param name="_ID">Song_ID:int</param>
        /// <param name="_isFavourite">Favourite:Boolean</param>
        public static void UpdateOnlyFavourite2DB(string _ID, bool _isFavourite)
        {
            using (dc = new MusicDBDataContext(Properties.Settings.Default.MusicConnectionString))
            {
                CHITIETBAIHAT _ctiet = dc.CHITIETBAIHATs.Single(ctiet => ctiet.Ma_BaiHat == _ID);

                if (_ctiet != null)
                {
                    _ctiet.Rating = _isFavourite;
                }

                dc.SubmitChanges();
            }
        }
        /// <summary>
        /// Track processing with dialog
        /// </summary>
        /// <param name="filespaths">List of string</param>
        public static async Task TrackProcess(MetroWindow window, List <string> filespaths)
        {
            // Call ProgressDialog
            var processDialog = await window.ShowProgressAsync(
                window.FindResource("pleaseWait").ToString(), window.FindResource("trackProcessing").ToString());

            processDialog.SetIndeterminate();

            await Task.Run(() =>
            {
                // Parallel for loop, with maximun of degree is the number of processors
                Parallel.For(0, filespaths.Count, new ParallelOptions {
                    MaxDegreeOfParallelism = Environment.ProcessorCount
                }, (int i) =>
                {
                    using (var dc = new MusicDBDataContext(Properties.Settings.Default.MusicConnectionString))
                    {
                        // Thread sleep
                        //Thread.Sleep(new Random().Next(50, 500));

                        // Only handle file with extension is M4A or MP3
                        string ext = System.IO.Path.GetExtension(filespaths[i]).ToUpperInvariant();
                        if (ext == ".M4A" || ext == ".MP3")
                        {
                            Writer.ImportTrack2Database(dc, Reader.GetBasicTrack(filespaths[i]));
                        }
                    }
                });

                // One way processing

                //for (int i = 0; i < filespaths.Count; i++)
                //{
                //    using (var dc = new MusicDBDataContext(Properties.Settings.Default.MusicConnectionString))
                //    {
                //        string ext = System.IO.Path.GetExtension(filespaths[i]).ToUpperInvariant();
                //        if (ext == ".M4A" || ext == ".MP3")
                //        {
                //            //Track _track = Reader.GetBasicTrack(filespaths[i]);
                //            Writer.ImportTrack2Database(dc, Reader.GetBasicTrack(filespaths[i]));
                //        }
                //    }
                //}
            });

            await processDialog.CloseAsync();
        }
        /// <summary>
        /// Import basic information of a track to database
        /// </summary>
        /// <param name="_track"></param>
        public static void ImportTrack2Database(MusicDBDataContext dc, Track _track)
        {
            if (_track == null)
            {
                return;
            }

            BAIHAT        bh   = new BAIHAT();
            CHITIETBAIHAT ctbh = new CHITIETBAIHAT();

            // If the file path has exist in database so that file has added. Return!
            if (dc.BAIHATs.Any(s => s.DuongDan == _track.Location))
            {
                return;
            }

            // FILL TABLE BAIHAT, CASI, TUA, THELOAI, ALBUM:
            // 1: Checking and FILL information to Tables: CASI, TUA, THELOAI, ALBUM
            // 2: Fill table BAIHAT by getting the ID from those tables.

            bh.DuongDan  = _track.Location;
            bh.Ma_BaiHat = Utils.GenerateID("BAIHAT");

            // Check exist and add a new Artist in table
            bh.Ma_CaSi = Write2_CASI1(_track, dc);

            // Check exist and add a new Title in table TUA
            bh.Ma_Tua = Write2_TUA(_track, dc);

            // Check exist and add a new Album in table ALBUM
            bh.Ma_Album = Write2_ALBUM(_track, dc);

            // Check exist and add a new Genre in table THELOAI
            bh.Ma_TheLoai = Write2_THELOAI(_track, dc);

            // Check exist and add a new AlbumArtist in table CASI
            bh.Ma_CaSiAlbum = Write2_CASI2(_track, dc);

            dc.BAIHATs.InsertOnSubmit(bh);
            dc.SubmitChanges();

            // FILL TABLE CHITIETBAIHAT
            Write2_CHITIETBAIHAT(_track, dc, bh);
            //}
        }
        /// <summary>
        /// Clean up and refresh database
        /// </summary>
        public static async void CleanDatabase()
        {
            using (var dc = new MusicDBDataContext(Properties.Settings.Default.MusicConnectionString))
            {
                dc.ExecuteCommand("DELETE FROM CHITIETBAIHAT");
                dc.ExecuteCommand("DELETE FROM BAIHAT");
                await Task.Run(() => { dc.ExecuteCommand("DELETE FROM TUA"); });

                await Task.Run(() => { dc.ExecuteCommand("DELETE FROM CASI"); });

                await Task.Run(() => { dc.ExecuteCommand("DELETE FROM ALBUMS"); });

                await Task.Run(() => { dc.ExecuteCommand("DELETE FROM THELOAI"); });

                await Task.Run(() => { PlaylistsSetting.DeletePlaylistsFile(); });

                dc.SubmitChanges();
            }
        }
        /// <summary>
        /// Get 50 recently added tracks from library
        /// </summary>
        /// <param name="_playlist"></param>
        /// <returns></returns>
        public static Playlist GetRecentlyAdded()
        {
            Playlist _recentlyAdded = new Playlist();

            _recentlyAdded.Name    = Application.Current.Resources["recentlyAdded"].ToString();
            _recentlyAdded.Prio    = Playlist.Priority.Application;
            _recentlyAdded.Icon    = Utils.ConvertBitmapSourceToByteArray(new Uri(@"pack://application:,,,/Resources/Images/listbox_recentlyAdded.png"));
            _recentlyAdded.CanEdit = false;

            // Use LINQ to get 50 most recent tracks from library, and collect them
            using (dc = new MusicDBDataContext(Properties.Settings.Default.MusicConnectionString))
            {
                var query = (from chitiet in dc.CHITIETBAIHATs
                             orderby chitiet.NgayThemVaoCSDL descending
                             select chitiet.Ma_BaiHat).Take(50);
                query.ToList().ForEach(maBaiHat => _recentlyAdded.ListTrack.Add(GetBasicTrack(maBaiHat)));
            }
            return(_recentlyAdded);
        }
        // UPDATER


        /// <summary>
        /// Update Details to DB
        /// </summary>
        /// <param name="_track"></param>
        public static void UpdateDetails2DB(Track _track)
        {
            using (dc = new MusicDBDataContext(Properties.Settings.Default.MusicConnectionString))
            {
                // Update Title
                UpdateTitle(dc, _track);
                // Update Artist
                UpdateArtist(dc, _track);
                // Update Album
                UpdateAlbum(dc, _track);
                // Update AlbumArtist
                UpdateAlbumArtist(dc, _track);
                // Update Genre
                UpdateGenre(dc, _track);
                // Update Year
                UpdateYear(dc, _track);
                // Update Favourite
                UpdateFavourite(dc, _track);
            }
        }
        /// <summary>
        /// Get favourite tracks from given _playlist
        /// </summary>
        /// <returns></returns>
        public static Playlist GetFavourites()
        {
            Playlist _favourites = new Playlist();

            _favourites.Name    = Application.Current.Resources["favourite"].ToString();
            _favourites.Prio    = Playlist.Priority.Application;
            _favourites.Icon    = Utils.ConvertBitmapSourceToByteArray(new Uri(@"pack://application:,,,/Resources/Images/listbox_favourite.png"));
            _favourites.CanEdit = false;

            // Use LINQ to get favourite tracks from a given _playlist, and collect them
            using (dc = new MusicDBDataContext(Properties.Settings.Default.MusicConnectionString))
            {
                var query = (from chitiet in dc.CHITIETBAIHATs
                             where chitiet.Rating == true
                             select chitiet.Ma_BaiHat);
                query.ToList().ForEach(maBaiHat => _favourites.ListTrack.Add(GetBasicTrack(maBaiHat)));
            }

            return(_favourites);
        }
        /// <summary>
        /// Push artist name to CASI
        /// </summary>
        /// <param name="_track"></param>
        /// <param name="dc"></param>
        public static string Write2_CASI1(Track _track, MusicDBDataContext dc)
        {
            if (dc.CASIs.Any(cs => cs.Ten_CaSi == _track.Artist))
            {
                return((from cs in dc.CASIs
                        where cs.Ten_CaSi == _track.Artist
                        select cs.Ma_CaSi).FirstOrDefault());
            }
            else
            {
                CASI casi = new CASI();

                casi.Ma_CaSi  = Utils.GenerateID("CASI");
                casi.Ten_CaSi = _track.Artist;

                dc.CASIs.InsertOnSubmit(casi);
                dc.SubmitChanges();

                return(casi.Ma_CaSi);
            }
        }
        /// <summary>
        /// Push genre to THELOAI
        /// </summary>
        /// <param name="_track"></param>
        /// <param name="dc"></param>
        public static string Write2_THELOAI(Track _track, MusicDBDataContext dc)
        {
            if (dc.THELOAIs.Any(tl => tl.Ten_TheLoai == _track.Genre))
            {
                return((from tl in dc.THELOAIs
                        where tl.Ten_TheLoai == _track.Genre
                        select tl.Ma_TheLoai).FirstOrDefault());
            }
            else
            {
                THELOAI theloai = new THELOAI();

                theloai.Ma_TheLoai  = Utils.GenerateID("THELOAI");
                theloai.Ten_TheLoai = _track.Genre;

                dc.THELOAIs.InsertOnSubmit(theloai);
                dc.SubmitChanges();

                return(theloai.Ma_TheLoai);
            }
        }
        /// <summary>
        /// Push title to TUA
        /// </summary>
        /// <param name="_track"></param>
        /// <param name="dc"></param>
        public static string Write2_TUA(Track _track, MusicDBDataContext dc)
        {
            if (dc.TUAs.Any(tua => tua.Ten_Tua == _track.Title))
            {
                return((from tua in dc.TUAs
                        where tua.Ten_Tua == _track.Title
                        select tua.Ma_Tua).FirstOrDefault());
            }
            else
            {
                TUA tua = new TUA();

                tua.Ma_Tua  = Utils.GenerateID("TUA");
                tua.Ten_Tua = _track.Title;

                dc.TUAs.InsertOnSubmit(tua);
                dc.SubmitChanges();

                return(tua.Ma_Tua);
            }
        }
        /// <summary>
        /// Push album name to ALBUM
        /// </summary>
        /// <param name="_track"></param>
        /// <param name="dc"></param>
        public static string Write2_ALBUM(Track _track, MusicDBDataContext dc)
        {
            if (dc.ALBUMs.Any(alb => alb.Ten_Album == _track.Album))
            {
                return((from alb in dc.ALBUMs
                        where alb.Ten_Album == _track.Album
                        select alb.Ma_Album).FirstOrDefault());
            }
            else
            {
                ALBUM album = new ALBUM();

                album.Ma_Album  = Utils.GenerateID("ALBUM");
                album.Ten_Album = _track.Album;

                dc.ALBUMs.InsertOnSubmit(album);
                dc.SubmitChanges();

                return(album.Ma_Album);
            }
        }
        /// <summary>
        /// Get all songs in database
        /// </summary>
        /// <returns></returns>
        public static Playlist GetSongs()
        {
            var _songs = new Playlist();

            _songs.Name    = Application.Current.Resources["songs"].ToString();
            _songs.Prio    = Playlist.Priority.Application;
            _songs.Icon    = Utils.ConvertBitmapSourceToByteArray(new Uri(@"pack://application:,,,/Resources/Images/listbox_songs.png"));
            _songs.CanEdit = true;

            using (dc = new MusicDBDataContext(Properties.Settings.Default.MusicConnectionString))
            {
                var tmp = new ObservableCollection <Track>();

                // Get all IDs in table BaiHat, foreach ID get basic track, and collect all of them
                (from baihat in dc.BAIHATs
                 select baihat.Ma_BaiHat).ToList().ForEach(maBaiHat => tmp.Add(GetBasicTrackFromID(maBaiHat)));

                // Sorting collection
                _songs.ListTrack = new ObservableCollection <Track>(tmp.OrderBy(track => track.Title));
                tmp = null;
            }

            return(_songs);
        }
        /// <summary>
        /// Get other details of a track by reading directly on file
        /// </summary>
        /// <param name="_location"></param>
        /// <returns></returns>
        public static void GetDetailsOfTrack(ref Track _track)
        {
            if (!_track.IsExist)
            {
                return;
            }

            using (f = TagLib.File.Create(_track.Location))
            {
                // Album artist
                _track.AlbumArtist = string.IsNullOrWhiteSpace(f.Tag.FirstAlbumArtist) ? UNKNOW : f.Tag.FirstAlbumArtist;

                // Composer
                _track.Composer = string.IsNullOrWhiteSpace(f.Tag.FirstComposer) ? UNKNOW : f.Tag.FirstComposer;

                // Cover Art
                if (_track.HasCoverArt)
                {
                    _track.CoverArt = f.Tag.Pictures[0].Data.Data;
                }
                else
                {
                    _track.CoverArt = Utils.ConvertBitmapSourceToByteArray(new Uri(@"pack://application:,,,/Resources/Images/emptyImage.png"));
                }

                // File kind
                _track.Kind = GetFormatKind(Path.GetExtension(_track.Location).ToUpperInvariant());

                // Track info
                var trackNo    = f.Tag.Track;
                var trackCount = f.Tag.TrackCount;
                // Using C# 6.0 here!
                _track.TrackInfo = (trackCount > 0) ? string.Format($"{trackNo}/{trackCount}") : string.Empty;

                // Lyrics
                _track.Lyrics = (f.Tag.Lyrics != null) ? f.Tag.Lyrics : null;

                // Is Variable Bit Rate
                if (_track.Kind == "MPEG-3")
                {
                    var codec = f.Properties.Codecs.FirstOrDefault(c => c is TagLib.Mpeg.AudioHeader);
                    _track.IsVBR = codec != null && (((TagLib.Mpeg.AudioHeader)codec).VBRIHeader.Present || ((TagLib.Mpeg.AudioHeader)codec).XingHeader.Present);
                }
                else
                {
                    _track.IsVBR = false;
                }

                // Bit rate
                if (_track.IsVBR)
                {
                    var fileSizeinBit = new FileInfo(_track.Location).Length * 8;
                    var seconds       = f.Properties.Duration.TotalSeconds;

                    _track.BitRate = ((int)(fileSizeinBit / seconds)).ToString().Remove(3) + " kbps (VBR)";
                }
                else
                {
                    _track.BitRate = f.Properties.AudioBitrate.ToString() + " kbps";
                }

                // Sample Rate
                _track.SampleRate = f.Properties.AudioSampleRate.ToString() + " Hz";

                // Channels
                _track.Channels = GetChannels(f.Properties.AudioChannels);

                // Copy Right
                _track.CopyRight = f.Tag.Copyright;
            }

            using (var dc = new MusicDBDataContext(Properties.Settings.Default.MusicConnectionString))
            {
                var temp  = _track;
                var track = dc.CHITIETBAIHATs.FirstOrDefault(item => item.Ma_BaiHat == temp.ID);

                _track.PlayCount  = track.SoLanNghe;
                _track.LastPlayed = track.LanNgheCuoi;

                temp = null; track = null;
            }
        }
 /// <summary>
 /// Update Year from track (view) to DB
 /// </summary>
 /// <param name="dc"></param>
 /// <param name="_track"></param>
 public static void UpdateYear(MusicDBDataContext dc, Track _track)
 {
     dc.CHITIETBAIHATs.Single(ctiet => ctiet.Ma_BaiHat == _track.ID).NamPhatHanh = _track.Year.Value.ToString();
     dc.SubmitChanges();
 }
 /// <summary>
 /// Update Favourite
 /// </summary>
 /// <param name="_ID">Song_ID:int</param>
 /// <param name="_isFavourite">Favourite:Boolean</param>
 public static void UpdateFavourite(MusicDBDataContext dc, Track _track)
 {
     dc.CHITIETBAIHATs.Single(ctiet => ctiet.Ma_BaiHat == _track.ID).Rating = _track.IsFavourite;
     dc.SubmitChanges();
 }