// $Id: ParserUtil.cpp,v 1.17 2018/01/03 21:32:57 mkkuhner Exp $

/*
Copyright 2002-2005 Mary K. Kuhner, Peter Beerli, and Joseph Felsenstein

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

*/

/* Authors: Patrick Colacurcio, Peter Beerli, Mary Kuhner, Jon Yamato 
/* Authors: Patrick Colacurcio, Peter Beerli, Mary Kuhner, Jon Yamato 
and Joseph Felsenstein */


#include <string>
#include <cstring>
#include <cctype>
#include <iostream>

#include "Converter_ParserUtil.h"

#ifdef DMALLOC_FUNC_CHECK
#include "/usr/local/include/dmalloc.h"
#endif

using namespace std;

ParserUtil::ParserUtil() {}
ParserUtil::~ParserUtil() {}

// should this also include \r?
bool
isnewline (int ch)
{
    return (ch == '\n' || ch == '\r');
}

bool
ParserUtil::getWord (istream& is, string& buffer) const
{
    int i = 0;
    int ch;

    while ((ch=is.get()) != EOF )
    {
        //if ( (ch != ' ') && (ch != '\n') && (!isdigit(ch)) )
        if ( (ch != ' ') && !isnewline(ch) && (!isdigit(ch)) )
        {
            i = 1;
            //buffer += (char*)&ch;
            buffer += ch;
        }
        else if ( i == 1 )
            break;
    }
    if (ch == EOF)
    {
        if (i == 0)
            return false;
        else
        {
            // putback the EOF
            is.putback(ch);
            return true;
        }
    }
    if(i == 1)
    {
        is.putback(ch);
        return true;
    }
    else
        return false;
}                               // ParserUtil::getWord

bool
ParserUtil::getName (istream& is, string& buffer) const
{
    int i = 0;
    int readalphabetic = 0;
    int ch;

    while ((ch=is.get()) != EOF )
    {
        //     if ( (ch != ' ') && (ch != '\n') )
        if ( (ch != ' ') && !isnewline(ch) )
        {
            i = 1;
            if (isalpha(ch)) readalphabetic = 1;
            //  buffer += (char*)&ch;
            buffer += ch;
        }
        else if ( i == 1 )
            break;
    }
    if (ch == EOF)
    {
        if (i == 0 || readalphabetic == 0)
            return false;
        else
        {
            // putback the EOF
            is.putback(ch);
            return true;
        }
    }
    if(i == 1 && readalphabetic == 1)
    {
        is.putback(ch);
        return true;
    }
    else
        return false;
}                               // ParserUtil::getName

bool
ParserUtil::getNumber (istream& is, string& buffer) const
{
    bool seenADigit = 0;
    int ch;

    while ((ch=is.get()) != EOF )
    {
        if ( (ch != ' ') && !isnewline(ch) )
            // we've got something that's not whitespace
        {
            if(isdigit(ch))
                // hooray! it's a digit.
            {
                seenADigit = true;
                buffer += ch;
            }
            else
                // oops! not what we expected
            {
                break;
            }
        }
        else
            // we're seeing whitespace now, so we can
            // bail if we've seen digits already.
        {
            if (seenADigit)
            {
                break;
            }
        }
    }
    is.putback(ch);
    return seenADigit;
}                               // ParserUtil::getNumber

bool
ParserUtil::getToken (istream& is, string& buffer) const
{
    int i = 0;
    int ch;

    while ((ch=is.get()) != EOF )
    {
        //      if ( (ch != ' ') && (ch!= '>') && (ch != '\n') && (ch != '\t') )
        if ( (ch != ' ') && (ch!= '>') && !isnewline(ch) && (ch != '\t') )
        {
            i = 1;
            //buffer += (char*)&ch;
            buffer += ch;
        }
        else if ( i == 1 )
            break;
    }
    if (ch == EOF)
    {
        if (i == 0)
            return false;
        else
        {
            // putback the EOF
            is.putback(ch);
            return true;
        }
    }
    if(i == 1)
    {
        // putback the last character. (the first non-number)
        is.putback(ch);
        return true;
    }
    else
        return false;
}                               // ParserUtil::getToken

bool
ParserUtil::getLine (istream& is, string& buffer) const
{
    int i = 0;
    int ch;

    while ((ch=is.get()) != EOF )
    {
        //if (ch != '\n')
        if (ch != '\n' && ch != 13) // 13 - carriage return, as seen on MacOS X
        {
            i = 1;
            //        buffer += (char*)&ch;
            buffer += ch;
        }
        else if ( i == 1 )
            break;
    }
    if (ch == EOF)
    {
        if (i == 0)
            return false;
        else
        {
            // putback the EOF
            is.putback(ch);
            return true;
        }
    }
    if(i == 1)
        return true;
    else
        return false;
}                               // ParserUtil::getLine

bool
ParserUtil::skipWhiteSpace (istream& is) const
{
    int ch;

    //  Get the first non whitespace character
    while ((ch=is.get()) != EOF )
    {
        if ( (ch == ' ') || isnewline(ch) )
        {
        }
        else
        {
            // its not whitespace, so put it back
            break;
        }
    }

    // put back the last char grabbed
    is.putback(ch);
    return true;
}                               // ParserUtil::skipWhiteSpace

bool
ParserUtil::getNextNNonWhiteSpace (istream& is, string& buffer,const long& n) const
{
    long i = 0;
    int ch;

    for ( i = 0; i < n; i++ )
    {
        if ((ch=is.get()) != EOF)
        {
            // Skip the newlines and spaces
            if ( (ch!='\t') && (ch!='\n') && (ch!=' ') )
            {
                buffer += ch;
            }
            else
            {
                --i;
            }
        }
        else
        {
            is.putback(ch);
            return false;
        }
    }
    // MARYDEBUG commented in the following two lines
    // cout << "The sequence length: " << buffer.length() << endl;
    // cout << "The sequence: \"" << buffer << "\"" << endl;
    return true;
}                               // ParserUtil::getNextNNonWhiteSpace

bool
ParserUtil::getNextNChars (istream& is, string& buffer,const long& n) const
{
    long i = 0;
    int ch;

    for ( i = 0; i < n; i++ )
    {
        if ((ch=is.get()) != EOF)
        {
            // Skip the newlines and tabs
            if ( (ch!='\n') && (ch!='\t') )
            {
                buffer += ch;
            }
            else
            {
                --i;
            }
        }
        else
        {
            is.putback(ch);
            return false;
        }
    }
    //  cout << "Got the following buffer: \"" << buffer << "\"" << endl;
    return true;
}                               // ParserUtil::getNextNChars

bool
ParserUtil::skipToChar (istream& is, int searchChar) const
{
    int ch;

    //  Get the first non whitespace character
    while ((ch=is.get()) != EOF )
    {
        if ( (ch != searchChar) )
        {
        }
        else
        {
            // its not whitespace, so put it back
            break;
        }
    }

    // put back the last char grabbed
    is.putback(ch);
    return true;
}                               // ParserUtil::skipToChar

bool
ParserUtil::isFirstChar(istream& is, const string& searchString) const
{
    bool found = false;
    char* ch = new char[2];

    skipWhiteSpace(is);

    is.get(ch,2);

    if (ch[0] != EOF)
        if (strpbrk(ch,searchString.c_str()))
            found = true;

    is.putback(ch[0]);

    delete [] ch;
    return found;

} // ParserUtil::isFirstChar

//____________________________________________________________________________________
