/* gprs_coding_scheme.h
 *
 * Copyright (C) 2015 by Sysmocom s.f.m.c. GmbH
 * Author: Jacob Erlbeck <jerlbeck@sysmocom.de>
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * 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.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 */

#pragma once

#include <stdint.h>
#include <stddef.h>


class GprsCodingScheme {
public:
	enum Scheme {
		UNKNOWN,
		CS1, CS2, CS3, CS4,
		MCS1, MCS2, MCS3, MCS4,
		MCS5, MCS6, MCS7, MCS8, MCS9,
		NUM_SCHEMES
	};

	enum Mode {
		GPRS,
		EGPRS_GMSK,
		EGPRS,
	};

	enum HeaderType {
		HEADER_INVALID,
		HEADER_GPRS_CONTROL,
		HEADER_GPRS_DATA,
		HEADER_EGPRS_DATA_TYPE_1,
		HEADER_EGPRS_DATA_TYPE_2,
		HEADER_EGPRS_DATA_TYPE_3,
	};

	GprsCodingScheme(Scheme s = UNKNOWN);

	operator bool() const {return m_scheme != UNKNOWN;}
	operator int()  const {return (int)m_scheme;}
	operator Scheme() const {return m_scheme;}
	unsigned int to_num() const;

	GprsCodingScheme& operator =(Scheme s);
	GprsCodingScheme& operator =(GprsCodingScheme o);

	bool isValid()   const {return UNKNOWN <= m_scheme && m_scheme <= MCS9;}
	bool isGprs()   const {return CS1 <= m_scheme && m_scheme <= CS4;}
	bool isEgprs()  const {return m_scheme >= MCS1;}
	bool isEgprsGmsk()  const {return isEgprs() && m_scheme <= MCS4;}
	bool isCompatible(Mode mode) const;
	bool isCompatible(GprsCodingScheme o) const;

	void inc(Mode mode);
	void dec(Mode mode);
	void inc();
	void dec();

	unsigned int sizeUL() const;
	unsigned int sizeDL() const;
	unsigned int maxBytesUL() const;
	unsigned int maxBytesDL() const;
	unsigned int spareBitsUL() const;
	unsigned int spareBitsDL() const;
	unsigned int maxDataBlockBytes() const;
	unsigned int numDataBlocks() const;
	const char *name() const;
	HeaderType headerTypeData() const;
	HeaderType headerTypeControl() const;

	static GprsCodingScheme getBySizeUL(unsigned size);
	static GprsCodingScheme getGprsByNum(unsigned num);
	static GprsCodingScheme getEgprsByNum(unsigned num);

	static const char *modeName(Mode mode);
private:
	enum Scheme m_scheme;
};

inline unsigned int GprsCodingScheme::to_num() const
{
	if (isGprs())
		return (m_scheme - CS1) + 1;

	if (isEgprs())
		return (m_scheme - MCS1) + 1;

	return 0;
}

inline bool GprsCodingScheme::isCompatible(Mode mode) const
{
	switch (mode) {
	case GPRS: return isGprs();
	case EGPRS_GMSK: return isEgprsGmsk();
	case EGPRS: return isEgprs();
	}

	return false;
}

inline bool GprsCodingScheme::isCompatible(GprsCodingScheme o) const
{
	return (isGprs() && o.isGprs()) || (isEgprs() && o.isEgprs());
}

inline GprsCodingScheme::HeaderType GprsCodingScheme::headerTypeControl() const
{
	return HEADER_GPRS_CONTROL;
}

inline GprsCodingScheme::GprsCodingScheme(Scheme s)
	: m_scheme(s)
{
	if (!isValid())
		m_scheme = UNKNOWN;
}

inline GprsCodingScheme& GprsCodingScheme::operator =(Scheme s)
{
	m_scheme = s;

	if (!isValid())
		m_scheme = UNKNOWN;

	return *this;
}

inline GprsCodingScheme& GprsCodingScheme::operator =(GprsCodingScheme o)
{
	m_scheme = o.m_scheme;
	return *this;
}

inline GprsCodingScheme GprsCodingScheme::getGprsByNum(unsigned num)
{
	if (num < 1 || num > 4)
		return GprsCodingScheme();

	return GprsCodingScheme(Scheme(CS1 + (num - 1)));
}

inline GprsCodingScheme GprsCodingScheme::getEgprsByNum(unsigned num)
{
	if (num < 1 || num > 9)
		return GprsCodingScheme();

	return GprsCodingScheme(Scheme(MCS1 + (num - 1)));
}

/* The coding schemes form a partial ordering */
inline bool operator ==(GprsCodingScheme a, GprsCodingScheme b)
{
	return int(a) == int(b);
}

inline bool operator !=(GprsCodingScheme a, GprsCodingScheme b)
{
	return !(a == b);
}

inline bool operator <(GprsCodingScheme a, GprsCodingScheme b)
{
	return a.isCompatible(b) && int(a) < int(b);
}

inline bool operator >(GprsCodingScheme a, GprsCodingScheme b)
{
	return a.isCompatible(b) && int(a) > int(b);
}

inline bool operator <=(GprsCodingScheme a, GprsCodingScheme b)
{
	return a == b || a < b;
}

inline bool operator >=(GprsCodingScheme a, GprsCodingScheme b)
{
	return a == b || a > b;
}

