using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Services;
using System.IO;
using System.Xml.Serialization;
using System.Collections;
using System.Configuration;

namespace SilverTunes_Web
{
    public class Album
    {
        public string Cover { get; set; }
        public string Title { get; set; }
        public string Artist { get; set; }
        public List<Song> Songs { get; set; }

        public Album()
        {
            Songs = new List<Song>();
        }
    }

    public class Song
    {
        public string Title { get; set; }
        public string Path { get; set; }
    }

    /// <summary>
    /// Summary description for MediaLibrary
    /// </summary>
    [WebService(Namespace = "http://tempuri.org/")]
    [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
    [System.ComponentModel.ToolboxItem(false)]
    // To allow this Web Service to be called from script, using ASP.NET AJAX, uncomment the following line. 
    // [System.Web.Script.Services.ScriptService]
    public class MediaLibrary : System.Web.Services.WebService
    {
        static string[] _acceptedMedia = new[] { ".mp3", ".wma" };

        public static bool IsLocalServer
        {
            get 
            { 
                return ConfigurationSettings.AppSettings["server"] == "local"; 
            }
        }

        [WebMethod]
        public List<Album> GetLibrary(string mediapath)
        {
            var albums = new List<Album>();
            var librarypath = Server.MapPath("medialibrary.xml");
            if (!string.IsNullOrEmpty(mediapath))
            {
                albums = BuildMediaLibrary(mediapath, librarypath);
            }
            else if (File.Exists(librarypath))
            {
                using (var stream = new FileStream(librarypath, FileMode.Open, FileAccess.Read))
                {
                    albums = (List<Album>)new XmlSerializer(typeof(List<Album>)).Deserialize(stream);
                }
            }
            else
            {
                albums = BuildMediaLibrary(Environment.GetFolderPath(Environment.SpecialFolder.MyMusic), librarypath);
            }

            return albums;
        }

        [WebMethod]
        public List<string> Dir(string path)
        {
            if (IsLocalServer)
            {
                if (string.IsNullOrEmpty(path))
                {
                    return Directory.GetLogicalDrives().ToList();
                }
                if (!path.EndsWith("\\"))
                {
                    path = path + "\\";
                }
                if (Directory.Exists(path))
                {
                    try
                    {
                        return Directory.GetDirectories(path).ToList();
                    }
                    catch (UnauthorizedAccessException) 
                    {
                    }
                }    
            }            
            return new List<string>();
        }

        private List<Album> BuildMediaLibrary(string mediapath, string librarypath)
        {
            var albums = new List<Album>();
            if (!IsLocalServer)
            {
                return albums;
            }
            var stack = new Stack<string>();
            stack.Push(mediapath);

            while(stack.Count > 0)
            {
                var file = stack.Pop();
                if (Directory.Exists(file))
                {
                    foreach (var child in Directory.GetDirectories(file).Concat(Directory.GetFiles(file)))
                    {
                        stack.Push(child);
                    }
                }
                else if (Path.GetExtension(file) == ".lnk")
                {
                    var target = GetFileFromShortcut(file);
                    if (!string.IsNullOrEmpty(target))
                    {
                        stack.Push(target);
                    }
                }
                else if (_acceptedMedia.Contains(Path.GetExtension(file)))
                {
                    try
                    {
                        var tag = TagLib.File.Create(file).Tag;
                        var album = albums.FirstOrDefault(a =>
                            a.Title == tag.Album
                            && a.Artist == (tag.FirstAlbumArtist ?? tag.FirstPerformer));
                        if (album == null)
                        {
                            album = new Album
                            {
                                Artist = tag.FirstAlbumArtist ?? tag.FirstPerformer,
                                Title = tag.Album,
                            };
                            var ipicture = tag.Pictures.FirstOrDefault(p => p.Type == TagLib.PictureType.FrontCover);
                            if (ipicture != null)
                            {
                                album.Cover = ResolvePath(file);
                            }

                            albums.Add(album);
                        }
                        album.Songs.Add(new Song { Title = tag.Title, Path = ResolvePath(file) });
                    }
                    catch { }
                }                
            }

            if (File.Exists(librarypath))
            {
                try
                {
                    var att = File.GetAttributes(librarypath);
                    if ((att | FileAttributes.ReadOnly) != 0)
                    {
                        File.SetAttributes(librarypath, att & ~FileAttributes.ReadOnly);
                    }
                }
                catch { }
            }
            using (var stream = new FileStream(librarypath, FileMode.Create, FileAccess.Write))
            {
                new XmlSerializer(typeof(List<Album>)).Serialize(stream, albums);
            }
            return albums;
        }

        private string ResolvePath(string file)
        {
            var webRoot = Server.MapPath("/");
            return file.StartsWith(webRoot, StringComparison.InvariantCultureIgnoreCase) ? file.Substring(webRoot.Length) : file;            
        }

        private static string GetFileFromShortcut(string path)
        {
            try
            {
                IWshRuntimeLibrary.WshShell wShell = new IWshRuntimeLibrary.WshShellClass();
                IWshRuntimeLibrary.WshShortcut wShortcut = (IWshRuntimeLibrary.WshShortcut)wShell.CreateShortcut(path);
                return wShortcut.TargetPath;
            }
            catch
            { }

            return null;
        }
    }
}
