#include <fonts.h>
#include <render.h>

	// Local function: Get next nibble.
	static int ctr=0;  // offset for next nibble
	static int hilo=0; // 0= high nibble next, 1=low nibble next
	const uint8_t * data;
	static char gnn(){ // Get next nibble
		static int byte;
		int val;
		if(hilo==1)
			ctr++;
		hilo=1-hilo;
		if(hilo==1){
            if(efont.type==FONT_EXTERNAL){
                byte=_getFontData(GET_DATA,0);
            }else{
                byte=data[ctr];
            };
			val=byte>>4;
		}else{
			val=byte&0x0f;
		};
		return val;
	};

	// Local function: Unpack "long run".
	int upl(int off){
		int retval;

		while((retval=gnn())==0){
			off++;
		};
		while(off-->0){
			retval=retval<<4;
			retval+=gnn();
		};
		return retval;
	};


uint8_t * pk_decode(const uint8_t * ldata,int * len){
	ctr=0;hilo=0;
	data=ldata;
	int length=*len;      // Length of character bytestream
	int height;           // Height of character in bytes
	int hoff;             // bit position for non-integer heights
	uint8_t * bufptr=charBuf; // Output buffer for decoded character

	height=(font->u8Height-1)/8+1;
	hoff=font->u8Height%8;

#define DYN (12)  // Decoder parameter: Fixed value for now.
	int repeat=0; // Decoder internal: repeat colum?
	int curbit=0; // Decoder internal: current bit (1 or 0)
	int pos=0;    // Decoder internal: current bit position (0..7)
	int nyb;      // Decoder internal: current nibble / value

    if(efont.type==FONT_EXTERNAL){
        if(_getFontData(PEEK_DATA,0)>>4 == 14){ // Char starts with 1-bits. 
            gnn();
            curbit=1;
        };
    }else{
        if(data[ctr]>>4 == 14){ // Char starts with 1-bits. 
            gnn();
            curbit=1;
        };
    };

	while(ctr<length){ /* Iterate the whole input stream */

		/* Get next encoded nibble and decode */
		nyb=gnn();

		if(nyb==15){
			repeat++;
			continue;
		}else if(nyb==14){
			nyb=upl(0);
			nyb+=1;
			repeat+=nyb;
			continue;
		}else if(nyb>DYN){
			nyb=(16*(nyb-DYN-1))+gnn()+DYN+1;
		}else if(nyb==0){
			nyb=upl(1);
			nyb+=(16*(13-DYN)+DYN)-16;
		};

		/* Generate & output bits */

		while(nyb-->0){
			if(pos==0) // Clear each byte before we start.
				*bufptr=0;
			if(curbit==1){
				*bufptr|=1<<(7-pos);
			};
			pos++;
			if(((bufptr-charBuf)%height)==(height-1) && (pos==hoff)){
				// Finish incomplete last byte per column
				pos=8;
			};

			if(pos==8){
				bufptr++;
				if((bufptr-charBuf)%height==0){ // End of column?
					while(repeat>0){
						for(int y=0;y<height;y++){
							bufptr[0]=bufptr[-height];
							bufptr++;
						};
						repeat--;
					};
				};
				pos=0;
			};
		};
		curbit=1-curbit;
	};
		
	*len=(bufptr-charBuf)/height; // return size of output buffer.
	return charBuf;
};