using System;

namespace Community.CsharpSqlite
{
	public partial class Sqlite3
	{
		/*
		*************************************************************************
		**
		** This file contains low-level memory & pool allocation drivers
		**
		** This file contains implementations of the low-level memory allocation
		** routines specified in the sqlite3_mem_methods object.
		**
		*************************************************************************
		*/

		/*
		** Like malloc(), but remember the size of the allocation
		** so that we can find it later using sqlite3MemSize().
		**
		** For this low-level routine, we are guaranteed that nByte>0 because
		** cases of nByte<=0 will be intercepted and dealt with by higher level
		** routines.
		*/
#if SQLITE_POOL_MEM
#if TRUE
    static byte[] sqlite3MemMalloc( u32 nByte )
    {
      return new byte[nByte];
    }
    static byte[] sqlite3MemMalloc( int nByte )
    {
      return new byte[nByte];
    }
    static int[] sqlite3MemMallocInt( int nInt )
    {
      return new int[nInt];
    }
#else
    static byte[] sqlite3MemMalloc(int nByte)
    {
      byte[] pByte = null;
      int savej = -1;
      int BestSize = int.MaxValue;
      if (nByte > mem0.aByteSize[0])
      {
        int i;
        for (i = 0; i < mem0.aByteSize.Length - 1; i++) if (nByte <= mem0.aByteSize[i]) break;
        mem0.mr_Byte++;
        for (int j = 0; j <= mem0.aByte_used[i]; j++)
          if (mem0.aByte[i][j] != null)
          {
            if (mem0.aByte[i][j].Length == nByte)
            {
              pByte = mem0.aByte[i][j]; mem0.aByte[i][j] = null; mem0.cf_Byte++;
              if (j == mem0.aByte_used[i]) mem0.aByte_used[i]--;
              break;
            }
            if (mem0.aByte[i][j].Length > nByte)
            {
              if (mem0.aByte[i][j].Length < BestSize)
              {
                BestSize = mem0.aByte[i][j].Length;
                savej = j;
              }
            }
          }
        if (pByte == null && savej >= 0)
        {
          pByte = mem0.aByte[i][savej]; mem0.aByte[i][savej] = null; mem0.cf_Byte++;
          Array.Resize(ref pByte, nByte);
        }
        if (mem0.aByte_used[i] >=0 && mem0.aByte[i][mem0.aByte_used[i]] == null) mem0.aByte_used[i]--;
      }
      if (pByte == null) pByte = new byte[nByte];
      return pByte;
    }
    static int[] sqlite3MemMallocInt(int nInt)
    {
      int[] pInt = null;
      int savei = -1;
      int BestSize = int.MaxValue;
      if (nInt >=10)
      {
        mem0.mr_Int++;
        int i;
        for (i = 0; i < mem0.hw_Int; i++)
          if (mem0.aInt[i] != null)
          {
            if (mem0.aInt[i].Length == nInt)
            {
              pInt = mem0.aInt[i]; mem0.aInt[i] = null; mem0.cf_Int++; break;
            }
            if (mem0.aInt[i].Length > nInt)
            {
              if (mem0.aInt[i].Length < BestSize)
              {
                BestSize = mem0.aInt[i].Length;
                savei = i;
              }
            }
          }
        if (pInt == null && savei >= 0)
        {
          pInt = mem0.aInt[savei]; mem0.aInt[savei] = null; mem0.cf_Int++;
        }
      }
      if (pInt == null) pInt = new int[nInt];
      return pInt;
    }
#endif

    static Mem sqlite3MemMallocMem( Mem dummy )
    {
      Mem pMem;
      mem0.msMem.alloc++;
      if ( mem0.msMem.next > 0 && mem0.aMem[mem0.msMem.next] != null )
      {
        pMem = mem0.aMem[mem0.msMem.next];
        mem0.aMem[mem0.msMem.next] = null;
        mem0.msMem.cached++;
        mem0.msMem.next--;
      }
      else
        pMem = new Mem();
      return pMem;
    }
    static BtCursor sqlite3MemMallocBtCursor( BtCursor dummy )
    {
      BtCursor pBtCursor;
      mem0.msBtCursor.alloc++;
      if ( mem0.msBtCursor.next > 0 && mem0.aBtCursor[mem0.msBtCursor.next] != null )
      {
        pBtCursor = mem0.aBtCursor[mem0.msBtCursor.next];
        Debug.Assert( pBtCursor.pNext == null && pBtCursor.pPrev == null && pBtCursor.wrFlag == 0 );
        mem0.aBtCursor[mem0.msBtCursor.next] = null;
        mem0.msBtCursor.cached++;
        mem0.msBtCursor.next--;
      }
      else
        pBtCursor = new BtCursor();
      return pBtCursor;
    }
#endif
		/*
    ** Free memory.
    */

		// -- overloads ---------------------------------------
		private static void sqlite3MemFree<T>(ref T x) where T : class
		{
			x = null;
		}

		private static void sqlite3MemFree(ref string x)
		{
			x = null;
		}

		//

		/*
		** Like free() but works for allocations obtained from sqlite3MemMalloc()
		** or sqlite3MemRealloc().
		**
		** For this low-level routine, we already know that pPrior!=0 since
		** cases where pPrior==0 will have been intecepted and dealt with
		** by higher-level routines.
		*/
#if SQLITE_POOL_MEM
#if TRUE
    static void sqlite3MemFreeInt( ref int[] pPrior )
    {
      pPrior = null;
    }
#else
    static void sqlite3MemFree(ref byte[] pPrior)
    {
      if (pPrior == null) return;
      if (pPrior.Length > mem0.aByteSize[0])
      {
        int savej = -1;
        int Smallest = int.MaxValue;
        int i;
        for (i = 0; i < mem0.aByteSize.Length - 1; i++) if (pPrior.Length <= mem0.aByteSize[i]) break;
#if DEBUG
for (int j = 0; j < mem0.aByte[i].Length; j++) if (mem0.aByte[i][j] != null && mem0.aByte[i][j] == pPrior) Debugger.Break();
#endif
        mem0.mf_Byte++;
        for (int j = 0; j <= mem0.aByte_used[i]; j++)
        {
          if (mem0.aByte[i][j] == null)
          {
            mem0.aByte[i][j] = pPrior;
            pPrior = null;
            return;
          }
          if (mem0.aByte[i][j].Length < Smallest)
          {
            savej = j;
            Smallest = mem0.aByte[i][j].Length;
          }
        }

        if (mem0.aByte_used[i] < mem0.aByte[i].Length - 1) mem0.aByte[i][++mem0.aByte_used[i]] = pPrior;
        else if (savej >= 0) mem0.aByte[i][savej] = pPrior;
      }
      pPrior = null;
      return;
    }
    static void sqlite3MemFreeInt(ref int[] pPrior)
    {
      if (pPrior == null) return;
      if (pPrior.Length >= 10)
      {
        int savei = -1;
        int Smallest = int.MaxValue;
#if DEBUG
for (int i = 0; i < mem0.aInt.Length; i++) if (mem0.aInt[i] != null && mem0.aInt[i] == pPrior) Debugger.Break();
#endif
        mem0.mf_Int++;
        for (int i = 0; i < mem0.aInt.Length; i++)
        {
          if (mem0.aInt[i] == null)
          {
            mem0.aInt[i] = pPrior;
            pPrior = null;
            return;
          }
          if (mem0.aInt[i].Length < Smallest)
          {
            savei = i;
            Smallest = mem0.aInt[i].Length;
          }
        }
        if (savei >= 0) mem0.aInt[savei] = pPrior;
      }
      pPrior = null;
      return;
    }
#endif
    static void sqlite3MemFreeMem( ref Mem pPrior )
    {
      if ( pPrior == null )
        return;
#if FALSE && DEBUG
for (int i = mem0.msMem.next - 1; i >= 0; i--) if (mem0.aMem[i] != null && mem0.aMem[i] == pPrior) Debugger.Break();
#endif
      mem0.msMem.dealloc++;
      if ( mem0.msMem.next < mem0.aMem.Length - 1 )
      {
        pPrior.db = null;
        pPrior._SumCtx = null;
        pPrior._MD5Context = null;
        pPrior._SubProgram = null;
        pPrior.flags = MEM_Null;
        pPrior.r = 0;
        pPrior.u.i = 0;
        pPrior.n = 0;
        if ( pPrior.zBLOB != null )
          sqlite3MemFree( ref pPrior.zBLOB );
        mem0.aMem[++mem0.msMem.next] = pPrior;
        if ( mem0.msMem.next > mem0.msMem.max )
          mem0.msMem.max = mem0.msMem.next;
      }
      //Array.Resize( ref mem0.aMem, (int)(mem0.hw_Mem * 1.5 + 1 ));
      //mem0.aMem[mem0.hw_Mem] = pPrior;
      //mem0.hw_Mem = mem0.aMem.Length;
      pPrior = null;
      return;
    }
    static void sqlite3MemFreeBtCursor( ref BtCursor pPrior )
    {
      if ( pPrior == null )
        return;
#if FALSE && DEBUG
      for ( int i = mem0.msBtCursor.next - 1; i >= 0; i-- ) if ( mem0.aBtCursor[i] != null && mem0.aBtCursor[i] == pPrior ) Debugger.Break();
#endif
      mem0.msBtCursor.dealloc++;
      if ( mem0.msBtCursor.next < mem0.aBtCursor.Length - 1 )
      {
        mem0.aBtCursor[++mem0.msBtCursor.next] = pPrior;
        if ( mem0.msBtCursor.next > mem0.msBtCursor.max )
          mem0.msBtCursor.max = mem0.msBtCursor.next;
      }
      //Array.Resize( ref mem0.aBtCursor, (int)(mem0.hw_BtCursor * 1.5 + 1 ));
      //mem0.aBtCursor[mem0.hw_BtCursor] = pPrior;
      //mem0.hw_BtCursor = mem0.aBtCursor.Length;
      pPrior = null;
      return;
    }
    /*
    ** Like realloc().  Resize an allocation previously obtained from
    ** sqlite3MemMalloc().
    **
    ** For this low-level interface, we know that pPrior!=0.  Cases where
    ** pPrior==0 while have been intercepted by higher-level routine and
    ** redirected to xMalloc.  Similarly, we know that nByte>0 becauses
    ** cases where nByte<=0 will have been intercepted by higher-level
    ** routines and redirected to xFree.
    */
    static byte[] sqlite3MemRealloc( ref byte[] pPrior, int nByte )
    {
      //  sqlite3_int64 p = (sqlite3_int64*)pPrior;
      //  Debug.Assert(pPrior!=0 && nByte>0 );
      //  nByte = ROUND8( nByte );
      //  p = (sqlite3_int64*)pPrior;
      //  p--;
      //  p = realloc(p, nByte+8 );
      //  if( p ){
      //    p[0] = nByte;
      //    p++;
      //  }
      //  return (void*)p;
      Array.Resize( ref pPrior, nByte );
      return pPrior;
    }
#else
		/*
** No-op versions of all memory allocation routines
*/

		private static byte[] sqlite3MemMalloc(int nByte)
		{
			return new byte[nByte];
		}

		private static int[] sqlite3MemMallocInt(int nInt)
		{
			return new int[nInt];
		}

		private static Mem sqlite3MemMallocMem(Mem pMem)
		{
			return new Mem();
		}

		private static void sqlite3MemFree(ref byte[] pPrior)
		{
			pPrior = null;
		}

		private static void sqlite3MemFreeInt(ref int[] pPrior)
		{
			pPrior = null;
		}

		private static void sqlite3MemFreeMem(ref Mem pPrior)
		{
			pPrior = null;
		}

		private static int sqlite3MemInit()
		{
			return SQLITE_OK;
		}

		private static void sqlite3MemShutdown()
		{
		}

		private static BtCursor sqlite3MemMallocBtCursor(BtCursor dummy)
		{
			return new BtCursor();
		}

		private static void sqlite3MemFreeBtCursor(ref BtCursor pPrior)
		{
			pPrior = null;
		}

#endif

		private static byte[] sqlite3MemRealloc(byte[] pPrior, int nByte)
		{
			Array.Resize(ref pPrior, nByte);
			return pPrior;
		}

		/*
		** Report the allocated size of a prior return from xMalloc()
		** or xRealloc().
		*/

		private static int sqlite3MemSize(byte[] pPrior)
		{
			//  sqlite3_int64 p;
			//  if( pPrior==0 ) return 0;
			//  p = (sqlite3_int64*)pPrior;
			//  p--;
			//  return p[0];
			return pPrior == null ? 0 : (int)pPrior.Length;
		}

		/*
		** Round up a request size to the next valid allocation size.
		*/

		private static int sqlite3MemRoundup(int n)
		{
			return n;//      ROUND8( n );
		}

		/*
		** Initialize this module.
		*/

		private static int sqlite3MemInit(object NotUsed)
		{
			UNUSED_PARAMETER(NotUsed);
			if (!sqlite3GlobalConfig.bMemstat)
			{
				/* If memory status is enabled, then the malloc.c wrapper will already
				** hold the STATIC_MEM mutex when the routines here are invoked. */
				mem0.mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MEM);
			}
			return SQLITE_OK;
		}

		/*
		** Deinitialize this module.
		*/

		private static void sqlite3MemShutdown(object NotUsed)
		{
			UNUSED_PARAMETER(NotUsed);
			return;
		}

		/*
		** This routine is the only routine in this file with external linkage.
		**
		** Populate the low-level memory allocation function pointers in
		** sqlite3GlobalConfig.m with pointers to the routines in this file.
		*/

		private static void sqlite3MemSetDefault()
		{
			sqlite3_mem_methods defaultMethods = new sqlite3_mem_methods(
			sqlite3MemMalloc,
			sqlite3MemMallocInt,
			sqlite3MemMallocMem,
			sqlite3MemFree,
			sqlite3MemFreeInt,
			sqlite3MemFreeMem,
			sqlite3MemRealloc,
			sqlite3MemSize,
			sqlite3MemRoundup,
			(dxMemInit)sqlite3MemInit,
			(dxMemShutdown)sqlite3MemShutdown,
			0
			);
			sqlite3_config(SQLITE_CONFIG_MALLOC, defaultMethods);
		}

		private static void sqlite3DbFree(sqlite3 db, ref int[] pPrior)
		{
			if (pPrior != null)
				sqlite3MemFreeInt(ref pPrior);
		}

		private static void sqlite3DbFree(sqlite3 db, ref Mem pPrior)
		{
			if (pPrior != null)
				sqlite3MemFreeMem(ref pPrior);
		}

		private static void sqlite3DbFree(sqlite3 db, ref Mem[] pPrior)
		{
			if (pPrior != null)
				for (int i = 0; i < pPrior.Length; i++)
					sqlite3MemFreeMem(ref pPrior[i]);
		}

		private static void sqlite3DbFree<T>(sqlite3 db, ref T pT) where T : class
		{
		}

		private static void sqlite3DbFree(sqlite3 db, ref string pString)
		{
		}
	}
}