#pragma once
#include "../../stdafx.h"

//TODO: this file!
//TODO: tests!

class glLibInternal_integer {
	protected:
		bool* _bits; //LSB to MSB
		unsigned long _numof_bits;
	public:
		glLibInternal_integer() {
			_bits = NULL;
			_numof_bits = 0;
		}
		template <typename type_int> glLibInternal_integer(type_int t) {
			_numof_bits = 8 * sizeof(type_int);

			_bits = new bool[_numof_bits];

			for (unsigned long i=0;i<_numof_bits;++i) {
				_bits[i] = t & ((unsigned long)(1)<<i);
			}
		}
		glLibInternal_integer(const glLibInternal_integer& t) {
			_numof_bits = t._numof_bits;

			_bits = new bool[_numof_bits];

			for (unsigned long i=0;i<_numof_bits;++i) {
				_bits[i] = t._bits[i];
			}
		}
		~glLibInternal_integer() {
			if (_bits!=NULL) delete [] _bits;
		}

		glLibInternal_integer& operator =(const glLibInternal_integer& b);

		glLibInternal_integer operator +(const glLibInternal_integer& b) const;
		glLibInternal_integer operator -(const glLibInternal_integer& b) const;
		glLibInternal_integer operator *(const glLibInternal_integer& b) const;
		glLibInternal_integer operator /(const glLibInternal_integer& b) const;
		glLibInternal_integer operator %(const glLibInternal_integer& b) const;

		glLibInternal_integer operator +() const; //+a
		glLibInternal_integer operator -() const; //-a
		glLibInternal_integer& operator ++(); //++a
		glLibInternal_integer operator ++(int); //a++
		glLibInternal_integer& operator --(); //--a
		glLibInternal_integer operator --(int); //a--

		bool operator ==(const glLibInternal_integer& b) const {
			unsigned long i =   _numof_bits - 1;
			unsigned long j = b._numof_bits - 1;
			for ( ; ((i>=0)&&(j>=0)); --i,--j ) {
				if (_bits[i]!=b._bits[j]) return false;
			}
			return true;
		}
		inline bool operator !=(const glLibInternal_integer& b) const {
			return !(*this==b);
		}
		bool operator <(const glLibInternal_integer& b) const {
			unsigned long i =   _numof_bits - 1;
			unsigned long j = b._numof_bits - 1;
			for ( ; ((i>=0)&&(j>=0)); --i,--j ) {
				if (_bits[i]==0) {
					if (b._bits[j]==1) return true;
				}
			}
			return false;
		}
		inline bool operator <=(const glLibInternal_integer& b) const {
			return !(*this<b);
		}
		inline bool operator >(const glLibInternal_integer& b) const {
			return (b<*this);
		}
		inline bool operator >=(const glLibInternal_integer& b) const {
			return !(b<*this);
		}

		glLibInternal_integer operator ~() const {
			glLibInternal_integer result(*this);
			for (unsigned long i=0;i<_numof_bits;++i) _bits[i] = !_bits[i];
			return result;
		}
		glLibInternal_integer operator &(const glLibInternal_integer& b) const {
			glLibInternal_integer result(*this);
			for (unsigned long i=0;i<_numof_bits;++i) _bits[i] = ((_bits[i])&&(b._bits[i]));
			return result;
		}
		glLibInternal_integer operator |(const glLibInternal_integer& b) const {
			glLibInternal_integer result(*this);
			for (unsigned long i=0;i<_numof_bits;++i) _bits[i] = ((_bits[i])||(b._bits[i]));
			return result;
		}
		glLibInternal_integer operator ^(const glLibInternal_integer& b) const {
			glLibInternal_integer result(*this);
			for (unsigned long i=0;i<_numof_bits;++i) _bits[i] = (((_bits[i])&&(!b._bits[i]))||((!_bits[i])&&(b._bits[i])));
			return result;
		}
		/*glLibInternal_integer operator <<(const glLibInternal_integer& b) const {
			glLibInternal_integer temp(b);
			for (unsigned long i=0;i<_numof_bits;++i) {
				_bits[i] = (((_bits[i])&&(!b._bits[i]))||((!_bits[i])&&(b._bits[i])));
			}
			temp--;
		}
		glLibInternal_integer operator >>(const glLibInternal_integer& b) const {
			unsigned long temp = b.unsigned_long();
			for (unsigned long i=0;i<_numof_bits;++i) {
				_bits[i] = (((_bits[i])&&(!b._bits[i]))||((!_bits[i])&&(b._bits[i])));
			}
		}*/

		glLibInternal_integer& operator +=(const glLibInternal_integer& b) {
			unsigned long i =   _numof_bits - 1;
			unsigned long j = b._numof_bits - 1;
			bool carry = false;
			for ( ; ((i>=0)&&(j>=0)); --i,--j ) {
				switch (_bits[i]+b._bits[i]+carry) {
					case 0: { break; } //_bits[i]; carry=0, but we already know that
					case 1: { _bits[i]= true; carry=false; break; }
					case 2: { _bits[i]=false; carry= true; break; }
					case 3: { _bits[i]= true; carry= true; break; }
				}
			}
			if (carry) {
				//TODO: overflow!
			}
			return *this;
		}
		glLibInternal_integer& operator -=(const glLibInternal_integer& b);
		glLibInternal_integer& operator *=(const glLibInternal_integer& b);
		glLibInternal_integer& operator /=(const glLibInternal_integer& b);
		glLibInternal_integer& operator %=(const glLibInternal_integer& b);
		glLibInternal_integer& operator &=(const glLibInternal_integer& b);
		glLibInternal_integer& operator |=(const glLibInternal_integer& b);
		glLibInternal_integer& operator ^=(const glLibInternal_integer& b);
		glLibInternal_integer& operator <<=(const glLibInternal_integer& b);
		glLibInternal_integer& operator >>=(const glLibInternal_integer& b);

		void print_bits(void) {
			for (unsigned long i=0;i<_numof_bits;++i) {
				printf("%d",_bits[_numof_bits-i-1]);
			}
		}
};
class glLibMathBigUInt : public glLibInternal_integer {
};
class glLibMathBigInt : public glLibInternal_integer {
	//TODO: must override operators to handle signs
	public:
		char sign;
	public:
		glLibMathBigInt() : glLibInternal_integer() {
			sign = 0;
		}
		template <typename type_int> glLibMathBigInt(type_int t) : glLibInternal_integer(t) {
			(t<0) ? sign=-1 : sign=1;
		}
};