// $Id: stringx.h,v 1.79 2018/01/03 21:33:02 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: Peter Beerli, Mary Kuhner, Jon Yamato and Joseph Felsenstein */


#ifndef STRINGX_H
#define STRINGX_H

#include <cmath>
#include <functional>
#include <iomanip>
#include <iostream>
#include <set>
#include <sstream>
#include <string>
#include <vector>

#include "arranger_types.h"
#include "constants.h"
#include "defaults.h"
#include "types.h"
#include "ui_id.h"
#include "vectorx.h"

// needed in .h because of template functions
#ifdef DMALLOC_FUNC_CHECK
#include "/usr/local/include/dmalloc.h"
#endif

class ParamVector;
class ParamStatus;

const long DEFLINELENGTH=75;
const long DEFWIDTH=8;
const long DEFINDENT=0;
const long LINEFEED=10;

void   UpperCase(std::string&);
void   LowerCase(std::string&);
std::string ToString(char);
std::string ToString(int);
std::string ToString(long);
std::string ToString(long long);
std::string ToString(double);
std::string ToDecimalString(double);
std::string ToString(unsigned int);
std::string ToString(unsigned long);
std::string ToString(unsigned long long);
std::string ToString(bool);
std::string ToString(data_source);
std::string ToString(force_type);
std::string ToShortString(force_type);
std::string ToString(growth_type gType, bool getLongName = false);
std::string ToString(growth_scheme gScheme, bool getLongName = false);
std::string ToString(method_type method, bool getLongName = false);
std::string ToString(model_type model, bool getLongName = false);
std::string ToString(noval val);
std::string ToString(paramlistcondition par);
std::string ToString(proftype prof);
std::string ToString(priortype ptype);
std::string ToString(pstatus pstat);
std::string ToString(const ParamStatus& pstat);
std::string ToString(selection_type sType, bool getLongName = false);
std::string ToString(std::string);
std::string ToString(verbosity_type);
// specialization necessary since these three things are enums!
std::string ToString(std::vector<method_type> meths);
std::string ToString(std::vector<proftype> profs);
std::string ToString(std::vector<ParamStatus> pstats);

std::string ToString(ParamVector&); // bogus -- throws implementation_error

std::string ToStringTF(bool);  // ToString variant that returns
// "true" or "false" rather than
// "yes" or "no"
std::string ToString(UIId);
std::string ToString(std::vector<UIId> uiids);
std::string ToString(std::vector<std::vector<UIId> > uiids);

bool CaselessStrCmp(const std::string& lhs, const std::string& rhs);
bool CaselessStrCmp(const std::string& lhs, const char* rhs);
bool CaselessStrCmp(const char* lhs, const std::string& rhs);
bool CaselessStrCmp(const char* lhs, const char* rhs);

//------------------------------------------------------------------------------------

// Scott Meyers' case-insensitive string comparison code

long ciCharCompare(char c1, char c2);
long ciStringCompareImpl(const std::string& s1, const std::string& s2);
long ciStringCompare(const std::string& s1, const std::string& s2);
bool ciCharLess(char c1, char c2);
// Scott called the following ciStringCompare but then there are
// two functions of that name....
bool ciStringLess(const std::string& s1, const std::string& s2);

struct CIStringCompare : public std::binary_function<std::string, std::string, bool>
{
    bool operator()(const std::string& lhs, const std::string& rhs) const
    { return ciStringLess(lhs, rhs); }
}; // CIStringCompare struct

bool ciStringEqual(const std::string& s1, const std::string& s2);

//------------------------------------------------------------------------------------

template <class T>
std::string ToString(double number, int decimals)
{
    std::ostringstream ostr;
    ostr.precision(decimals);
    ostr << " " << number;
    std::string s(ostr.str());
    return s;
}

template <class T>
std::string ToString(vector <T> number, int decimals)
{
    std::ostringstream ostr;
    ostr.precision(decimals);
    ostr.unsetf(std::ios::scientific);
    typename vector <T> :: const_iterator nit;
    for(nit=number.begin(); nit!=number.end(); nit++)
    {
        ostr << " " << *nit;
    }
#if 0
    ostr << std::ends;
#endif
    std::string s(ostr.str());
    return s;
}

template <class T>
std::string ToString(vector <T> number)
{
    int decimals = 2;
    return ToString(number, decimals);
}

template <class T>
std::vector < string >  VecElemToString(vector <T> number)
{
    std::vector < string > svec;
    typename std::vector <T> :: iterator i;
    for(i=number.begin(); i != number.end(); i++)
        svec.push_back(ToString(*i));
    return svec;
}

template <class T>
std::vector < string >  MultisetElemToString(std::multiset <T> inputs)
{
    std::vector < string > svec;
    typename std::multiset <T> :: iterator i;
    for(i=inputs.begin(); i != inputs.end(); i++)
        svec.push_back(ToString(*i));
    return svec;
}

std::string Pretty(double number, int width=DEFWIDTH);
std::string Pretty(long number, int width=DEFWIDTH);
std::string Pretty(unsigned long number, int width=DEFWIDTH);
std::string Pretty(std::string str, int width=DEFWIDTH);

template <class T>
std::vector < string >  VecElemToString(vector <T> number, int width)
{
    std::vector < string > svec;
    typename std::vector <T> :: iterator i;
    for(i=number.begin(); i != number.end(); i++)
        svec.push_back(Pretty(*i, width));
    return svec;
}

// careful: was not able to link this function
// when its name was DoubleVecFromString(..)
bool FromString(const std::string & in, DoubleVec1d & out);
bool FromString(const std::string & in, LongVec1d & out);
bool FromString(const std::string & in, MethodTypeVec1d & out);
bool FromString(const std::string & in, ProftypeVec1d & out);
bool FromString(const std::string & in, StringVec1d & out);
bool FromString(const std::string & in, ParamVector & out); // bogus, throws
bool FromString(const std::string & in, long& out);
bool FromString(const std::string & in, double& out);
bool FromString(const std::string & in, method_type& out);

DoubleVec1d StringToDoubleVecOrBarf(const std::string& in);

// functions for making xmltags and lines of xml
std::string MakeTag(const std::string& str);
std::string MakeCloseTag(const std::string& str);
std::string MakeTagWithName(const std::string& tag, const std::string& name);
std::string MakeTagWithType(const std::string& tag, const std::string& type);
std::string MakeTagWithTypePlusPanel(const std::string& tag, const std::string& type);
std::string MakeTagWithConstraint(const std::string& tag, const std::string& constraint);
std::string MakeJustified(const std::string & str, long width=DEFLINELENGTH);
std::string MakeJustified(const char* str, long width=DEFLINELENGTH);
std::string MakeCentered(const std::string& str, long width=DEFLINELENGTH,
                         long indent=DEFINDENT, bool trunc=true);
std::string MakeCentered(const char* str, long width=DEFLINELENGTH,
                         long indent=DEFINDENT, bool trunc=true);
std::string MakeIndent(const std::string & str, unsigned long indent);
std::string MakeIndent(const char* str, unsigned long indent);

bool   StringCompare(const std::string&, const char*, long, long);
bool   StringCompare(const std::string&, const std::string&, long, long);

bool   CompareWOCase(const std::string& str1, const std::string& str2);
bool   CompareWOCase(const char* str1, const std::string& str2);
bool   CompareWOCase(const std::string& str1, const char* str2);
bool   CompareWOCase(const char* str1, const char* str2);

int    StringType(const std::string&);
std::string::size_type   GetCharacter(const std::string&, char&, long);

// free functions used to wrap tables
vector<std::string> Linewrap(vector<std::string> invec, long linelength = DEFLINELENGTH);
vector<std::string> Linewrap(std::string instring,long linelength, long indent);
vector<std::string> LinewrapCopy(vector<std::string> original, long repeat_length, long total_length = DEFLINELENGTH);
bool           IsSeparator(const std::string s);

template<class T> bool InBounds(T val, T lower, T upper);

bool IsInteger(const std::string& src);
bool IsReal(const std::string& src);

template<class T>
bool InBounds(T val, T lower, T upper)
{
    return (lower <= val && val <= upper);
} // InBounds

bool ProduceBoolOrBarf(const std::string&);
double ProduceDoubleOrBarf(const std::string&);
long ProduceLongOrBarf(const std::string&);
verbosity_type ProduceVerbosityTypeOrBarf(const std::string&);
bool StringMatchesGrowthType(const std::string&, growth_type);
growth_type ProduceGrowthTypeOrBarf(const std::string&);
growth_scheme ProduceGrowthSchemeOrBarf(const std::string&);
bool StringMatchesModelType(const std::string&, model_type);
model_type ProduceModelTypeOrBarf(const std::string&);
bool StringMatchesMethodType(const std::string&, method_type);
method_type ProduceMethodTypeOrBarf(const std::string&);
bool StringMatchesForceType(const std::string&, force_type);
force_type ProduceForceTypeOrBarf(const std::string&);
bool StringMatchesProftype(const std::string&, method_type);
proftype ProduceProftypeOrBarf(const std::string&);
ProftypeVec1d ProduceProftypeVec1dOrBarf(const std::string&);
bool StringMatchesParamstatus(const std::string&, pstatus type);
ParamStatus ProduceParamstatusOrBarf(const std::string&);
vector < ParamStatus > ProduceParamstatusVec1dOrBarf(const std::string&);
MethodTypeVec1d ProduceMethodTypeVec1dOrBarf(const std::string&);
bool StringMatchesSelectionType(const std::string&, selection_type);
selection_type ProduceSelectionTypeOrBarf(const std::string&);
DoubleVec1d ProduceDoubleVec1dOrBarf(const std::string&);
LongVec1d ProduceLongVec1dOrBarf(const std::string&);
bool StringMatchesPriortype(const std::string&, priortype type);
priortype ProducePriorTypeOrBarf(const std::string&);

// hack to replace a problme with cin.getline() [see cpp for more detail]
void MyCinGetline(std::string & sline);

char getFirstInterestingChar(const string & input);

// get a string containing the current working directory
std::string cwdString();

void StripLeadingSpaces(std::string &);
void StripTrailingSpaces(std::string &);

std::string SpacesToUnderscores(const std::string &);

// this does ToString(index+1), and you should use this
// version instead, in case we ever get users clamoring
// to have printed indices start with 0
string indexToKey(long index);

// the reverse of indexToKey
long   keyToIndex(string key);

// build a name of the form <name>_#####
std::string buildName(const std::string & prefix, const std::string & delim, size_t digits, size_t value);

#endif // STRINGX_H

//____________________________________________________________________________________
