#include <string.h>
#include <ctype.h>
#include <math.h>
#include <glib/gprintf.h>
#include "globals.h"
#include "string_utils.h"


void Float_To_Text(int decimal_digits,float number_in, gchar ** text_out)
{
	g_assert (*text_out == NULL);

	if (fabs(number_in)<1.1*smallest_allowed_number) {
		if (number_in<0.0) {
			*text_out = g_strdup_printf("-0.%0*d",decimal_digits,0);
		} else {
			*text_out = g_strdup_printf("0.%0*d",decimal_digits,0);
		}
		return;
	}

	*text_out = g_strdup_printf("%.*e", decimal_digits, number_in);
}


gboolean String_is_it_numeric(char *parameter)
{

	GRegex *numeric_regex = g_regex_new (	"^\\s*[+-]?(\\d*\\.\\d+|\\d+(\\.\\d*)?)\\s*(e\\s*[+-]?\\d+)?\\s*$",
	                                        G_REGEX_CASELESS,
	                                        0,
	                                        NULL);

	gboolean match = g_regex_match (numeric_regex, parameter, 0, NULL);
	g_regex_unref (numeric_regex);
	return match;
}


gboolean String_is_it_pos_int(char *parameter)
{

        GRegex *numeric_regex = g_regex_new (   "^\\s*[+]?\\d+\\s*$",
                                                G_REGEX_CASELESS,
                                                0,
                                                NULL);

        gboolean match = g_regex_match (numeric_regex, parameter, 0, NULL);
        g_regex_unref (numeric_regex);
        return match;
}


gboolean String_is_it_pos_neg_int(char *parameter)
{

        GRegex *numeric_regex = g_regex_new (   "^\\s*[+-]?\\d+\\s*$",
                                                G_REGEX_CASELESS,
                                                0,
                                                NULL);

        gboolean match = g_regex_match (numeric_regex, parameter, 0, NULL);
        g_regex_unref (numeric_regex);
        return match;
}


void String_Parameter_To_Text(float Float_To_Convert, int significant_digits,
                              char *start_string,char *units,gchar **LCD_string,int show_plus_sign, int width_of_column)
{
	gchar *floating_val = NULL;
	gchar *unit_mult = NULL;	/* units multiplier, eg. M, k, u */

	/* Copy the floating point value to a string. Do not multiply to accomodate units; the roundoff */
	/* is annoying. (e.g. 1.000 -> 0.999) */
	/* Move the decimal with string manipulations instead. */

	GString *out_gstr = g_string_new (start_string);

	/* if significant_digits is zero, used the supplied integer rather than the floating number */

	if (!significant_digits) {
		g_string_append_printf (out_gstr, "%d", (int) Float_To_Convert);
	} else {
		int i;
		int shift_decimal_by;	/* if the exponent isn't a multiple of 3, the decimal point will be moved */
		int decimal_location;	/* where the decimal is in the number string */
		int exponent_val;	/* the exponent, in integer form */

		Float_To_Text(remote_digits_after_decimal,Float_To_Convert,&floating_val);

		/* -- COPY FIRST ONE OR TWO CHARACTERS -- */
		if (floating_val[0]=='-') {		/* if it's negative ... */
			decimal_location=2;						/* decimal at position two (e.g.: -2.23e-9) */
			out_gstr = g_string_append_c (out_gstr, '-');			/* copy minus sign */
			out_gstr = g_string_append_c (out_gstr, floating_val[1]);	/* copy first digit */

		} else if (show_plus_sign==YES) {	/* if it's positive and plus sign required ... */
			decimal_location=1;				/* decimal at position one (e.g.: 2.23e-9) */
			out_gstr = g_string_append_c (out_gstr, '+');                   /* copy minus sign */
			out_gstr = g_string_append_c (out_gstr, floating_val[0]);       /* copy first digit */
		} else {									/* if it's positive and plus sign not required ... */
			decimal_location=1;				/* decimal at position one (e.g.: 2.23e-9) */
			out_gstr = g_string_append_c (out_gstr, floating_val[0]);       /* copy first digit */
		}

		int digits_so_far = 1;

		/* -- FIND EXPONENT -- */
		/* find how much the decimal has to be moved, by examining the exponent in the string and */
		/* modding it by 3 */
		exponent_val = atoi(floating_val+strlen(floating_val)-3);	/* read the last three characters */
		/* e.g. +09, or -07 */

		shift_decimal_by=(300+exponent_val) % 3;	/* added 300 to keep everything positive */

		/* -- PICK UNITS -- */
		if (exponent_val<12 && exponent_val>=9) {
			unit_mult = g_strdup("G");
		} else if (exponent_val<9 && exponent_val>=6) {
			unit_mult = g_strdup("M");
		} else if (exponent_val<6 && exponent_val>=3) {
			unit_mult = g_strdup("k");
		} else if (exponent_val<3 && exponent_val>=0) {
			unit_mult = g_strdup("");
		} else if (exponent_val<0 && exponent_val>=-3) {
			unit_mult = g_strdup("m");
		} else if (exponent_val<-3 && exponent_val>=-6) {
			unit_mult = g_strdup("u");
		} else if (exponent_val<-6 && exponent_val>=-9) {
			unit_mult = g_strdup("n");
		} else if (exponent_val<-9 && exponent_val>=-12) {
			unit_mult = g_strdup("p");
		} else {
			unit_mult = g_strdup("");   /* if parameter=0, don't use silly units */
		}

		/* -- MOVE DIGITS AROUND DECIMAL POINT -- */

		/* move the digits that will come before the decimal */
		for (i=decimal_location; i<decimal_location+shift_decimal_by; ++i) {
			out_gstr = g_string_append_c (out_gstr, floating_val[1+i]);
			++digits_so_far;
		}

		/* put in the new decimal point */
		out_gstr = g_string_append_c (out_gstr, '.');

		int space_left = width_of_column - strlen(out_gstr->str) - strlen (unit_mult) - strlen (units);

		/* copy the rest of the digits */
		for (i=shift_decimal_by+1+decimal_location; (digits_so_far<significant_digits) && (space_left>0); ++i) {
			out_gstr = g_string_append_c (out_gstr, floating_val[i]);
			++digits_so_far;
			space_left = width_of_column - strlen(out_gstr->str) - strlen (unit_mult) - strlen (units);
			/* leave space for minus sign, decimal point, and extra digit on the end too */
		}

		/* -- FINISH UP -- */


		/* -- CHECK FOR TERMINATING DECIMAL POINT -- */
		int len = strlen(out_gstr->str);
		if (out_gstr->str[len-1]=='.') {
			out_gstr = g_string_erase (out_gstr, len-1, 1);
		}

		out_gstr = g_string_append (out_gstr, unit_mult);
	}

	out_gstr = g_string_append (out_gstr, units);

	*LCD_string = g_strdup (out_gstr->str);

	g_string_free (out_gstr, TRUE);
	g_free (floating_val);
	g_free (unit_mult);
}


gchar* conditional_regex_replace (gboolean do_it, gchar* in_string, gchar* regex_string, gchar* replace_with)
{
	gchar *out;

	if (do_it) {
		GRegex *regex = g_regex_new (regex_string, 0, 0, NULL);
		out = g_regex_replace_literal (regex, in_string, -1, 0, replace_with, 0, NULL);
		g_regex_unref (regex);
	} else {
		out = g_strdup (in_string);
	}

	return out;
}