using System;
using System.IO;
using System.Net;
using System.Text;

namespace NcProgramManager.Cnc.Mitsubishi
{
    /// <summary>FTP client for Mitsubishi M-series CNC program transfer.</summary>
    internal sealed class MitsubishiFtpClient : IMitsubishiFtpClient
    {
        private readonly MitsubishiConnectionConfig _config;

        public MitsubishiFtpClient(MitsubishiConnectionConfig config)
        {
            _config = config ?? throw new ArgumentNullException("config");
        }

        /// <summary>Verify FTP server is reachable by listing the program directory.</summary>
        public bool Ping()
        {
            try
            {
                var req = CreateRequest(_config.ProgramDirectory, WebRequestMethods.Ftp.ListDirectory);
                using (var resp = (FtpWebResponse)req.GetResponse())
                    return resp.StatusCode == FtpStatusCode.DataAlreadyOpen
                        || resp.StatusCode == FtpStatusCode.OpeningData
                        || (int)resp.StatusCode / 100 == 2;
            }
            catch { return false; }
        }

        /// <summary>Download file from Mitsubishi to string.</summary>
        public string DownloadFile(string ncPath)
        {
            var req = CreateRequest(ncPath, WebRequestMethods.Ftp.DownloadFile);
            using (var resp = (FtpWebResponse)req.GetResponse())
            using (var reader = new StreamReader(resp.GetResponseStream(), Encoding.ASCII))
                return reader.ReadToEnd();
        }

        /// <summary>Upload string content to Mitsubishi.</summary>
        public void UploadFile(string ncPath, string content)
        {
            var req = CreateRequest(ncPath, WebRequestMethods.Ftp.UploadFile);
            byte[] data = Encoding.ASCII.GetBytes(content);
            req.ContentLength = data.Length;
            using (var stream = req.GetRequestStream())
                stream.Write(data, 0, data.Length);
            using ((FtpWebResponse)req.GetResponse()) { }
        }

        public void DeleteFile(string ncPath)
        {
            var req = CreateRequest(ncPath, WebRequestMethods.Ftp.DeleteFile);
            using ((FtpWebResponse)req.GetResponse()) { }
        }

        private FtpWebRequest CreateRequest(string path, string method)
        {
            string uri = string.Format("ftp://{0}:{1}{2}", _config.IpAddress, _config.Port, path);
            var req = (FtpWebRequest)WebRequest.Create(uri);
            req.Method = method;
            req.Credentials = new NetworkCredential(_config.Username, _config.Password);
            req.Timeout = (int)_config.RequestTimeout.TotalMilliseconds;
            req.KeepAlive = false;
            req.UseBinary = false;
            req.UsePassive = true;
            return req;
        }
    }
}
