/*
 *         bpack - A Burrows-Wheeler Transform and Huffman Encoding
 *                            Implementation
 *
 *  Copyright (C) 2006      Angelo Arrifano <miknix@gmail.com>
 *  Copyright (C) 2006      Vasco Costa <the_papon@hotmail.com>
 *
 *  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
 */

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

#include "bw.h"

/********************************************
 * This code doesnt calculate correct index *
 ********************************************/
/*
unsigned char *block_beg;
unsigned char *block_end;

int bw_encode_cmp(unsigned char **m1, unsigned char **m2){
	unsigned char *b1, *b2;

	b1=*m1;
	b2=*m2;
	while(*b1 == *b2){
		b1++; b2++;
		if(b1 > block_end) b1=block_beg;
		if(b2 > block_end) b2=block_beg;
		if(b1 == *m1) return(0);
	}
	if(*b1 > *b2)
		return(1);
	else
		return(-1);
}


int bw_encode(unsigned char *block, unsigned char *bw_block, int size){
	unsigned char **map;
	int i, index;

	//Byte mapping (build 1st column)
	if((map=(unsigned char **)malloc(sizeof(char *) * size))==NULL){
		printf("ERROR: Out of memory!\n");
		exit(10);
	}
	for(i=0; i<size; i++) map[i]=block+i;
	block_beg=block;
	block_end=block+size-1;
	
	//Byte Sorting
	qsort(map, size, sizeof(char *), (int(*)(const void *, const void *))bw_encode_cmp);
		
	//Byte remaping (build last column)
	// and index scanning
	index=-1;
	for(i=0; i<size; i++){
		if(map[i] == block_beg)
			bw_block[i]=*block_end;
		else
			bw_block[i]=*(map[i]-1);
		if(bw_block[i] == block[0] && index == -1) index = i-1;
	}	

	free(map); 
	return(index);
}*/

/***************************
 * Based on Wikipedia-en   *
 * Burrows-Wheeler article *
 ***************************/

unsigned char *block_beg;
int block_size;

int bw_encode_cmp(int *a, int *b){
	int ai=*a, bi=*b, count=block_size;
    
	while(block_beg[ai] == block_beg[bi]){
		if (++ai == block_size) ai=0;
		if (++bi == block_size) bi=0;
		if (--count == 0) return(0);
	}
	if(block_beg[ai] > block_beg[bi])
		return(1);
	else
		return(-1);
}

//
int bw_encode(unsigned char *block, unsigned char *bw_block, int size){
int *blocki;
int i, index=0;

	blocki=(int *)malloc(sizeof(int)*size);

	for(i=0; i<size; i++) blocki[i]=i;

	block_beg=block;
	block_size=size;
	qsort(blocki, size, sizeof(int), (int(*)(const void *,const void *))bw_encode_cmp);

	for(i=0; i<size; i++){
		bw_block[i]=block[(blocki[i]+size-1)%size];
		if(blocki[i] == 0) index=i;
	}

	free(blocki);
	return(index);
}

/**************************************
 * SUPER FAST BW INVERSE TRANSFORM    *
 * Angelo Arrifano (miknix@gmail.com) *
 **************************************/

int bw_decode_cmp(unsigned char **m1, unsigned char **m2){
	unsigned char *b1, *b2;

	b1=*m1;
	b2=*m2;
	if(*b1 == *b2){
		//If they are same byte, compare memory addresses.
		if(b1 > b2)
			return(1);
		else
			return(-1);
	}
	if(*b1 > *b2)
		return(1);
	else
		return(-1);
}


int bw_decode(unsigned char *bw_block, unsigned char *block, int size, int index){
	unsigned char **map;
	int i, j;
	
	//Byte mapping (build last column)
	map=(unsigned char **)malloc(sizeof(char *) * size);
	for(i=0; i<size; i++) map[i]=bw_block+i;

	//Byte Sorting
	qsort(map, size, sizeof(char *), (int(*)(const void *,const void *))bw_decode_cmp);

	i=0;
	j=index;
	do{
		block[i]=*map[j];
		j=map[j]-bw_block;
		i++;
	}while(i<size);

	free(map);
	return(0);
}

