using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Configuration;
using System.Runtime.Remoting.Messaging;
using System.Collections;
using MyTunes.Library;
using System.IO;

namespace MyTunes.Admin
{
    public partial class Cleanup : System.Web.UI.Page
    {
        private Global _g;

        protected void Page_Load(object sender, EventArgs e)
        {
            PanelUnauthorized.Visible = !User.IsInRole("Managers");
            PanelRun.Visible = !PanelUnauthorized.Visible;
            _g = (Global)HttpContext.Current.ApplicationInstance;
            if (_g.IsScanningActive)
                Response.Redirect("~/Admin/Wait.aspx");

        }

        protected void BtnCleanup_Click(object sender, EventArgs e)
        {
            _g.AsyncResult = StartCleanupProcess();
            Response.Redirect("Wait.aspx");
        }


        protected void btnCleanPlaylists_Click(object sender, EventArgs e)
        {
            _g.AsyncResult = StartPlaylistCheck();
            Response.Redirect("Wait.aspx");
        }

        private IAsyncResult StartPlaylistCheck()
        {
            string path = Server.MapPath(@"\Library\playlists\");
            CleanupDelegate d = new CleanupDelegate(CleanupOldPlaylists);
            return d.BeginInvoke(path, new AsyncCallback(ScanCallback), null);
        }


        private IAsyncResult StartCleanupProcess()
        {
            string path = ConfigurationManager.AppSettings["MusicPath"];

            CleanupDelegate d = new CleanupDelegate(DoCleanup);
            return d.BeginInvoke(path, new AsyncCallback(ScanCallback), null);
        }

        private delegate void CleanupDelegate(string path);

        private void ScanCallback(IAsyncResult ar)
        {
            AsyncResult aResult = (AsyncResult)ar;
            CleanupDelegate d = (CleanupDelegate)aResult.AsyncDelegate;
            d.EndInvoke(ar);
        }

        Hashtable mp3Files = null;
        List<int> _badSongs = null;
        private MyTunesDataContext db;

        private void DoCleanup(string path)
        {
            try
            {
                _g.IsScanningActive = true;

                db = new MyTunesDataContext();

                DirectoryInfo dirInfo = new DirectoryInfo(path);
                mp3Files = new Hashtable();
                FindMP3Files(dirInfo);

                _badSongs = new List<int>();
                CheckRecords();
                if (_badSongs.Count > 0)
                    RemoveBadRecords();
                else
                    _g.ScanResult = "No bad records found.";

            }
            catch (Exception ex)
            {
                _g.ScanResult = "Error: " + ex.Message;
            }
            finally
            {
                db.Connection.Close();
                db = null;
                _badSongs.Clear();
                _g.IsScanningActive = false;
            }

        }

        private void CleanupOldPlaylists(string path)
        {
            try
            {
                _g.IsScanningActive = true;

                int nFiles = 0;
                int nDeleted = 0;
                int nDirs = 0;
                int nRemoved = 0;

                if (Directory.Exists(path))
                {
                    DirectoryInfo di = new DirectoryInfo(path);
                    foreach (DirectoryInfo subDir in di.GetDirectories())
                    {
                        nDirs++;
                        foreach (FileInfo f in subDir.GetFiles())
                        {
                            nFiles++;
                            if (f.CreationTime.AddDays(1) < DateTime.Now)
                            {
                                f.Delete();
                                nDeleted++;
                            }
                            _g.ScanStatus = string.Format("Removed {0} of {1} playlists and {2} of {3} folders.",
                                nDeleted, nFiles, nRemoved, nDirs);
                        }
                    }

                    di.Refresh();
                    foreach (DirectoryInfo subDir in di.GetDirectories())
                    {
                        subDir.Refresh();
                        if (subDir.GetFiles().Count() == 0)
                        {
                            subDir.Delete();
                            nRemoved++;
                        }
                        _g.ScanStatus = string.Format("Removed {0} of {1} playlists and {2} of {3} folders.",
                            nDeleted, nFiles, nRemoved, nDirs);
                    }

                    di.Refresh();
                    if (di.GetFiles().Count() == 0 && di.GetDirectories().Count() == 0)
                    {
                        di.Delete();
                        nRemoved++;
                    }
                }

                _g.ScanResult = string.Format("Removed {0} of {1} playlists and {2} of {3} folders.",
                    nDeleted, nFiles, nRemoved, nDirs);
            }
            catch (Exception ex)
            {
                _g.ScanResult = "Error: " + ex.Message;
            }
            finally
            {
                _g.IsScanningActive = false;
            }
            
        }

        private void CheckRecords()
        {
            var songs = from Song in db.Songs
                        select new
                        {
                            Song.SongID,
                            Song.URL
                        };

            _g.ScanStatus = string.Format(
                "Comparing {0} database records to {1} MP3 files...",
                songs.Count(), mp3Files.Count);

            foreach (var s in songs)
            {
                if (!mp3Files.Contains(s.URL))
                    _badSongs.Add(s.SongID);
            }
        }

        private void RemoveBadRecords()
        {
            int processed = 0;
            int deleted = 0;

            foreach (int id in _badSongs)
            {
                var playlistRecords = from PlaylistItem in db.PlaylistItems
                                      where PlaylistItem.SongID == id
                                      select PlaylistItem;

                foreach (var selected in playlistRecords)
                {
                    db.PlaylistItems.DeleteOnSubmit(selected);
                    deleted++;
                }

                var songRecords = from Song in db.Songs
                                  where Song.SongID == id
                                  select Song;

                foreach (var selected in songRecords)
                {
                    db.Songs.DeleteOnSubmit(selected);
                    deleted++;
                }

                _g.ScanResult = string.Format(
                    "Removed {0} of {1} songs...",
                    processed++, _badSongs.Count);
            }

            db.SubmitChanges();
            _g.ScanResult = string.Format(
                "{0} bad song records found.  {1} total records deleted.",
                _badSongs.Count, deleted);
        }

        /// <summary>
        /// Recursively processes directories to locate all
        /// files that end with .mp3, then adds them to the
        /// mp3files field for additional processing.
        /// </summary>
        /// <param name="dir"></param>
        private void FindMP3Files(DirectoryInfo dir)
        {
            FileInfo[] files = dir.GetFiles("*.mp3");
            foreach (FileInfo file in files)
            {
                mp3Files.Add(file.FullName, file);
                _g.ScanStatus = String.Format("Searching for MP3 files. {0} found so far...", mp3Files.Count);
            }

            DirectoryInfo[] dirs = dir.GetDirectories();
            foreach (DirectoryInfo d in dirs)
                FindMP3Files(d);
        }
    }
}