void
EnhancedUplinkPacketScheduler::RBsAllocation ()
{
	/* This is an implementation of an algorithm based on  first maximum expansion algorithm reported in
	 * L. Temiño, G. Berardinelli, S. Frattasi,  and P.E. Mogensen,
	 * "Channel-aware scheduling algorithms for SC-FDMA in LTE uplink",  in Proc. PIMRC 2008
	 * The main difference is that here we have a given number of RB's to allocate to the UE
	 * based on its pending queue status whereas the original attempts to allocate till another
	 * UE has a better channel response
	 */
#ifdef SCHEDULER_DEBUG
	std::cout << " ---- UL RBs Allocation";
#endif

	UsersToSchedule *users = GetUsersToSchedule ();
	UserToSchedule* scheduledUser;
	int nbOfRBs = GetMacEntity ()->GetDevice ()->GetPhy ()->GetBandwidthManager ()->GetUlSubChannels ().size ();

	int availableRBs;     // No of RB's not allocated
	int unallocatedUsers; // No of users who remain unallocated
	int selectedUser;     // user to be selected for allocation
	int selectedPRB;      // PRB to be selected for allocation
	double bestMetric;    // best metric to identify user/RB combination
	int left, right;      // index of left and left PRB's to check
	bool Allocated[nbOfRBs];
	bool allocationMade;
	double metrics[nbOfRBs][users->size ()];
	int requiredPRBs[users->size ()];


	//Some initialization
	availableRBs = nbOfRBs;
	unallocatedUsers = users->size ();
	for(int i=0; i < nbOfRBs; i++)
		Allocated[i] = false;

	//create a matrix of flow metrics
	for (int i = 0; i < nbOfRBs; i++)
	{
		for (int j = 0; j < users->size (); j++)
		{
			metrics[i][j] = ComputeSchedulingMetric (users->at (j), i);
		}
	}

	//create number of required PRB's per scheduled users
	for(int j=0; j < users->size(); j++)
	{
		scheduledUser = users->at(j);
#ifdef SCHEDULER_DEBUG
		cout << "\n" << "User "  << j; // << "CQI Vector";
#endif

		std::vector<double> sinrs;
		for (std::vector<int>::iterator c = scheduledUser->m_channelContition.begin ();
				c != scheduledUser->m_channelContition.end (); c++)
		{
			//cout << *c <<" ";
			sinrs.push_back (GetMacEntity ()->GetAmcModule ()->GetSinrFromCQI (*c));
		}


		double effectiveSinr =  GetEesmEffectiveSinr (sinrs);

		int mcs = GetMacEntity ()->GetAmcModule ()->GetMCSFromCQI (
			  GetMacEntity ()->GetAmcModule ()->GetCQIFromSinr (effectiveSinr));
		scheduledUser->m_selectedMCS = mcs;
		requiredPRBs[j] = (floor) (scheduledUser->m_dataToTransmit /
				  (GetMacEntity ()->GetAmcModule ()->GetTBSizeFromMCS (mcs, 1) / 8));
#ifdef SCHEDULER_DEBUG
		cout << " EffSINR = " << effectiveSinr << "  MCS = " << mcs << "\n";
#endif
	}

#ifdef SCHEDULER_DEBUG
  //std::cout << ", available RBs " << nbOfRBs << ", users " << users->size () << std::endl;
  for (int ii = 0; ii < users->size (); ii++)
    {
	  std::cout << "Metrics for user "
			  << users->at (ii)->m_userToSchedule->GetIDNetworkNode () << "\n";
	  for (int jj = 0; jj < nbOfRBs; jj++)
	    {
		  //std::cout  << setw(3) << metrics[jj][ii]/1000 << " ";
		  printf("%3d  ", (int) (metrics[jj][ii]/1000.0));
	    }
	  std::cout << std::endl;
    }
#endif

  //RBs allocation

  while(availableRBs > 0 && unallocatedUsers > 0) //
  {
	  // First step: find the best user-RB combo
	  selectedPRB = -1;
	  selectedUser = -1;
	  bestMetric = (double) (-(1<<30));

	  for(int i=0; i < nbOfRBs; i++)
	  {
		  if (!Allocated[i]){ // check only unallocated PRB's
			  for(int j=0; j < users->size (); j++)
			  {
				  if ( users->at (j)->m_listOfAllocatedRBs.size() == 0
						  && requiredPRBs[j] > 0) //only unallocated users requesting some RB's
					  if (bestMetric < metrics[i][j]){
						  selectedPRB = i;
						  selectedUser = j;
						  bestMetric = metrics[i][j];
					  }
			  }

		  }
	  }
	  // Now start allocating for the selected user at the selected PRB the required blocks
	  // using how many PRB's are needed for the user
	  if (selectedUser != -1)
	  {
		  scheduledUser = users->at(selectedUser);
		  scheduledUser->m_listOfAllocatedRBs.push_back (selectedPRB);
		  Allocated[selectedPRB] = true;
		  left =  selectedPRB - 1;
		  right = selectedPRB + 1;
		  availableRBs--;
		  unallocatedUsers--;

		  allocationMade = true;
		  for(int i = 1; i < requiredPRBs[selectedUser] && availableRBs > 0 && allocationMade; i++ )
		  { // search right and left of initial allocation
			  allocationMade = false;
			  if (left >=0 && Allocated[left] && right < nbOfRBs && Allocated[right])
				  break; // nothing is available, since we need to have contiguous allocation

			  if (    (right < nbOfRBs) && (! Allocated[right]) &&
					  (
							  ((left >=0) &&
							  (metrics[right][selectedUser] >= metrics[left][selectedUser])) // right is better than left
							  || (left < 0) || Allocated[left]// OR no more left
					  )
				)
			  {
				  //Allocate PRB at right to the user
				  Allocated[right] = true;
				  scheduledUser->m_listOfAllocatedRBs.push_back (right);
				  right++;
				  allocationMade = true;
				  availableRBs--;
			  } else if ( (left >=0) && (! Allocated[left]) &&
						  (
							  ((right < nbOfRBs) &&
							  (metrics[left][selectedUser] > metrics[right][selectedUser])) //left better than right
							  || (right >= nbOfRBs) || Allocated[right]// OR no more right
						   )
						)
			  {
				  //Allocate PRB at left to the user
				  Allocated[left] = true;
				  scheduledUser->m_listOfAllocatedRBs.push_back (left);
				  left--;
				  allocationMade = true;
				  availableRBs--;
			  }
		  } // end of for
		  if (allocationMade){
			  scheduledUser->m_transmittedData = GetMacEntity ()->GetAmcModule ()->
					  GetTBSizeFromMCS (scheduledUser->m_selectedMCS, scheduledUser->m_listOfAllocatedRBs.size()) / 8;
#ifdef SCHEDULER_DEBUG
			  printf("Scheduled User = %d mcs = %d Required RB's = %d Allocated RB's= %d\n",
		 				  scheduledUser->m_userToSchedule->GetIDNetworkNode(),
		 				  scheduledUser->m_selectedMCS,
		 				  requiredPRBs[selectedUser], scheduledUser->m_listOfAllocatedRBs.size() );
			  for(int i=0; i<scheduledUser->m_listOfAllocatedRBs.size(); i++)
				  printf("%d ", scheduledUser->m_listOfAllocatedRBs.at(i));
			  printf("\n------------------\n");
#endif
		  }
	  } else { // nothing to do exit the allocation loop
		  break;
	  }
  } //while

}
void
DownlinkPacketScheduler::RBsAllocation ()
{
#ifdef SCHEDULER_DEBUG
	std::cout << " ---- DownlinkPacketScheduler::RBsAllocation";
#endif


  FlowsToSchedule* flows = GetFlowsToSchedule ();
  int nbOfRBs = GetMacEntity ()->GetDevice ()->GetPhy ()->GetBandwidthManager ()->GetDlSubChannels ().size ();

  //create a matrix of flow metrics
  double metrics[nbOfRBs][flows->size ()];
  for (int i = 0; i < nbOfRBs; i++)
    {
	  for (int j = 0; j < flows->size (); j++)
	    {
		  metrics[i][j] = ComputeSchedulingMetric (flows->at (j)->GetBearer (),
				                                   flows->at (j)->GetSpectralEfficiency ().at (i),
	    		                                   i);
	    }
    }

#ifdef SCHEDULER_DEBUG
  std::cout << ", available RBs " << nbOfRBs << ", flows " << flows->size () << std::endl;
  for (int ii = 0; ii < flows->size (); ii++)
    {
	  std::cout << "\t metrics for flow "
			  << flows->at (ii)->GetBearer ()->GetApplication ()->GetApplicationID () << ":";
	  for (int jj = 0; jj < nbOfRBs; jj++)
	    {
		  std::cout << " " << metrics[jj][ii];
	    }
	  std::cout << std::endl;
    }
#endif


  AMCModule *amc = GetMacEntity ()->GetAmcModule ();
  double l_dAllocatedRBCounter = 0;

  int l_iNumberOfUsers = ((ENodeB*)this->GetMacEntity()->GetDevice())->GetNbOfUserEquipmentRecords();

  bool * l_bFlowScheduled = new bool[flows->size ()];
  int l_iScheduledFlows = 0;
  std::vector<double> * l_bFlowScheduledSINR = new std::vector<double>[flows->size ()];
  for (int k = 0; k < flows->size (); k++)
      l_bFlowScheduled[k] = false;

  //RBs allocation
  for (int s = 0; s < nbOfRBs; s++)
    {
      if (l_iScheduledFlows == flows->size ())
          break;

      double targetMetric = 0;
      bool RBIsAllocated = false;
      FlowToSchedule* scheduledFlow;
      int l_iScheduledFlowIndex = 0;

      for (int k = 0; k < flows->size (); k++)
        {
          if (metrics[s][k] > targetMetric && !l_bFlowScheduled[k]  && flows->at (k)->GetDataToTransmit() >0 )
            {
              targetMetric = metrics[s][k];
              RBIsAllocated = true;
              scheduledFlow = flows->at (k);
              l_iScheduledFlowIndex = k;
            }
        }

      if (RBIsAllocated)
        {
          l_dAllocatedRBCounter++;

          scheduledFlow->GetListOfAllocatedRBs()->push_back (s); // the s RB has been allocated to that flow!

#ifdef SCHEDULER_DEBUG
          std::cout << "\t *** RB " << s << " assigned to the "
                  " flow " << scheduledFlow->GetBearer ()->GetApplication ()->GetApplicationID ()
                  << std::endl;
#endif
          double sinr = amc->GetSinrFromCQI (scheduledFlow->GetCqiFeedbacks ().at (s));
          l_bFlowScheduledSINR[l_iScheduledFlowIndex].push_back(sinr);

          double effectiveSinr = GetEesmEffectiveSinr (l_bFlowScheduledSINR[l_iScheduledFlowIndex]);
          int mcs = amc->GetMCSFromCQI (amc->GetCQIFromSinr (effectiveSinr));
          int transportBlockSize = amc->GetTBSizeFromMCS (mcs, scheduledFlow->GetListOfAllocatedRBs ()->size ());
          if (transportBlockSize >= scheduledFlow->GetDataToTransmit() * 8)
          {
              l_bFlowScheduled[l_iScheduledFlowIndex] = true;
              l_iScheduledFlows++;
          }

        }
    }

  delete [] l_bFlowScheduled;
  delete [] l_bFlowScheduledSINR;


  //Finalize the allocation
  PdcchMapIdealControlMessage *pdcchMsg = new PdcchMapIdealControlMessage ();

  for (FlowsToSchedule::iterator it = flows->begin (); it != flows->end (); it++)
    {
      FlowToSchedule *flow = (*it);
      if (flow->GetListOfAllocatedRBs ()->size () > 0)
        {
          //this flow has been scheduled
          std::vector<double> estimatedSinrValues;
          for (int rb = 0; rb < flow->GetListOfAllocatedRBs ()->size (); rb++ )

            {
              double sinr = amc->GetSinrFromCQI (
                      flow->GetCqiFeedbacks ().at (flow->GetListOfAllocatedRBs ()->at (rb)));

              estimatedSinrValues.push_back (sinr);
            }

          //compute the effective sinr
          double effectiveSinr = GetEesmEffectiveSinr (estimatedSinrValues);

          //get the MCS for transmission

          int mcs = amc->GetMCSFromCQI (amc->GetCQIFromSinr (effectiveSinr));

          //define the amount of bytes to transmit
          //int transportBlockSize = amc->GetTBSizeFromMCS (mcs);
          int transportBlockSize = amc->GetTBSizeFromMCS (mcs, flow->GetListOfAllocatedRBs ()->size ());
          double bitsToTransmit = transportBlockSize;
          flow->UpdateAllocatedBits (bitsToTransmit);

#ifdef SCHEDULER_DEBUG
		  std::cout << "\t\t --> flow "	<< flow->GetBearer ()->GetApplication ()->GetApplicationID ()
				  << " has been scheduled: " <<
				  "\n\t\t\t nb of RBs " << flow->GetListOfAllocatedRBs ()->size () <<
				  "\n\t\t\t effectiveSinr " << effectiveSinr <<
				  "\n\t\t\t tbs " << transportBlockSize <<
				  "\n\t\t\t bitsToTransmit " << bitsToTransmit
				  << std::endl;
#endif

		  //create PDCCH messages
		  for (int rb = 0; rb < flow->GetListOfAllocatedRBs ()->size (); rb++ )
		    {
			  pdcchMsg->AddNewRecord (PdcchMapIdealControlMessage::DOWNLINK,
					  flow->GetListOfAllocatedRBs ()->at (rb),
									  flow->GetBearer ()->GetDestination (),
									  mcs);
		    }
	    }
    }

  if (pdcchMsg->GetMessage()->size () > 0)
    {
      GetMacEntity ()->GetDevice ()->GetPhy ()->SendIdealControlMessage (pdcchMsg);
    }
  delete pdcchMsg;
}