using System;
using System.Collections.Generic;
using System.Text;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.ComTypes;
using System.Security.Cryptography;
using System.IO;
using System.Diagnostics;

namespace Sample9_PlayVideoFromMemoryStream
{
    class VirtualFileStream : IStream
    {
        private MemoryStream _MemoryStream;
        private int _Position = 0;

        public VirtualFileStream(MemoryStream MemoryStream)
        {
            _MemoryStream = MemoryStream;
        }

        #region IStream Members

        public void Read(byte[] pv, int cb, IntPtr pcbRead)
        {
            int ReadBytes;

            if (_Position < 0 || _Position > _MemoryStream.Length)
            {
                ReadBytes = 0;
            }
            else
            {
                // Lock memory stream to be able for all instances set required position within memory stream
                lock (_MemoryStream)
                {
                    _MemoryStream.Position = _Position;
                    ReadBytes = _MemoryStream.Read(pv, 0, cb);
                    _Position += ReadBytes;
                }
            }

            if (IntPtr.Zero != pcbRead)
                Marshal.WriteIntPtr(pcbRead, new IntPtr(ReadBytes));
        }

        public void Write(byte[] pv, int cb, IntPtr pcbWritten)
        {
            throw new Exception("The method or operation is not implemented.");
        }

        public void Clone(out IStream ppstm)
        {
            ppstm = new VirtualFileStream(_MemoryStream);
        }

        public void Seek(long dlibMove, int dwOrigin, IntPtr plibNewPosition)
        {
            SeekOrigin Origin = (SeekOrigin)dwOrigin;

            // Let's protect _Position: _Position might be changed by Read()
            lock (_MemoryStream)
            {
                switch (Origin)
                {
                    case SeekOrigin.Begin:
                        {
                            _Position = (int)dlibMove;
                            break;
                        }
                    case SeekOrigin.Current:
                        {
                            _Position += (int)dlibMove;
                            break;
                        }
                    case SeekOrigin.End:
                        {
                            _Position = (int)(_MemoryStream.Length + dlibMove);
                            break;
                        }
                }
            }

            if (IntPtr.Zero != plibNewPosition)
                Marshal.WriteInt64(plibNewPosition, _Position);
        }

        public void Stat(out System.Runtime.InteropServices.ComTypes.STATSTG pstatstg, int grfStatFlag)
        {
            pstatstg = new System.Runtime.InteropServices.ComTypes.STATSTG();
            pstatstg.cbSize = _MemoryStream.Length;
        }

        public void Commit(int grfCommitFlags)
        {
            throw new Exception("The method or operation is not implemented.");
        }

        public void CopyTo(IStream pstm, long cb, IntPtr pcbRead, IntPtr pcbWritten)
        {
            throw new Exception("The method or operation is not implemented.");
        }

        public void LockRegion(long libOffset, long cb, int dwLockType)
        {
            throw new Exception("The method or operation is not implemented.");
        }

        public void Revert()
        {
            throw new Exception("The method or operation is not implemented.");
        }

        public void SetSize(long libNewSize)
        {
            throw new Exception("The method or operation is not implemented.");
        }

        public void UnlockRegion(long libOffset, long cb, int dwLockType)
        {
            throw new Exception("The method or operation is not implemented.");
        }

        #endregion
    }
}
