using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Security.Cryptography;

namespace Cosmos.IL2CPU
{


    public class Elf32 : HashAlgorithm
    {
        private UInt32 hash;

        public Elf32()
        {
            Initialize();
        }

        public override void Initialize()
        {
            hash = 0;
        }

        protected override void HashCore(byte[] buffer, int start, int length)
        {
            hash = CalculateHash(hash, buffer, start, length);
        }

        protected override byte[] HashFinal()
        {
            byte[] hashBuffer = UInt32ToBigEndianBytes(hash);
            this.HashValue = hashBuffer;
            return hashBuffer;
        }

        public override int HashSize
        {
            get { return 32; }
        }

        public static UInt32 Compute(UInt32 polynomial, UInt32 seed, byte[] buffer)
        {
            return CalculateHash(seed, buffer, 0, buffer.Length);
        }

        private static UInt32 CalculateHash(UInt32 seed, byte[] buffer, int start, int size)
        {
            UInt32 hash = seed;

            for (int i = start; i < size; i++)
                unchecked
                {
                    hash = (hash << 4) + buffer[i];
                    UInt32 work = (hash & 0xf0000000);
                    if (work != 0)
                        hash ^= (work >> 24);
                    hash &= ~work;
                }
            return hash;
        }

        private byte[] UInt32ToBigEndianBytes(UInt32 x)
        {
            return new byte[] {
			(byte)((x >> 24) & 0xff),
			(byte)((x >> 16) & 0xff),
			(byte)((x >> 8) & 0xff),
			(byte)(x & 0xff)
		};
        }
    }



    public class Elf64 : HashAlgorithm
    {
        private UInt64 hash;

        public Elf64()
        {
            Initialize();
        }

        public override void Initialize()
        {
            hash = 0;
        }

        protected override void HashCore(byte[] buffer, int start, int length)
        {
            hash = CalculateHash(hash, buffer, start, length);
        }

        protected override byte[] HashFinal()
        {
            byte[] hashBuffer = UInt64ToBigEndianBytes(hash);
            this.HashValue = hashBuffer;
            return hashBuffer;
        }

        public override int HashSize
        {
            get { return 32; }
        }

        public static UInt64 Compute(UInt64 polynomial, UInt64 seed, byte[] buffer)
        {
            return CalculateHash(seed, buffer, 0, buffer.Length);
        }

        //not sure if this is valid.
        private static UInt64 CalculateHash(UInt64 seed, byte[] buffer, int start, int size)
        {
            UInt64 hash = seed;

            for (int i = start; i < size; i++)
                unchecked
                {
                    hash = (hash << 4) + buffer[i];
                    UInt64 work = (hash & 0xf000000000000000L);
                    if (work != 0)
                        hash ^= (work >> 56);
                    hash &= ~work;
                }
            return hash;
        }

        private byte[] UInt64ToBigEndianBytes(UInt64 x)
        {
            return new byte[] 
            {
            (byte)((x >> 56) & 0xff),
            (byte)((x >> 48) & 0xff),
            (byte)((x >> 40) & 0xff),
            (byte)((x >> 32) & 0xff),
            (byte)((x >> 24) & 0xff),
			(byte)((x >> 16) & 0xff),
			(byte)((x >> 8) & 0xff),
			(byte)(x & 0xff)
		};
        }
    }

}
