/*
 * PeakSeq
 * Version 1.01
 * Paper by Joel Rozowsky, et. al.
 * Coded in C by Theodore Gibson.
 * io.c
 * This module deals with input/output concerns.
 */


#include <stdio.h>
#include <string.h>
#include "io.h"
#include "util.h"
#include "config.h"


//----------------------------------------------------------------------------
// PRIVATE FUNCTION PROTOTYPE
//----------------------------------------------------------------------------
String toString( const int num );


//----------------------------------------------------------------------------
// PUBLIC FUNCTIONS
//----------------------------------------------------------------------------
int getCnum( const String cname )
{
	// These local varaibles are used for temporary storage.
	char chr[3];
	int cnum = 0;

	// Remove the "chr" prefix from the string.
	int ret = sscanf( cname, "chr%2[^.]", chr );

	// If this function fails, return -1, indicating failure.
	if( ret != 1 ) return -1;

	// If the value in the chr string is a decimal number, cnum is the number.
	ret = sscanf(chr, "%d", &cnum);

	// If the value was a decimal number, check that this number is within the
	// bounds specified in config.h.
	if( ret == 1 )
	{
		if( (cnum >= MIN_CNUM) && (cnum <= MAX_CNUM) )
			return cnum;
		return -1;
	}

	// Otherwise get the character and return its numerical representation.
	char ch = '\0';
	sscanf(chr, "%c", &ch);
	switch( ch )
	{
		case 'X':
			cnum = 23;
			break;
		case 'Y':
			cnum = 24;
			break;
		case 'M':
			cnum = 25;
			break;
		default:
			return -1;
	}

	// If the function reaches this point, cnum must be either 23, 24, or 25.
	// As long as this value is within the bounds, return it.  Otherwise,
	// return -1.
	if( (cnum < MIN_CNUM) || (cnum < MAX_CNUM) )
		return cnum;
	return -1;
}

String getCname( const int cnum )
{
	// If cnum is not a real chromosome (not between 1 and 25) return the NULL
	// pointer.  It will be checked later within this function that cnum is
	// below 26.
	if( cnum < 1 )
		return NULL;

	// Initialize the String.
	String cname = safe_malloc( 6 * sizeof(char) );
	strcpy( cname, "chr" );

	// If this chromosome is represented by a number, convert the number to
	// its String representation and add it to the end of the chr string.
	if( cnum <= 22 )
	{
		String str = toString( cnum );
		strcat( cname, str );
		free( str );
		return cname;
	}

	// Otherwise this is a "character" chromosome.
	switch( cnum )
	{
		case 23:
			strcat( cname, "X" );
			return cname;
		case 24:
			strcat( cname, "Y" );
			return cname;
		case 25:
			strcat( cname, "M" );
			return cname;
		default:
			free( cname );
			return NULL;
	}
}

void getNewline( FILE* in )
{
	char buf[40];

	// Get the rest of the line and its terminating '\n' character.
	while( fscanf( in, "%39[^\n]", buf) == 1);
	char ch = fgetc( in );

	// If the end of the file has been reached, put the EOF character back so
	// that it can be read by the loop comparison.  Otherwise, a segmentation
	// fault might occur.
	if( ch == EOF) ungetc( ch, in );
}


//----------------------------------------------------------------------------
// PRIVATE FUNCTION
//----------------------------------------------------------------------------
/*
 * This function converts an integer between 1 and 22 (the chromosome numbers)
 * 	to a string containing these digits.
 * Outputs the string.
 */
String toString( const int num )
{
	// Check that the number is in the correct range.
	if( (num < 1) || (num > 22) )
		return NULL;

	// Allocate memory for and initialize the string.
	String str = safe_malloc( 3 * sizeof(char) );
	for(int i = 0; i < 3; i++)
		str[i] = '\0';

	// If this is a single digit number, it is only necessary to store one
	// character in the string.
	if( num < 10 )
		str[0] = num + '0';

	// Otherwise, store the tens and ones digit in separate fields.
	else
	{
		str[0] = (num/10) + '0';				// The tens digit.
		str[1] = (num % ((num/10) * 10)) + '0';	// The ones digit.
	}

	return str;		// Return the string.
}
