using System;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Security.Cryptography;
using System.Text;

namespace General
{
    enum Endianness
    {
        LITTLE_ENDIAN,
        BIG_ENDIAN,
        UNCHANGED
    };

    class Tools
    {
        public Tools(bool bigEndain)
        {
            BigEndain = bigEndain;
        }
        public bool BigEndain = false;

	    public static byte[] bmp    = Encoding.ASCII.GetBytes("BM");     // BMP
	    public static byte[] gif    = Encoding.ASCII.GetBytes("GIF");    // GIF
	    public static byte[] png    = new byte[] { 137, 80, 78, 71 };    // PNG
	    public static byte[] tiff   = new byte[] { 73, 73, 42 };         // TIFF
	    public static byte[] tiff2  = new byte[] { 77, 77, 42 };         // TIFF
 	    public static byte[] jpeg   = new byte[] { 255, 216, 255 };      // jpeg
        public static Random rng = new Random(Guid.NewGuid().GetHashCode());

        public static void WriteStringToStream(Stream s, String str)
        {
            Byte[] bytes = Encoding.UTF8.GetBytes(str);
            s.Write(bytes, 0x00, bytes.Length);
        }
        public static void WriteUtf16StringToStream(Stream s, String str)
        {
            Byte[] bytes = Encoding.Unicode.GetBytes(str);
            s.Write(bytes, 0x00, bytes.Length);
        }
        public static MemoryStream ByteToStream(byte[] Array)
        {
            MemoryStream ms = new MemoryStream();
            ms.Write(Array, 0x00, Array.Length);
            ms.Seek(0, SeekOrigin.Begin);
            return ms;
        }

        public static byte[] StreamToByte(Stream stream)
        {
            int StreamLen = (int)stream.Length;
            byte[] Bytes = new byte[StreamLen];
            stream.Seek(0, SeekOrigin.Begin);
            stream.Read(Bytes, 0x00, StreamLen);
            return Bytes;
        }

        public static string GenerateReplacePattern()
        {
            byte[] RandomNumber = new byte[0x20];
            rng.NextBytes(RandomNumber);
            return "{{" + BitConverter.ToString(RandomNumber).Replace("-", "") + "}}";
        }
        public static string GetFileExtension(byte[] Bytes)
        {
            if (bmp.SequenceEqual(Bytes.Take(bmp.Length)))
            {
                return ".bmp";
            }
            else if (gif.SequenceEqual(Bytes.Take(gif.Length)))
            {
                return ".gif";
            }
            else if (png.SequenceEqual(Bytes.Take(png.Length)))
            {
                return ".png";
            }
            else if (tiff.SequenceEqual(Bytes.Take(tiff.Length)))
            {
                return ".tiff";
            }
            else if (tiff2.SequenceEqual(Bytes.Take(tiff2.Length)))
            {
                return ".tiff";
            }
            else if (jpeg.SequenceEqual(Bytes.Take(jpeg.Length)))
            {
                return ".jpg";
            }
            else if (IsZlib(Bytes))
            {
                return ".z";
            }
            else if (IsRcf(Bytes))
            {
                return ".rcs";
            }
            else if (IsDDS(Bytes))
            {
                return ".dds";
            }
            else if (IsVAG(Bytes))
            {
                return ".vag";
            }
            else if (IsGim(Bytes))
            {
                return ".gim";
            }
            else if (!HasBinaryContent(Encoding.UTF8.GetString(Bytes)))
            {
                return ".txt";
            }
            else
            {
                return ".bin";
            }
        }

        public static bool IsVAG(byte[] Bytes)
        {
            MemoryStream Data = ByteToStream(Bytes);
            String header = ReadString(Data, 4);
            if (header.StartsWith("VAG"))
            {
                return true;
            }
            else
            {
                return false;
            }
        }

        public static bool IsDDS(byte[] Bytes)
        {
            MemoryStream Data = ByteToStream(Bytes);
            String header = ReadString(Data, 4);
            if (header.StartsWith("DDS"))
            {
                return true;
            }
            else
            {
                return false;
            }
        }


        public static bool IsRcf(byte[] Bytes)
        {
            MemoryStream Data = ByteToStream(Bytes);
            String header = ReadString(Data, 5);
            if (header.StartsWith("RCSF"))
            {
                return true;
            }
            else
            {
                return false;
            }
        }

        public static bool IsGim(byte[] Bytes)
        {
            MemoryStream Data = ByteToStream(Bytes);
            String header = ReadString(Data, 4);
            if (header.StartsWith("MIG") || header.EndsWith("GIM"))
            {
                return true;
            }
            else
            {
                return false;
            }
        }

        public static bool IsZlib(byte[] Bytes)
        {
            if (Bytes[0] == 0x78)
            {
                if (Bytes[1] == 0x01)
                    return true;
                if (Bytes[1] == 0x9C)
                    return true;
                if (Bytes[1] == 0xDA)
                    return true;
            }
            return false;
        }



        public static Bitmap GetBitmap(byte[] BitmapBytes)
        {
            MemoryStream ms = ByteToStream(BitmapBytes);
            Bitmap bmp = new Bitmap(ms);
            ms.Dispose();
            return bmp;
        }

        public static String ReadStringAt(Stream ms, int location)
        {
            long ogPos = ms.Position;
            ms.Seek(location, SeekOrigin.Begin);
            String str = ReadString(ms);
            ms.Seek(ogPos, SeekOrigin.Begin);
            return str;
        }

        public static int ReadLittleEndainIntAt(Stream ms, int location)
        {
            long ogPos = ms.Position;
            ms.Seek(location, SeekOrigin.Begin);
            int i = ReadLittleEndainInt(ms);
            ms.Seek(ogPos, SeekOrigin.Begin);
            return i;
        }

        public int ReadIntAt(Stream ms, int location)
        {
            long ogPos = ms.Position;
            ms.Seek(location, SeekOrigin.Begin);
            int i = ReadInt32(ms);
            ms.Seek(ogPos, SeekOrigin.Begin);
            return i;
        }
        public static bool HasBinaryContent(string content)
        {
            return content.Any(ch => char.IsControl(ch) && ch != '\r' && ch != '\n');
        }


        public void WriteInt32(Stream ms, int val)
        {
            if (BigEndain)
                WriteBigEndainInt(ms, val);
            else
                WriteLittleEndainInt(ms, val);
        }

        public void WriteSingle(Stream ms, Single val)
        {
            if (BigEndain)
                WriteBigEndainSingle(ms, val);
            else
                WriteLittleEndainSingle(ms, val);
        }

        public int ReadInt32(Stream ms)
        {
            if (BigEndain)
                return ReadBigEndainInt(ms);
            else
                return ReadLittleEndainInt(ms);
        }

        public Single ReadSingle(Stream ms)
        {
            if (BigEndain)
                return ReadBigEndainSingle(ms);
            else
                return ReadLittleEndainSingle(ms);
        }

        public static int ReadBigEndainIntAt(Stream ms, int location)
        {
            long ogPos = ms.Position;
            ms.Seek(location, SeekOrigin.Begin);
            int i = ReadBigEndainInt(ms);
            ms.Seek(ogPos, SeekOrigin.Begin);
            return i;
        }
        public static Single ReadBigEndainSingle(Stream ms)
        {
            byte[] SingleBytes = new byte[4];
            ms.Read(SingleBytes, 0x00, 4);
            SingleBytes = SingleBytes.Reverse().ToArray();
            Single val = BitConverter.ToSingle(SingleBytes, 0x00);
            return val;
        }
        public static Single ReadLittleEndainSingle(Stream ms)
        {
            byte[] SingleBytes = new byte[4];
            ms.Read(SingleBytes, 0x00, 4);
            SingleBytes = SingleBytes.ToArray();
            Single val = BitConverter.ToSingle(SingleBytes, 0x00);
            return val;
        }
        public static void WriteLittleEndainSingle(Stream ms, Single val)
        {
            byte[] SingleBytes = BitConverter.GetBytes(val);
            ms.Write(SingleBytes, 0x00, SingleBytes.Length);
        }
        public static void WriteBigEndainSingle(Stream ms, Single val)
        {
            byte[] SingleBytes = BitConverter.GetBytes(val);
            SingleBytes = SingleBytes.Reverse().ToArray();
            ms.Write(SingleBytes, 0x00, SingleBytes.Length);
        }

        public static void WriteLittleEndainInt(Stream ms, int val)
        {
            byte[] IntBytes = BitConverter.GetBytes(val);
            ms.Write(IntBytes, 0x00, IntBytes.Length);
        }
        public static void WriteBigEndainInt(Stream ms, int val)
        {
            byte[] IntBytes = BitConverter.GetBytes(val);
            IntBytes = IntBytes.Reverse().ToArray();
            ms.Write(IntBytes, 0x00, IntBytes.Length);
        }

        public static int ReadLittleEndainInt(Stream ms)
        {
            byte[] IntBytes = new byte[4];
            ms.Read(IntBytes, 0x00, 4);
            IntBytes = IntBytes.ToArray();
            int i = BitConverter.ToInt32(IntBytes, 0x00);
            return i;
        }
        public static int ReadBigEndainInt(Stream ms)
        {
            byte[] IntBytes = new byte[4];
            ms.Read(IntBytes, 0x00, 4);
            IntBytes = IntBytes.Reverse().ToArray();
            int i = BitConverter.ToInt32(IntBytes, 0x00);
            return i;
        }
        public static String GetRootFolder(string path)
        {
            while (true)
            {
                string temp = Path.GetDirectoryName(path);
                if (String.IsNullOrEmpty(temp))
                    break;
                path = temp;
            }
            return path;
        }

        public static String GenerateHash(byte[] Data)
        {
            SHA1 sha = SHA1.Create();
            byte[] ShaBytes = sha.ComputeHash(Data);
            return BitConverter.ToString(ShaBytes).Replace("-", "").ToUpper();
        }

        public static string GenerateShortHash(byte[] Data)
        {
            SHA1 sha = SHA1.Create();
            byte[] ShaBytes = sha.ComputeHash(Data);
            byte[] First4 = new byte[0x4];
            Array.Copy(ShaBytes, 0, First4, 0, First4.Length);
            First4 = First4.Reverse().ToArray();
            return BitConverter.ToInt32(First4, 0).ToString("X8").ToLowerInvariant();
        }

        public static String ReadString(Stream ms, int limit = -1)
        {
            int i = 0xFF;
            int counter = 0;

            MemoryStream StringStream = new MemoryStream();

            do
            {
                i = ms.ReadByte();
                if (i == 0 || counter == limit)
                    break;
                StringStream.WriteByte((byte)i);
                counter += 1;
            }
            while (true);

            byte[] StringData = StringStream.ToArray();

            String str = Encoding.UTF8.GetString(StringData);

            return str;

        }
    }

}
