/*
    Theseus - maximum likelihood superpositioning of macromolecular structures

    Copyright (C) 2004-2009 Douglas L. Theobald

    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 <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <ctype.h>
#include <unistd.h>
#include <time.h>
#include <math.h>
#include <float.h>
#include "DLTutils.h"

/* #undef __APPLE__ */
#if defined(__APPLE__)
    #if !defined(inline) 
        #define inline __inline__ 
    #endif 
    #include <CoreServices/CoreServices.h>
    #include <time.h>
    #include <sys/time.h>
    #include <sys/resource.h>
    #include <sys/types.h>
    #include <mach/mach_time.h>

    static union
    {
        Nanoseconds ns;
        UInt64 i;
    } apple_time;

    /* Returns elapsed time since the machine started up.
       Original code: Ian Ollmann <iano@apple.com> */
    UInt64
    getTime(void)
    {
        apple_time.ns = AbsoluteToNanoseconds(UpTime());
        return(apple_time.i);
    }

    double
    seconds(void)
    {
        return(1e-9 * (double) getTime());
    }
#endif


void
myfloath(void)
{
    printf("\n");
    printf(" DBL_DIG:         %d\n", DBL_DIG);
    printf(" DBL_EPSILON:     %e\n", DBL_EPSILON);
    printf(" DBL_MANT_DIG:    %d\n", DBL_MANT_DIG);
    printf(" DBL_MAX:         %e\n", DBL_MAX);
    printf(" DBL_MAX_10_EXP:  %d\n", DBL_MAX_10_EXP);
    printf(" DBL_MAX_EXP:     %d\n", DBL_MAX_EXP);
    printf(" DBL_MIN:         %e\n", DBL_MIN);
    printf(" DBL_MIN_10_EXP:  %d\n", DBL_MIN_10_EXP);
    printf(" DBL_MIN_EXP:     %d\n", DBL_MIN_EXP);

    printf(" FLT_DIG:         %d\n", FLT_DIG);
    printf(" FLT_EPSILON:     %e\n", FLT_EPSILON);
    printf(" FLT_MANT_DIG:    %d\n", FLT_MANT_DIG);
    printf(" FLT_MAX:         %e\n", FLT_MAX);
    printf(" FLT_MAX_10_EXP:  %d\n", FLT_MAX_10_EXP);
    printf(" FLT_MAX_EXP:     %d\n", FLT_MAX_EXP);
    printf(" FLT_MIN:         %e\n", FLT_MIN);
    printf(" FLT_MIN_10_EXP:  %d\n", FLT_MIN_10_EXP);
    printf(" FLT_MIN_EXP:     %d\n", FLT_MIN_EXP);

    printf(" LDBL_DIG:        %d\n",  LDBL_DIG);
    printf(" LDBL_EPSILON:    %Le\n", LDBL_EPSILON);
    printf(" LDBL_MANT_DIG:   %d\n",  LDBL_MANT_DIG);
    printf(" LDBL_MAX:        %Le\n", LDBL_MAX);
    printf(" LDBL_MAX_10_EXP: %d\n",  LDBL_MAX_10_EXP);
    printf(" LDBL_MAX_EXP:    %d\n",  LDBL_MAX_EXP);
    printf(" LDBL_MIN:        %Le\n", LDBL_MIN);
    printf(" LDBL_MIN_10_EXP: %d\n",  LDBL_MIN_10_EXP);
    printf(" LDBL_MIN_EXP:    %d\n",  LDBL_MIN_EXP); 
    printf("\n");
}


void
clrscr(void)
{
    /* char a[80]; */
    printf("\033[2J");     /* Clear the entire screen. */
    printf("\033[0;0f");   /* Move cursor to the top left hand corner */
    fflush(NULL);
}


double
*memsetd(double *dest, const double val, size_t len)
{
    register double *ptr = dest;

    while (len-- > 0)
        *ptr++ = val;

    return (dest);
}


void
write_C_mat(const double **mat, const int dim, int precision, int wrap)
{
    int i, j;

    if (wrap == 0)
        wrap = 5;

    if (precision == 0)
        precision = 6;

    printf("\n\nstatic double mat[%d][%d] = \n{\n", dim, dim);

    for (i = 0; i < dim; ++i)
    {
        printf("    {");
        for (j = 0; j < dim; ++j)
        {
            if (j < dim - 1)
                printf("% *.*f, ", precision + 1, precision, mat[i][j]);
            else
                printf("% *.*f", precision + 1, precision, mat[i][j]);

            if ((j+1) % wrap == 0 && j != dim - 1)
                printf("     \n");
        }

        if (i != dim - 1)
            printf("},\n");
        else
            printf("}\n");
    }
    printf("};\n\n");
    fflush(NULL);
}


/* automatically null terminates the string for you */
#define MYMIN(a,b) ((a) > (b) ? (b) : (a)) /* can't deal with side effects, sO DON'T USE THEM */
char
*mystrncpy(char *s1, const char *s2, size_t n)
{
    size_t         len = strlen(s2); /* minimum allocated length of s2 */
    len = MYMIN(n, len);

    strncpy(s1, s2, len);
    s1[len] = '\0';

    return(s1);
}
#undef MYMIN


/* automatically null terminates the string for you */
char
*mystrcpy(char *s1, const char *s2)
{
    size_t          len = strlen(s2);

    strncpy(s1, s2, len);
    s1[len] = '\0';

    return(s1);
}


/* This introduces a small yet convenient memory leak */
char
*mystrcat(const char *s1, const char *s2)
{
    size_t          len = strlen(s1) + strlen(s2) + 1;
    char           *s3 = malloc(len * sizeof(char));

    mystrcpy(s3, s1);
    strcat(s3, s2);

    return(s3);
}


/* both these functions destroy the string given as argument! */
void
strtolower(char *string)
{
    unsigned long   i;
    unsigned long   len = strlen(string); /* len doesn't include null term */

    for (i = 0; i < len; ++i)
        string[i] = tolower(string[i]);
}


void
strtoupper(char *string)
{
    unsigned long   i;
    unsigned long   len = strlen(string); /* len doesn't include null term */

    for (i = 0; i < len; ++i)
        string[i] = toupper(string[i]);
}


/* print a file to another file, using FILE pointers */
int
printfile(FILE *infile, FILE *outfile)
{
    int              c;

    while(1)
    {
        c = fgetc(infile);
        if (!feof(infile))
            fputc(c, outfile);
        else
            break;
    }

    return(EXIT_SUCCESS);
}


void
cpfile_name(char *newname, char *oldname)
{
    FILE            *fold = NULL;
    FILE            *fnew = NULL;
    int              c;

    /* Open source file for reading in binary mode */
    fold = fopen(oldname, "rb");
    if (fold == NULL)
    {
        perror("\n ERROR");
        fprintf(stderr, "\n ERROR37: could not open file \"%s\" for reading. \n\n", oldname);
        exit(EXIT_FAILURE);
    }

    /* Open destination file for writing in binary mode */
    fnew = fopen(newname, "wb");
    if (fnew == NULL)
    {
        fclose(fold);
        perror("\n ERROR");
        fprintf(stderr, "\n ERROR37: could not open file \"%s\" for writing. \n\n", newname);
        exit(EXIT_FAILURE);
    }

    while(1)
    {
        c = fgetc(fold);
        if (!feof(fold))
            fputc(c, fnew);
        else
            break;
    }

    fclose(fnew);
    fclose(fold);
}


void
cpfile_fp(FILE *fnew, FILE *fold)
{
    int              c;

    rewind(fnew);
    rewind(fold);

    while(1)
    {
        c = fgetc(fold);
        if (!feof(fold) && c != EOF)
            fputc(c, fnew);
        else
            break;
    }
}


/* Checks to see if a file exists */
int
CheckForFile(char *filename)
{
    FILE           *fp = NULL;

    fp = fopen(filename, "r");

    if (fp == NULL)
    {
        return(0);
    }
    else
    {
        fclose(fp);
        return(1);
    }
}


/* Determines a filename that doesn't overwrite an existing file,
   by tacking an underscore and digit onto the requested filename
   if necessary */
int
GetUniqFileNameNum(const char *fname, char *newfname)
{
    int         i;

    mystrcpy(newfname, fname);

    i = 0;
    while(CheckForFile(newfname) == 1)
    {
        ++i;
        sprintf(newfname, "%s_%d", fname, i);
    }

    return(i);
}


FILE
*myfopen(const char *fname, const char *mode)
{
    char       *newfname = malloc(FILENAME_MAX * sizeof(char));
    FILE       *fp = NULL;

    GetUniqFileNameNum(fname, newfname);
    /* printf("\n%s %s\n", newfname, fname); */

    fp = fopen(newfname, mode);

    free(newfname);

    return(fp);
}


int
isendline(int ch)
{
    if (ch == '\n' || ch == '\r' || ch == '\f')
        return(1);
    else
        return(0);
}


/* this takes DOS and Mac files as input and outputs unix files
   fixing all endlines */
FILE
*linefix(char *infile_name)
{
    FILE           *infile = NULL;
    FILE           *outfile = NULL;
    int             ch = '\0';

    infile = fopen(infile_name, "r");
    if (infile == NULL)
    {
        perror("\n ERROR");
        fprintf(stderr, "\n ERROR56: file \"%s\" not found \n", infile_name);
        exit(EXIT_FAILURE);
    }

    outfile = tmpfile();
    if (outfile == NULL)
    {
        perror("\n ERROR");
        fprintf(stderr, "\n ERROR56: temp file could not be opened \n");
        exit(EXIT_FAILURE);
    }

    do
    {
        ch = getc(infile);
        if (ch == EOF)
            break;
        if (ch == 13)    /* replace returns with nothing */
        {
            ch = getchar();
            if (ch == 10)
            {
                putchar(ch);
            }
            else if (ch == 13)
            {
                putchar(10);
                putchar(10);
            }
            else if (ch == EOF)
            {
                break;
            }
            else
            {
                putchar(10);
                putchar(ch);
            }
        }
        else
        {
            fputc(ch, outfile);
        }
    }
    while(1);

    cpfile_fp(outfile, infile);

    fclose(infile);
    fclose(outfile);
    
    return(outfile);
}


char
skipspace(FILE *afp)
{
    int ch;

    do
    {
        ch = getc(afp);
    }
    while (ch != EOF && isspace(ch));

    return(ch);
}


char
skipnum(FILE *afp)
{
    int     ch;
    do
    {
        ch = getc(afp);
    }
    while (ch != EOF && (isdigit(ch) || ch == 'e' || ch == '-' || ch == '.'));

    return(ch);
}


int
getfilesize(FILE *afp)
{
    int len;

    rewind(afp);

    len = 0;
    while(getc(afp) != EOF)
        ++len;

    rewind(afp);

    return(len);
}


char
*slurpfile(FILE *afp)
{
    char           *filestr;
    int             i, filesize;

    filesize = getfilesize(afp);

    filestr = (char *) malloc((filesize + 1) * sizeof(char));

    for(i = 0; i < filesize; ++i)
        filestr[i] = getc(afp);

    filestr[filesize] = '\0';
    rewind(afp);

    return(filestr);
}


/* takes an integer 'value' and converts it to a string */
/* char */
/* *itoa(int value, char *string, int radix) */
/* { */
/*     char            tmp[33]; */
/*     char           *tp = tmp; */
/*     int             i; */
/*     unsigned        v; */
/*     int             sign; */
/*     char           *sp = NULL; */
/*  */
/*     if (string == NULL) */
/*     { */
/*         fprintf(stderr, "\n ERROR78: string pointer passed to itoa is NULL \n\n"); */
/*         exit(EXIT_FAILURE); */
/*     } */
/*  */
/*     if ((radix > 36) || (radix <= 1)) */
/*     { */
/*         errno = EDOM; */
/*         return(NULL); */
/*     } */
/*  */
/*     sign = ((radix == 10) && (value < 0)); */
/*  */
/*     if (sign) */
/*         v = -value; */
/*     else */
/*         v = (unsigned) value; */
/*  */
/*     while (v || tp == tmp) */
/*     { */
/*         i = v % radix; */
/*         v = v / radix; */
/*         if (i < 10) */
/*             *tp++ = i + '0'; */
/*         else */
/*             *tp++ = i + 'a' - 10; */
/*     } */
/*  */
/*     sp = string; */
/*  */
/*     if (sign) */
/*         *sp++ = '-'; */
/*  */
/*     while (tp > tmp) */
/*         *sp++ = *--tp; */
/*     *sp = 0; */
/*  */
/*     return (string); */
/* } */


/* introduces a small and convenient memory leak */
char
*getroot(char *filename)
{
    char           *p;
    static char    *rootname = NULL;
    int             length = strlen(filename);

    rootname = (char *) malloc((length + 1) * sizeof(char));

    mystrncpy(rootname, filename, length);
    p = strrchr(rootname, '.'); /* find where file extension is 
                                   strrchr finds _last_ '.' */
    if (p == NULL)
    {
        return (rootname);
    }
    else
    {
        *p = '\0';
        return (rootname);
    }
}
