/*
string class
by Martin Robinson
objet de manipulation de chaine de charactère
__________________________________________________
preprocessor*/
#include "stringMR.hpp"

/*-----------
methode
-----------*/

//private method
//détruire l'allocation dynamique de fstring
void stringMR::destroyFstr()
{
    baseFstr * _tmpFstr;
    while (_str)
    {
        _tmpFstr = _str->undo();
        delete _str;
        _str = _tmpFstr;
    }
}

// constructeur sans paramètre
stringMR::stringMR()
{
    _str = new nuFstr("");
}			        

// construction avec des éléments 
// d’une chaîne de caractères ex : «allo»
stringMR::stringMR(const char *s)
{
    _str = new refFstr(s);
} 	

// constructeur qui répète c, n fois
stringMR::stringMR(int n, char c)
{
    char * _tmpStr = new char[n];
    for (int i=0;i<n;i++)
        *(_tmpStr+i) = c;
    _str = new nuFstr(_tmpStr);
    delete[]_tmpStr;
}	

// constructeur de copie
stringMR::stringMR(const stringMR& ch)
{
    _str = new nuFstr(ch.c_str());
}	

// destructeur
stringMR::~stringMR()
{
    destroyFstr();
}			    

// retourne le nombre de caractères             
int stringMR::size()const
{
    return _str->size();
}   	 	

// modif. du nb. de char : l’allongement 
void stringMR::resize(int n)
{
    resize(n,0);
}   		

// se fait en copiant c, n fois
void stringMR::resize(int n, char c)
{
    assert(n >= 0);
    if (n < _str->size())
        _str = new subFstr(_str,0,n);
    else
    {
        char * _tmpStr = new char[n];
        for (int i=0;i<n;i++)
            *(_tmpStr + i) = c;
        _str = new insertNuFstr(_str,_tmpStr, _str->size());
        delete [] _tmpStr;
    }
} 	


// accès au ième caractère
const char stringMR::operator[](int pos)const
{
    return _str->at(pos);
}

const char stringMR::at(int n)const
{
    return _str->at(n);
}

    
// obtention du char * sous-jacent, un nul est présent à la fin
const char *stringMR::c_str()const
{
    static char * _tmpStr = 0;
    if (_tmpStr)
        delete [] _tmpStr;
    _tmpStr = new char[_str->size()];
    for(int i=0;i<_str->size();i++)
        *(_tmpStr+i) = _str->at(i);
    return _tmpStr;
}

// affectateur avec: stringMR, char *, char
stringMR &stringMR::operator=(const stringMR &str)
{
    _str = str._str;
    return *this;
}
stringMR &stringMR::operator=(const char *s)
{
    _str = new refFstr(s);
    return *this;
}
stringMR &stringMR::operator=(char c)
{
    _str = new nuFstr(&c);
    return *this;
} 

// concaténation avec: stringMR, char *, char
stringMR &stringMR::operator+=(const stringMR &str)
{
    _str = new insertNuFstr(_str, str.c_str(), _str->size());
    return *this;
}
stringMR &stringMR::operator+=(const char *s)
{
    _str = new insertNuFstr(_str, s, _str->size());
    return *this;
}
stringMR &stringMR::operator+=(char c)
{
    _str = new insertNuFstr(_str, &c, _str->size());
    return *this;
}   

// insertion parmi les caractères d’une chaîne
stringMR &stringMR::insert(int pos, const stringMR &str)
{
    _str = new insertNuFstr(_str, str.c_str(), pos);
    return *this;
}
stringMR &stringMR::insert(int pos, const char *s)
{
    _str = new insertNuFstr(_str, s, pos);
    return *this;
}
stringMR &stringMR::insert(int pos, int n, const char *c)
{
    _str = new insertNuFstr(_str, c, pos , pos+n);
    return *this;
}    

// copie la stringMR implicite dans 
// l’explicite et vice-versa
void stringMR::swap(stringMR& str)
{
    baseFstr * tmp = str._str;
    str._str = _str;
    _str = tmp;
}	


// recherche de chaînes et de caractères dans une chaîne {return 0;}
int stringMR::find(const stringMR &str, int pos)const
{
    int j = 0;
    for (int i = 0 ; i<_str->size();i++)
    {
        j = 0;
        while(i+j < _str->size() && _str->at(i+j) == str._str->at(j))
        {
            j++;
            if (j >= str._str->size())
                return i; //begining of the found occurence
                //return i+j; //or the end ?
        }
    }
    return 0;
}

int stringMR::find(const stringMR &str)const
{
    return find(str,0);
}

int stringMR::find(const char *s, int pos, int n)const
{
    int j = 0,
        len = 0;
    while(*(s+len))
        len++;
    if (len > n)
        len = n;
    for (int i = 0 ; i<_str->size();i++)
    {
        j = 0;
        while(i+j < _str->size() && _str->at(i+j) == *(s+j))
        {
            j++;
            if (j >= len)
                return i; 
        }
    }
    return 0;
}
int stringMR::find(const char *s, int pos)const
{
    int j = 0,
        len = 0;
    while(*(s+len))
        len++;
    for (int i = pos ; i<_str->size();i++)
    {
        j = 0;
        while(i+j < _str->size() && _str->at(i+j) == *(s+j))
        {
            j++;
            if (j >= len)
                return i; 
        }
    }
    return 0;
}

int stringMR::find(const char *s)const
{
    find(s,0);
}

// recherche d'un caractère
int stringMR::find(char c, int pos)const
{
    for (int i=pos;i<size();i++)
        if (_str->at(i) == c)
            return i;
    return 0;
}

int stringMR::find(char c)const
{
    return find(c,0);
}

// comparaison de chaînes
int stringMR::compare(const stringMR &str)const
{
    int n=0;
    while (at(n) == str.at(n) && n < size() && n < str.size())
        n++;
    return n;
}

int stringMR::compare(int pos1, int n1, const stringMR &str)const
{
    int n=0;
    if (n1> size())
        n1 = size();
    while (at(pos1+n) == str.at(n) && n < n1 && n < str.size())
        n++;
    return n;
}

int stringMR::compare(int pos1, int n1, const stringMR &str, int pos2, int n2)const
{
    int n=0;
    if (n1> size())
        n1 = size();
    if (n2> str.size())
        n2 = str.size();
    while (at(pos1+n) == str.at(pos2+n) && n < n1 && n < n2)
        n++;
    return n;
}

int stringMR::compare(const char *s)const
{
    int n=0,
        len=0;
    while(*(s+len))
        len++;
    while (at(n) == *(s+n) && n < size() && n < len)
        n++;
    return n;
}

// comparaison avec operator==
bool stringMR::operator==(const stringMR &str)const
{
    return compare(str);
}

// extraction de sous-chaîne
stringMR & stringMR::substr(int pos0, int combien)
{
    _str = new subFstr(_str,pos0,pos0+combien);
    return *this;
}

// lecture et affichage externe à la classe. Lecture jusqu’au char c
istream & getline(istream & in, stringMR &str, char n='\n')
{
    int len = str.size();
    char * tmpStr = new char[len];
    str.destroyFstr();
    in.getline(tmpStr,len,n);
    str._str = new nuFstr(tmpStr);
    return in;
}
ostream & operator<<(ostream & out, const stringMR & str)
{
    for (int i=0;i<str.size();i++)
        out << str.at(i);
    return out;
}

//petit ajout spécial
stringMR & stringMR::undo()
{
    if (_str->undo())
    {
        baseFstr * tmp = _str;
        _str = tmp->undo();
        delete tmp;
    }
    return *this;
}
