using System;
using System.Collections.Generic;
using System.Text;
using System.IO;

using AccessSpeed = nft.framework.FileAccessSpeed;

namespace nft.framework
{
    public enum FileAccessSpeed
    {
        Fast, // Ordinaly local file (stored as is).
        Slow, // Compressed local file (ZIP), , or Stored in a bit slow device.
        VerySlow // Network remote file, or sometimes failed to open and require reload.
    }

    public interface IFileSource
    {
        /// <summary>
        /// Open File as Stream
        /// </summary>
        /// <returns></returns>
        Stream OpenRead();

        AccessSpeed AccessSpeed { get; }

        /// <summary>
        /// File offset path. Must be identical and consist of 
        /// characters available for offset path, in oredr to create cache.
        /// </summary>
        string Uri { get; }

        /// <summary>
        /// Reffered when cache is latest or not. Negative value will force update cache.
        /// </summary>
        long Timestamp { get; }
    }

    public abstract class FileSource : IFileSource
    {
        public abstract string Uri { get; }

        public abstract Stream OpenRead();

        public override bool Equals(object obj) {
            IFileSource iref = obj as IFileSource;
            if (iref != null) {
                return Uri.Equals(iref.Uri);
            } else {
                return false;
            }
        }

        public override int GetHashCode() {
            return Uri.GetHashCode();
        }

        [Obsolete("non blocking method is desired.")]
        public virtual void CopyToLocal(string path) {
            using (Stream s_in = OpenRead()) {
                using (FileStream s_out = new FileStream(path, FileMode.Create, FileAccess.Write)) {
                    int size = 4096;
                    byte[] buffer = new byte[size];
                    int numBytes;
                    while ((numBytes = s_in.Read(buffer, 0, size)) > 0) {
                        s_out.Write(buffer, 0, numBytes);
                    }
                }
            }
        }

        public abstract AccessSpeed AccessSpeed { get; }

        public abstract long Timestamp { get; }
    }

    public class LocalFile : FileSource, IFileSource
    {
        protected string idpath;
        protected string fullpath;
        public LocalFile(string path) {
            this.fullpath = Path.GetFullPath(path);
            this.idpath = new Uri(fullpath).AbsoluteUri;
        }

        public LocalFile(string parent_path, string offset_path) {
            Char c = offset_path[0];
            if (c == '/' || c == '\\') {
                this.idpath = offset_path.Substring(1);
            } else {
                this.idpath = offset_path;
            }
            this.fullpath = Path.Combine(parent_path, this.idpath);
        }

        public override Stream OpenRead() {
            return new FileStream(fullpath, FileMode.Open, FileAccess.Read);
        }

        public override AccessSpeed AccessSpeed {
            get { return AccessSpeed.Fast; }
        }

        public override string Uri {
            get { return idpath; }
        }

        public string AbsolutePath {
            get { return fullpath; }
        }

        public override long Timestamp {
            get { 
                FileInfo info =new FileInfo(AbsolutePath);
                return info.LastAccessTime.Ticks;
            }
        }
    }
}
