/*
* Copyright 2011, 2014 Range Networks, Inc.
*
* This software is distributed under multiple licenses;
* see the COPYING file in the main directory for licensing
* information for this specific distribution.
*
* This use of this software may be subject to additional restrictions.
* See the LEGAL file in the main directory for details.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*/

#define LOG_GROUP LogGroup::GPRS		// Can set Log.Level.GPRS for debugging

#include "GPRSRLC.h"
#include "GSMCommon.h"

namespace GPRS {

int deltaBSN(int bsn1,int bsn2)
{
	static const int halfModulus = RLCBSN_t::BSNPeriodicity/2;
	int delta = bsn1 - bsn2;
	if (delta>=halfModulus) delta -= RLCBSN_t::BSNPeriodicity;
	else if (delta<-halfModulus) delta += RLCBSN_t::BSNPeriodicity;
	return delta;
}


// Based on GSM::FNDelta
// We assume the values are within a half periodicity of each other.
int RLCBSN_t::BSNdelta(RLCBSN_t v2)
{
	RLCBSN_t v1 = *this;
	//int delta = v1.mValue - v2.mValue;
	//if (delta>=halfModulus) delta -= BSNPeriodicity;
	//else if (delta<-halfModulus) delta += BSNPeriodicity;
	//return RLCBSN_t(delta);
	return RLCBSN_t(deltaBSN(v1.mValue,v2.mValue));
}

// Return 1 if v1 > v2; return -1 if v1 < v2, using modulo BSNPeriodicity.
int RLCBSN_t::BSNcompare(RLCBSN_t v2)
{
	int delta = BSNdelta(v2);
	if (delta>0) return 1;
	if (delta<0) return -1;
	return 0;
}

// (pat) Return the block radio number for a frame number.
RLCBSN_t FrameNumber2BSN(int fn)
{
	// The RLC blocks use a 52-multiframe, but each 13-multiframe is identical:
	// the first 12 frames are 3 RLC blocks, and the last frame is for timing or idle.
	int mfn = (fn / 13);			// how many 13-multiframes
	int rem = (fn - (mfn*13));	// how many blocks within the last multiframe.
	RLCBSN_t result = mfn * 3 + ((rem==12) ? 2 : (rem/4));
	result.normalize();
	return result;
}


// Return the Block Sequence Number for a frame number.
// There are 12 radio blocks per 52 frames,
int BSN2FrameNumber(RLCBSN_t absn)	// absolute block sequence number.
{
	// One extra frame is inserted after every 3 radio blocks,
	// so 3 radio blocks take 13 frames.
	int bsn = absn;	// Convert to int so we do math on int, not RLCBSN_t
	int result = ((int)bsn / 3) * 13 + ((int)bsn % 3) * 4;
	assert(result >= 0 && (unsigned) result <= GSM::gHyperframe);
	return result;
}

std::ostream& operator<<(std::ostream& os, const RLCDir::type &dir)
{
	os << RLCDir::name(dir);
	return os;
}
};
