

//#ifdef HAVE_CONFIG_H
#include "config.h"
//#endif

#include "ssc_mode.h"
#include "ssc_cwrs.h"
#include "ssc_macro.h"

#include "rc_code.h"
#include "ssc_pulsealloc.h"


extern short *SSC_restricted_local;

static const unsigned char LOG2_FRAC_TABLE[24] = {
0x00,0x08,0x0d,0x10,0x13,0x15,0x17,0x18,0x1a,0x1b,
0x1c,0x1d,0x1e,0x1f,0x20,0x20,0x21,0x22,0x22,0x23,
0x24,0x24,0x25,0x25
};



#define ALLOC_STEPS 6


static SSC_INLINE int cal_bitsTopulses(const AUDIOMode *m, short end, int skip_start,
	const int *bits1, const int *bits2, const int *thresh, const short *cap, int total, int *_balance,
	int skip_rsv, int *intensity, int intensity_rsv, int *dual_stereo, int dual_stereo_rsv, short *bits,
	short *ebits, short *fine_priority,ec_ctx *ec)

{
   int psum;
   int lo, hi;
   int i, j;
   int logM;
   int blnc;
   int lft;
   int allo_f;
   int coeffp;
   int done;
   int Bands_c = -1;

   allo_f = 0x10; 


   lo = 0x0;
   hi = 64;
   i = 0x0;
   while(i<=5)
   {
      int mid = (lo+hi)>>1;
      psum = 0;
      done = 0;

	  for (j=end;j-->0;)
      {
         int tamp = bits1[j] + (SSC_MULT16x16(mid, bits2[j])>>6);

         if (done || (tamp >= thresh[j]))
         {
            done = 1;
			psum += (tamp < cap[j]) ? tamp : cap[j];
         } else {
			psum += (allo_f < (tamp + 1)) ? allo_f : 0;
         }
      }
	  if (psum <= total)
		  lo = mid;
	  else
		  hi = mid;

	  i++;
   }
   psum = 0x0;
   done = 0x0;

   for (j = end-1; j>=0;j--)
   {
      int tamp = bits1[j] + (SSC_MULT16x16(lo, bits2[j])>>6);

      if (tamp < thresh[j] && !done)
      {
		  tamp = (allo_f > tamp) ? 0 : allo_f;
      } else
         done = 1;

	  tamp = (tamp < cap[j]) ? tamp : cap[j];
	  psum += tamp;
      bits[j] = (short)tamp;
   }

   Bands_c = end;
   while (1)
   {
      int band_width;
      int band_bits;
      int rem;
      j = Bands_c-1;

	  if ((j-skip_start) <= 0)
      {
         total += skip_rsv;
		 break;
      }

/////////////// always j>0  ////////////////////////////
	  band_width = m->eBands[Bands_c];
	  band_bits = m->eBands[j];

      lft = total-psum;
	  coeffp = lft / band_width;
	  lft -= SSC_MULT16x16(band_width, coeffp);

	  band_width = band_width - band_bits;
	  rem = ((lft - band_bits) > 0) ? (lft - band_bits) : 0;
      band_bits = (int)(bits[j] + SSC_MULT16x16(coeffp, band_width) + rem);

      if (band_bits >= IMAX(thresh[j], allo_f+8))
      {
		  if (rc_decode_logp_bit(ec, 1)) {
			  break;
		  }
         psum = psum + 8;
         band_bits = band_bits - 8;
      }
      psum -= bits[j]+intensity_rsv;
    
	  bits[j] = 0;
	  if ((allo_f-band_bits) <= 0)
      {
         psum += allo_f;
         bits[j] = allo_f;
      }

#ifndef HW_OPTIMIZATION6	  
	  if (intensity_rsv > 0)
	  {
		  intensity_rsv = LOG2_FRAC_TABLE[j];
	  }
#else
	  intensity_rsv = LOG2_FRAC_TABLE[j];
#endif

	  psum += intensity_rsv;
	  Bands_c--;
   }

   *intensity = (intensity_rsv > 0) ? rc_decode_uint(ec, Bands_c + 1) : 0;



   if (*intensity <= 0)
   {
      total += dual_stereo_rsv;
      dual_stereo_rsv = 0;
   }

   *dual_stereo = (dual_stereo_rsv > 0) ? rc_decode_logp_bit(ec, 1) : 0;
   lft = total-psum;

   {
	   int tamp = m->eBands[Bands_c];
	   coeffp = lft / tamp;
	   lft -= SSC_MULT16x16(tamp, coeffp);
   }
  

   blnc = 0;
   logM = 0x18;

   //for (j=0;j<Bands_c;j++)
   j = 0;
   while(j< Bands_c)
   {
	  int offset = m->eBands[j];
	  int NClogN = m->eBands[j + 1];
      int N0, N;
      int excess, bit, den;

	  int tamp = (lft < (NClogN - offset)) ? (int)lft : (int)(NClogN - offset);
//#if 0
#ifdef VC_PROJ
	  bits[j] += ((int)coeffp*(NClogN - offset));
#else
	  bits[j] = AE_MULA16S_scalar(bits[j], coeffp, NClogN - offset);
#endif
	  lft -= tamp;
	  bits[j] += tamp;  
    
      N0 = NClogN - offset;
	  N = N0*8;

	  bit = (int)bits[j]+blnc;
	  tamp = bit - cap[j];
	  excess = (tamp > 0) ? tamp : 0;
	  bits[j] = bit-excess;


	  den=((N<<1)+ ((!*dual_stereo && j<*intensity) ? 1 : 0));
	  NClogN = SSC_MULT16x16(den, (m->logN[j] + logM));


//#if 0
#ifdef VC_PROJ
	 offset = (NClogN>>1)-den*21;
#else
	 offset = AE_MULS16S_scalar((NClogN>>1), den, 21);
#endif
	 tamp = bits[j];
	 if (tamp + offset < den<<4)
		offset += NClogN>>2;
	 else if (tamp + offset < den*24)
		offset += NClogN>>3;

	 ebits[j] = IMAX(0, (tamp + offset + (den<<2)) / (den<<3));


	 if ((ebits[j]<<1) > (tamp >>3))
		ebits[j] = tamp >> 4;

	 ebits[j] = (ebits[j] < 8) ? ebits[j] : 8;
	 fine_priority[j] = SSC_MULT16x16(ebits[j], (den<<3)) >= tamp +offset;

	 bits[j] = bits[j] - (ebits[j] << 4);
      if(excess > 0)
      {
		 int tmp_ex = (excess >> 4) < (8 - ebits[j]) ? (excess >> 4) : (8 - ebits[j]);
         ebits[j] += tmp_ex;
		 tmp_ex = tmp_ex <<4;
         fine_priority[j] = tmp_ex >= excess-blnc;
         excess -= tmp_ex;
      }
      blnc = excess;
	  j++;
   }
   *_balance = blnc;

   for (;j<end;j++)
   {
	  ebits[j] = bits[j] >> 4;
      fine_priority[j] = ebits[j]<1;
	  bits[j] = 0;
   }

   return Bands_c;
}


int calculate_bitalloc(const AUDIOMode *m, short end, const short *offsets, const short *cap, int alloc_trim, int *intensity, int *dual_stereo,
	int total, int *balance, short *pulses, short *ebits, short *fine_priority, ec_ctx *ec)

{
   int lo, hi, len, j;
   int codedBands;
   int skip_start;
#ifndef HW_OPTIMIZATION6
   int skip_rsv;
   int dual_stereo_rsv=0;
   int intensity_rsv=0;
#endif   
  

//// shared_local[0~21] is occupied by offsets. 
   int *shared_local = (int *)(SSC_restricted_local);
   int *bits2 = &shared_local[22];
   int *thresh = &shared_local[44];
   int *trim_offset = &shared_local[66];
   int *bits1 = &shared_local[88];


   int m_nbAlloc;
 

   const unsigned char *m_allocVectors;

   m_allocVectors = m->allocVectors;    // for 192 ÀÌÇÏ
   m_nbAlloc = m->nbAllocVectors;


   total = IMAX(total, 0);
   len = m->nbEBands;

   skip_start = 0;
   /* Reserve a bit to signal the end of manually skipped bands. */

   
#ifndef HW_OPTIMIZATION6
   skip_rsv = total >= 1<<BITRES ? 1<<BITRES : 0;      // HW_CANDIDATE  88kbps¶óµµ 24º¸´Ù´Â ¹«Á¶°Ç Å¬°ÍÀÓ.
   total -= skip_rsv;
#else
   total -= 8;
#endif


   intensity_rsv = LOG2_FRAC_TABLE[end];
   if ((total - intensity_rsv) < 0)
		intensity_rsv = 0;
   else
   {
        total -= intensity_rsv;
		dual_stereo_rsv = (total-8) >= 0 ? 8 : 0;
        total -= dual_stereo_rsv;
   }

   j = 0;
   while(j<end)
   {
	   short tmp_bnd = m->eBands[j + 1] - m->eBands[j];
	   thresh[j] = IMAX(16, SSC_MULT16x16(3, tmp_bnd <<2));
	   trim_offset[j] = SSC_MULT16x16(2, SSC_MULT16x16(SSC_MULT16x16(tmp_bnd, alloc_trim-8), (end - j - 1)));
	   j++;
   }
   lo = 1;
   hi = m_nbAlloc - 1;
   do
   {
	  int mid = (lo + hi) >> 1;
      int done = 0;
      int psum = 0;

	  for (j = end-1; j>= 0;j--)
      {
         int bitsj;
         int N = m->eBands[j+1]-m->eBands[j];

		 bitsj = SSC_MULT16x16(2, SSC_MULT16x16(N,m_allocVectors[mid*len+j]<<1));
		 if (bitsj > 0)
			 bitsj = (bitsj + trim_offset[j]) < 0 ? 0 : (bitsj + trim_offset[j]);
		 bitsj = bitsj + offsets[j];
		 if ((thresh[j] - bitsj <= 0) || done)
         {
			psum += (bitsj - cap[j]) < 0 ? bitsj : cap[j];
            done = 1;
         } else {
			 if ((bitsj-16) >= 0)
				 psum = psum + 16;
         }
      }
      if ((psum -total)> 0)
         hi = mid - 1;
      else
         lo = mid + 1;
   }
   while ((lo-hi) <= 0);
   hi = lo--;

   for (j=0;j<end;j++)
   {
      int bits1j, bits2j;
      int N = m->eBands[j+1]-m->eBands[j];

	  bits1j = SSC_MULT16x16(N, m_allocVectors[lo*len+j]<<2);

#ifndef HW_FOR_BOXSLIM
	  bits2j = hi>=m_nbAlloc?  cap[j] : N*m_allocVectors[hi*len+j]<<2;
#else
	  bits2j = N*m_allocVectors[hi*len+j]<<2;
#endif

      if (bits1j > 0)
         bits1j = IMAX(0, bits1j + trim_offset[j]);
      if (bits2j > 0)
         bits2j = IMAX(0, bits2j + trim_offset[j]);
      if (lo > 0)
         bits1j += offsets[j];
      bits2j += offsets[j];
      if (offsets[j]>0)
         skip_start = j;
      bits2j = IMAX(0,bits2j-bits1j);
      bits1[j] = bits1j;
      bits2[j] = bits2j;
   }

   codedBands = cal_bitsTopulses(m, end, skip_start, bits1, bits2, thresh, cap,
	   total, balance, skip_rsv, intensity, intensity_rsv, dual_stereo, dual_stereo_rsv,
	   pulses, ebits, fine_priority, ec);

   return codedBands;
}

