/*FSTRING_____________________________________________________________________
Function Object String class
by Martin Robinson
____________________goal
string manipulation functor collection
____________________philosophy
original data is never to be modified
method only intended to be getter function
new object will reinterpret old one by simulating modification
(hello) + (world) != (helloWorld)
hello == hello
world(hello) = helloworld
(hello) stay intact,
(world) keep hello as ref and add world to the string when asked
http://en.wikipedia.org/wiki/Functional_programming
______________________________________________________________________________
PREPROCESSOR________________________________________________________________*/

#include "fstring.hpp"

/*BASE________________________________________________________________________
dynamic polymorphism in C++
need base class so all object in the collection will be recognised as the alike
contain the only 3 getter function a string really need as virtual
all other getter only need at and size to traverse the string.
following functional paradigm, no setter or mutator is declared
____________________________________________________________________________*/
//public
char baseFstr::at(const int index)const{
    static char dummy = 0;
    return dummy;
}

int baseFstr::size()const{
    return 0;
}

baseFstr * baseFstr::undo()const{
    return 0;
}

//non virtual function that rely on virtual function
/*find first occurence of the string*/
int baseFstr::find(char c)const
{
    int index = 0;
    while(at(index) != c && at(index)!=0)
        index++;
    return index;
}

int baseFstr::find(const char * str)const
{
    int index=0,
        len=0;
    while(*(str+len))
        len++;
    while(at(index))
    {
        int i=0;
        while(at(index+i)==*(str+index+i))
            if (i<len)
                i++;
            else
                return index;
        index++;
    }
    return size();
}

int baseFstr::find(const char * str, int n)const
{
    int index=0,
        len=0;
    while(*(str+len))
        len++;
    if (n < len)
        len = n;
    while(at(index))
    {
        int i=0;
        while(at(index+i)==*(str+index+i))
            if (i<len)
                i++;
            else
                return index;
        index++;
    }
    return size();
}

int baseFstr::find(baseFstr* str)const
{
    int index=0;
    while(at(index))
    {
        int i=0;
        while(at(index+i)==str->at(i))
            if (i<str->size())
                i++;
            else
                return index;
        index++;
    }
    return size();
}

/*compare two string*/
int baseFstr::cmp(const char * str)const
{
    int index=0;
    while(at(index) && *(str+index) && at(index)==*(str+index))
        index++;
    return index;
}

int baseFstr::cmp(const char * str, int n)const
{
    int index=0;
    while(at(index) && *(str+index) && index<n && at(index)==*(str+index))
        index++;
    return size();
}

int baseFstr::cmp(baseFstr * str)const
{
    int index=0;
    while(at(index) && str->at(index) && at(index) == str->at(index))
        index++;
    return size();
}

/*REFERENCE___________________________________________________________________
first string initialisation by reference... mean by reference that the object
does not copy the string but only keep the pointer of the one given, use it
with const char * or if you want a dataflow. This one is more performant
than newFstr version and less secure
____________________________________________________________________________*/
//private
/*init
store pointer
count size*/
void refFstr::init(const char * str){
    _size = 0;
    while(*(str+_size)!=0)
        _size++;
    _str = str;
}

//public
/*constructor
call init*/
refFstr::refFstr(const char * str){
    init(str);
}

/*return char at index*/
char refFstr::at(const int index)const{
//    (index >= 0 && index < _size);
    if (index < 0 && index >= _size)
        return 0;
    return *(_str+index);
}

/*return size*/
int refFstr::size()const{
    return _size;
}


/*NEW STRING__________________________________________________________________
first string initialisation by copy, this one will copy the string given, so
everything change you make to the original wont affect the object. Slower than
refFstr but more secure
____________________________________________________________________________*/
//private
/*init
count size
allocate string
copy string*/
void nuFstr::init(const char * str){
    _size = 0;
    while(*(str+_size)!=0)
        _size++;
    _str = new char[_size];
    for (int i=0;i<_size;i++)
        *(_str+i) = *(str+i);
}

//public
/*construtor
call init*/
nuFstr::nuFstr(const char * str){
    init(str);
}

/*destructor*/
nuFstr::~nuFstr(){
    delete [] _str;
}

/*return char at index*/
char nuFstr::at(const int index)const{
    if(index < 0 && index >= _size)
        return 0;
    return *(_str+index);
}

/*return size*/
int nuFstr::size()const{
    return _size;
}



/*INSERT______________________________________________________________________
insert string into another
three version is available
with already declared Fstring
with given char* by copy  more secure slow one
with given char* by ref   non secure fast one
____________________________________________________________________________*/
//version with fstr
//private
void insertSubFstr::init(baseFstr * str, baseFstr * ins, int from, int to){
    _from = from;
    _to = to;
    _str = str;
    _ins = ins;
}
//public
insertSubFstr::insertSubFstr(baseFstr * str, baseFstr * ins, int from, int to){
    init(str,ins,from,to);
}
insertSubFstr::insertSubFstr(baseFstr * str, baseFstr * ins, int index){
    init(str,ins,index,index);
}
int insertSubFstr::size()const{
    return _str->size() + _ins->size() - _to + _from;
}
char insertSubFstr::at(const int index)const{
    if(index < 0 && index >= size())
        return 0;
    if (index < _from)
        return _str->at(index);
    else if(index < _from + _ins->size())
        return _ins->at(index-_from);
    else
        return _str->at(index-_ins->size()-_from+_to);
}
baseFstr * insertSubFstr::undo()const{
    return _str;
}


//version New
//private
void insertNuFstr::init(baseFstr * str, const char * ins, int from, int to){
    _from = from;
    _to = to;
    _str = str;
    _insSize = 0;
    while(*(ins+_insSize))
        _insSize++;
    _ins = new char[_insSize];
    for(int i=0;i<_insSize;i++)
        *(_ins+i) = *(ins+i);
}
//public
insertNuFstr::insertNuFstr(baseFstr * str, const char * ins, int from, int to){
    init(str,ins,from,to);
}
insertNuFstr::insertNuFstr(baseFstr * str, const char * ins, int index){
    init(str,ins,index,index);
}
insertNuFstr::~insertNuFstr(){
    delete [] _ins;
}
int insertNuFstr::size()const{
    return _str->size() + _insSize - _to + _from;
}
char insertNuFstr::at(const int index)const{
    if(index < 0 && index >= size())
        return 0;
    if (index < _from)
        return _str->at(index);
    else if(index < _from + _insSize)
        return *(_ins+index-_from);
    else
        return _str->at(index-_insSize-_from+_to);
}
baseFstr * insertNuFstr::undo()const{
    return _str;
}


//version REF
//private
void insertRefFstr::init(baseFstr * str, const char * ins, int from, int to){
    _from = from;
    _to = to;
    _str = str;
    _insSize = 0;
    while(*(ins+_insSize))
        _insSize++;
    _ins = ins;
}
//public
insertRefFstr::insertRefFstr(baseFstr * str, const char * ins, int from, int to){
    init(str,ins,from,to);
}
insertRefFstr::insertRefFstr(baseFstr * str, const char * ins, int index){
    init(str,ins,index,index);
}
int insertRefFstr::size()const{
    return _str->size() + _insSize - _to + _from;
}
char insertRefFstr::at(const int index)const{
    if(index < 0 && index >= size())
        return 0;
    if (index < _from)
        return _str->at(index);
    else if(index < _from + _insSize)
        return *(_ins+index-_from);
    else
        return _str->at(index-_insSize-_from+_to);
}
baseFstr * insertRefFstr::undo()const{
    return _str;
}

/*TRIM________________________________________________________________________
remove all character between two index
____________________________________________________________________________*/
//private
void trimFstr::init(baseFstr * str, int from, int to){
    _from = from;
    _to = to;
    _str = str;
}
//public
trimFstr::trimFstr(baseFstr * str, int from, int to){
    init(str,from,to);
}
int trimFstr::size()const{
    return _str->size() - _to + _from;
}
char trimFstr::at(const int index)const{
    if(index < 0 && index >= size())
        return 0;
    if (index < _from)
        return _str->at(index);
    return _str->at(index+_to-_from);
}
baseFstr * trimFstr::undo()const{
    return _str;
}

/*SUB_STRING__________________________________________________________________
return sub string between two index
____________________________________________________________________________*/
//private
void subFstr::init(baseFstr * str, int from, int to){
    _str = str;
    _from = from;
    _to = to;
}
//public
subFstr::subFstr(baseFstr * str, int from, int to){
    init(str,from,to);
}
int subFstr::size()const{
    return _to-_from;
}
char subFstr::at(const int index)const{
    if(index < 0 && index >= _to-_from)
        return 0;
    return _str->at(index+_from);
}
baseFstr * subFstr::undo()const{
    return _str;
}


