using System.IO;
namespace Top.Api.Util
{
    /// 
    /// 文件元数据。
    /// 可以使用以下几种构造方法:
    /// 本地路径:new FileItem("C:/temp.jpg");
    /// 本地文件:new FileItem(new FileInfo("C:/temp.jpg"));
    /// 字节数组:new FileItem("abc.jpg", bytes);
    /// 输入流:new FileItem("abc.jpg", stream);
    /// 
    public class FileItem
    {
        private Contract contract;
        /// 
        /// 基于本地文件的构造器。
        /// 
        /// 本地文件
        public FileItem(FileInfo fileInfo)
        {
            this.contract = new LocalContract(fileInfo);
        }
        /// 
        /// 基于本地文件全路径的构造器。
        /// 
        /// 本地文件全路径
        public FileItem(string filePath) : this(new FileInfo(filePath))
        {
        }
        /// 
        /// 基于文件名和字节数组的构造器。
        /// 
        /// 文件名称(服务端持久化字节数组到磁盘时的文件名)
        /// 文件字节数组
        public FileItem(string fileName, byte[] content) : this(fileName, content, null)
        {
        }
        /// 
        /// 基于文件名、字节数组和媒体类型的构造器。
        /// 
        /// 文件名(服务端持久化字节数组到磁盘时的文件名)
        /// 文件字字节数组
        /// 媒体类型
        public FileItem(string fileName, byte[] content, string mimeType)
        {
            this.contract = new ByteArrayContract(fileName, content, mimeType);
        }
        /// 
        /// 基于文件名和输入流的构造器。
        /// 
        /// 文件名称(服务端持久化输入流到磁盘时的文件名)
        /// 文件输入流
        public FileItem(string fileName, Stream stream) : this(fileName, stream, null)
        {
        }
        /// 
        /// 基于文件名、输入流和媒体类型的构造器。
        /// 
        /// 文件名(服务端持久化输入流到磁盘时的文件名)
        /// 文件输入流
        /// 媒体类型
        public FileItem(string fileName, Stream stream, string mimeType)
        {
            this.contract = new StreamContract(fileName, stream, mimeType);
        }
        public bool IsValid()
        {
            return this.contract.IsValid();
        }
        public long GetFileLength()
        {
            return this.contract.GetFileLength();
        }
        public string GetFileName()
        {
            return this.contract.GetFileName();
        }
        public string GetMimeType()
        {
            return this.contract.GetMimeType();
        }
        public void Write(Stream output)
        {
            this.contract.Write(output);
        }
    }
    internal interface Contract
    {
        bool IsValid();
        string GetFileName();
        string GetMimeType();
        long GetFileLength();
        void Write(Stream output);
    }
    internal class LocalContract : Contract
    {
        private FileInfo fileInfo;
        public LocalContract(FileInfo fileInfo)
        {
            this.fileInfo = fileInfo;
        }
        public long GetFileLength()
        {
            return this.fileInfo.Length;
        }
        public string GetFileName()
        {
            return this.fileInfo.Name;
        }
        public string GetMimeType()
        {
            return Constants.CTYPE_DEFAULT;
        }
        public bool IsValid()
        {
            return this.fileInfo != null && this.fileInfo.Exists;
        }
        public void Write(Stream output)
        {
            using (BufferedStream bfs = new BufferedStream(this.fileInfo.OpenRead()))
            {
                int n = 0;
                byte[] buffer = new byte[Constants.READ_BUFFER_SIZE];
                while ((n = bfs.Read(buffer, 0, buffer.Length)) > 0)
                {
                    output.Write(buffer, 0, n);
                }
            }
        }
    }
    internal class ByteArrayContract : Contract
    {
        private string fileName;
        private byte[] content;
        private string mimeType;
        public ByteArrayContract(string fileName, byte[] content, string mimeType)
        {
            this.fileName = fileName;
            this.content = content;
            this.mimeType = mimeType;
        }
        public bool IsValid()
        {
            return this.content != null && this.fileName != null;
        }
        public long GetFileLength()
        {
            return this.content.Length;
        }
        public string GetFileName()
        {
            return this.fileName;
        }
        public string GetMimeType()
        {
            if (string.IsNullOrEmpty(this.mimeType))
            {
                return Constants.CTYPE_DEFAULT;
            }
            else
            {
                return this.mimeType;
            }
        }
        public void Write(Stream output)
        {
            output.Write(this.content, 0, this.content.Length);
        }
    }
    internal class StreamContract : Contract
    {
        private string fileName;
        private Stream stream;
        private string mimeType;
        public StreamContract(string fileName, Stream stream, string mimeType)
        {
            this.fileName = fileName;
            this.stream = stream;
            this.mimeType = mimeType;
        }
        public long GetFileLength()
        {
            return 0L;
        }
        public string GetFileName()
        {
            return this.fileName;
        }
        public string GetMimeType()
        {
            if (string.IsNullOrEmpty(mimeType))
            {
                return Constants.CTYPE_DEFAULT;
            }
            else
            {
                return this.mimeType;
            }
        }
        public bool IsValid()
        {
            return this.stream != null && this.fileName != null;
        }
        public void Write(Stream output)
        {
            using (this.stream)
            {
                int n = 0;
                byte[] buffer = new byte[Constants.READ_BUFFER_SIZE];
                while ((n = this.stream.Read(buffer, 0, buffer.Length)) > 0)
                {
                    output.Write(buffer, 0, n);
                }
            }
        }
    }
}