using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
namespace AR.FTPClient
{
    /// 
    ///     ''' Represents a file or directory entry from an FTP listing
    ///     ''' 
    ///     ''' 
    ///     ''' This class is used to parse the results from a detailed
    ///     ''' directory list from FTP. It supports most formats of
    ///     ''' 
    public class FTPfileInfo
    {
        // Stores extended info about FTP file
        public string FullName
        {
            get
            {
                var retval = Path + "/" + Filename;
                return retval.Replace("//", "/");
            }
        }
        public string Filename
        {
            get
            {
                return _filename;
            }
        }
        public string Path
        {
            get
            {
                return _path;
            }
        }
        public DirectoryEntryTypes FileType
        {
            get
            {
                return _fileType;
            }
        }
        public long Size
        {
            get
            {
                return _size;
            }
        }
        public DateTime FileDateTime
        {
            get
            {
                return _fileDateTime;
            }
        }
        public string Permission
        {
            get
            {
                return _permission;
            }
        }
        public string Extension
        {
            get
            {
                int i = this.Filename.LastIndexOf(".");
                if (i >= 0 & i < (this.Filename.Length - 1))
                    return this.Filename.Substring(i + 1);
                else
                    return "";
            }
        }
        public string NameOnly
        {
            get
            {
                int i = this.Filename.LastIndexOf(".");
                if (i > 0)
                    return this.Filename.Substring(0, i);
                else
                    return this.Filename;
            }
        }
        private string _filename;
        private string _path;
        private DirectoryEntryTypes _fileType;
        private long _size;
        private DateTime _fileDateTime;
        private string _permission;
        /// 
        ///         ''' Identifies entry as either File or Directory
        ///         ''' 
        public enum DirectoryEntryTypes
        {
            File,
            Directory,
            Link
        }
        /// 
        ///         ''' Constructor taking a directory listing line and path
        ///         ''' 
        ///         ''' The line returned from the detailed directory list
        ///         ''' Path of the directory
        ///         ''' 
        public FTPfileInfo(string line, string path)
        {
            // parse line
            Match m = GetMatchingRegex(line);
            if (m == null)
                // failed
                throw new ApplicationException("Unable to parse line: " + line);
            else
            {
                _filename = m.Groups["name"].Value;
                _path = path;
                _permission = m.Groups["permission"].Value;
                string _dir = m.Groups["dir"].Value;
                if ((_dir != "" & (_dir == "d" || _dir == "D")))
                {
                    _fileType = DirectoryEntryTypes.Directory;
                    _size = 0; // CLng(m.Groups("size").Value)
                }
                else if ((_dir != "" & (_dir == "l" || _dir == "L")))
                {
                    _fileType = DirectoryEntryTypes.Link;
                    _size = 0; // CLng(m.Groups("size").Value)
                }
                else
                {
                    _fileType = DirectoryEntryTypes.File;
                    _size = System.Convert.ToInt64(m.Groups["size"].Value);
                }
                try
                {
                    var timestamp = m.Groups["timestamp"].Value;
                    if (timestamp.IndexOf(':') == -1)
                    {
                        _fileDateTime = DateTime.Parse(timestamp);
                    }
                    else
                    {
                        _fileDateTime = DateTime.Parse(DateTime.Now.Year + " " + timestamp);
                    }
                }
                catch
                {
                    // MsgBox("datetime err=" & Now.Year & Space(1) & "value=" & m.Groups("timestamp").Value & vbCrLf & ex.Message.ToString)
                    _fileDateTime = DateTime.Parse("1982-11-23");
                }
            }
        }
        public FTPfileInfo(string filename, string permission, string dir, int size, DateTime filetime, Boolean isdir, string path)
        {
            _filename = filename;// m.Groups["name"].Value;
            _path = path;
            _permission = permission; // m.Groups["permission"].Value;
            string _dir = dir;// m.Groups["dir"].Value;
            if (isdir == true)
            {
                _fileType = DirectoryEntryTypes.Directory;
                _size = 0; // CLng(m.Groups("size").Value)
            }
            else
            {
                _fileType = DirectoryEntryTypes.File;
                _size = size;//
            }
            _fileDateTime = filetime;
        }
        private Match GetMatchingRegex(string line)
        {
            Regex rx;
            Match m;
            for (int i = 0; i <= _ParseFormats.Length - 1; i++)
            {
                rx = new Regex(_ParseFormats[i]);
                m = rx.Match(line);
                if (m.Success)
                    return m;
            }
            return null;
        }
        /// 
        ///         ''' List of REGEX formats for different FTP server listing formats
        ///         ''' 
        ///         ''' 
        ///         ''' The first three are various UNIX/LINUX formats, fourth is for MS FTP
        ///         ''' in detailed mode and the last for MS FTP in 'DOS' mode.
        ///         ''' I wish VB.NET had support for Const arrays like C# but there you go
        ///         ''' 
        private static string[] _ParseFormats = new[] { @"(?
[\-dl])(?([\-r][\-w][\-xs]){3})\s+\d+\s+\w+\s+\w+\s+(?\d+)\s+(?\w+\s+\d+\s+\d{4})\s+(?.+)", @"(?[\-dl])(?([\-r][\-w][\-xs]){3})\s+\d+\s+\d+\s+(?\d+)\s+(?\w+\s+\d+\s+\d{4})\s+(?.+)", @"(?[\-dl])(?([\-r][\-w][\-xs]){3})\s+\d+\s+\d+\s+(?\d+)\s+(?\w+\s+\d+\s+\d{1,2}:\d{2})\s+(?.+)", @"(?[\-dl])(?([\-r][\-w][\-xs]){3})\s+\d+\s+\w+\s+\w+\s+(?\d+)\s+(?\w+\s+\d+\s+\d{1,2}:\d{2})\s+(?.+)", @"(?[\-dl])(?([\-r][\-w][\-xs]){3})(\s+)(?(\d+))(\s+)(?(\w+\s\w+))(\s+)(?(\d+))\s+(?\w+\s+\d+\s+\d{2}:\d{2})\s+(?.+)", @"(?\d{2}\-\d{2}\-\d{2}\s+\d{2}:\d{2}[Aa|Pp][mM])\s+(?\<\w+\>){0,1}(?\d+){0,1}\s+(?.+)" };
    }
}