/****************************************************************************
(c) 2006 Melanie Thielker

This file is part of libdjconsole.

libdjconsole 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.

libdjconsole 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
libdjconsole; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA 
****************************************************************************/

#include "bitfield.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

class BitfieldSpec
{
public:
	int byte;
	unsigned char mask;
	int code;
};

Bitfield::Bitfield()
{
	Buffer=0;
	Size=0;
	Dirty=false;
}

Bitfield::Bitfield(int size)
{
	Buffer=new unsigned char[size];
	Size=size;
	memset(Buffer, 0, Size);
}

Bitfield::~Bitfield()
{
	if(Buffer != 0)
		delete[] Buffer;
}

bool Bitfield::load(const char *file)
{
	FILE *fp;

	fp=fopen(file, "r");
	if(!fp)
		return false;
	
	while(Specs.size())
	{
		delete Specs[0];
		Specs.erase(Specs.begin());
	}

	char buf[1024];

	while(fgets(buf, 1024, fp))
	{
		int byte, mask, code;

		if(sscanf(buf, "%d %d %d", &byte, &mask, &code) == 3)
		{
			BitfieldSpec *s=new BitfieldSpec;
			s->byte=byte;
			s->mask=(unsigned char)(mask & 0xff);
			s->code=code;

			Specs.push_back(s);
		}
	}
	fclose(fp);

	return true;
}

void Bitfield::setSize(int size)
{
	if(Size != 0)
		return;
	Buffer=new unsigned char[size];
	Size=size;
	memset(Buffer, 0, Size);
}

int Bitfield::size()
{
	return Size;
}

const unsigned char *Bitfield::bits()
{
	Dirty=false;
	return Buffer;
}

void Bitfield::setBit(int code, bool on)
{
	vector<BitfieldSpec *>::iterator it;

	for(it=Specs.begin();it != Specs.end();++it)
	{
		if((*it)->code == code)
		{
			if((*it)->byte < 0 || (*it)->byte >= Size)
				continue;
			if(!on)
				Buffer[(*it)->byte] &= ~(*it)->mask;
			else
				Buffer[(*it)->byte] |= (*it)->mask;
			Dirty=true;
		}
	}
}

void Bitfield::clearBit(int code)
{
	setBit(code, 0);
}

bool Bitfield::dirty()
{
	return Dirty;
}
