/* 
 * ADIOS is freely available under the terms of the BSD license described
 * in the COPYING file in the top level directory of this source distribution.
 *
 * Copyright (c) 2008 - 2009.  UT-BATTELLE, LLC. All rights reserved.
 */

#include <stdint.h>
#include <stdio.h>
#include "public/adios_types.h"
#include "core/adios_logger.h"

void show_bytes(unsigned char * start, int len)
{
    int i;
    for (i = 0; i < len; i ++) {
        log_info(" %.2x", start[i]);
    }
    log_info("\n");
}


void swap_16_ptr(void *data) 
{
    uint16_t d = *(uint16_t *)data;
    *(uint16_t *)data = d>>8 | d<<8;
}


void swap_32_ptr(void *data)
{
    uint32_t d = *(uint32_t *)data;
    *(uint32_t *)data = ((d&0x000000FF)<<24) 
                      + ((d&0x0000FF00)<<8)
	                  + ((d&0x00FF0000)>>8)
	                  + ((d&0xFF000000)>>24);
}


void swap_64_ptr(void *data)
{
    uint64_t d = *(uint64_t *)data;
    *(uint64_t *)data = ((d&0x00000000000000FF)<<56) 
		                  + ((d&0x000000000000FF00)<<40)
		                  + ((d&0x0000000000FF0000)<<24)
		                  + ((d&0x00000000FF000000)<<8)
		                  + ((d&0x000000FF00000000LL)>>8)
		                  + ((d&0x0000FF0000000000LL)>>24)
		                  + ((d&0x00FF000000000000LL)>>40)
		                  + ((d&0xFF00000000000000LL)>>56);
}


void swap_128_ptr(void *data)
{
    uint64_t d = *(uint64_t *)data;
    *(uint64_t *)data = ((d&0x00000000000000FF)<<56) 
		                  + ((d&0x000000000000FF00)<<40)
		                  + ((d&0x0000000000FF0000)<<24)
		                  + ((d&0x00000000FF000000)<<8)
		                  + ((d&0x000000FF00000000LL)>>8)
		                  + ((d&0x0000FF0000000000LL)>>24)
		                  + ((d&0x00FF000000000000LL)>>40)
		                  + ((d&0xFF00000000000000LL)>>56);
    d = *((uint64_t *)data + 1);
    d = ((d&0x00000000000000FF)<<56) 
		                  + ((d&0x000000000000FF00)<<40)
		                  + ((d&0x0000000000FF0000)<<24)
		                  + ((d&0x00000000FF000000)<<8)
		                  + ((d&0x000000FF00000000LL)>>8)
		                  + ((d&0x0000FF0000000000LL)>>24)
		                  + ((d&0x00FF000000000000LL)>>40)
		                  + ((d&0xFF00000000000000LL)>>56);
    *((uint64_t *)data + 1) = *(uint64_t *)data;
    *(uint64_t *)data = d; 
}


void swap_adios_type(void *data, enum ADIOS_DATATYPES type)
{
    if(type == adios_string) {
        return;
	}
	else {
		uint64_t size = adios_get_type_size (type, "");

		switch (size)
		{
			case 1:
				break;
			case 2:
				swap_16_ptr(data);
				break;
			case 4:
				swap_32_ptr(data);
				break;
			case 8:
				swap_64_ptr(data);
				break;
			case 16:
				swap_128_ptr(data);
				break;
			case adios_complex:
			case adios_double_complex:
				// TODO
				break;
		}
	}
}


void swap_adios_type_array(void *data, enum ADIOS_DATATYPES type, uint64_t payload_size)
{
    uint64_t size = adios_get_type_size (type, "");
    uint64_t num_elements = payload_size / size;

    uint64_t i = 0;
	for(i = 0; i < num_elements; i ++) {
        swap_adios_type((char *)data + i*size, type);
	}    
}

void swap_ptr(void * data, int size)
{
	switch (size)
	{
		case 16:
			swap_16_ptr(data);
			break;
		case 32:
			swap_32_ptr(data);
			break;
		case 64:
			swap_64_ptr(data);
			break;
		case 128:
			swap_128_ptr(data);
			break;
	}
}
