#include "dmem/dmem.h"

#include <string.h>

#include "Symbol.hh"

/*
 * class Symbol
 */

// statics :

char const Symbol::s_empty = '\0';

char *Symbol::duplicate(char const *str) {
  size_t len;
  char *res = NULL;
  
  if( NULL!=str ) {
    len = strlen(str);
    if( len>0 ) {
      res = (char *)calloc(len+1, sizeof(char));
      strcpy(res, str);
      return res;
    }
  }
  return res;
}

char *Symbol::duplicate(char *&str, bool proxy) {
  if( proxy ) {
    char *tmp = str;
    str = NULL;
    return tmp;
  } else
    return duplicate(str);
}

char *Symbol::end(char *str) {
  if( NULL!=str )
    for( ; '\0'!=*str; ++str );
  return str;
}
    
// structors :

Symbol::Symbol()
  :is_proxy(false), m_content(NULL), m_end(NULL) {}

Symbol::Symbol(bool proxy) 
  :is_proxy(proxy), m_content(NULL), m_end(NULL) {}

Symbol::Symbol(char const *str) 
  :is_proxy(false), m_content(duplicate(str)) {
  m_end = end(m_content);
}

Symbol::Symbol(char c)
  :is_proxy(false), m_content((char *)calloc(2, sizeof(char))) {
  m_content[0] = c;
  m_content[1] = '\0';
}

Symbol::Symbol(Symbol const &other, bool proxy)
  :is_proxy(proxy), 
   m_content(duplicate(other.content(), other.is_proxy)) {
  m_end = end(m_content);
}

Symbol::~Symbol() {
  clear();
}

// modifiers :

Symbol &Symbol::operator= (Symbol const &other) {
  if( other.m_content!=m_content ) {
    clear();
    m_content = duplicate(other.content(), other.is_proxy);
    m_end = end(m_content);
  }
  return *this;
}

void Symbol::clear() {
  if( !empty() ) {
    free(m_content);
    m_content = NULL;
    m_end = NULL;
  }
}

Symbol &Symbol::operator+= (Symbol const &other) {
  Symbol tmp(operator+(other), true);
  return operator= (tmp);
}

// observers :

char const *Symbol::c_str() const {
  if( empty() )
    return &s_empty;
  else
    return m_content;
}

size_t Symbol::size() const {
  if( empty() )
    return 0;
  else
    return strlen(m_content);
}

bool Symbol::empty() const {
  return NULL==m_content;
}

int Symbol::compareTo(Symbol const &other) const {
  if( empty() )
    return other.empty()?0:-1;
  else if( other.empty() )
    return 1;
  else 
    return strcmp(m_content, other.m_content);
}

bool Symbol::operator==(Symbol const &other) const {
  return 0==compareTo(other);
}

bool Symbol::operator< (Symbol const &other) const {
  return compareTo(other)<0;
}

Symbol Symbol::operator+ (Symbol const &other) const {
  if( empty() )
    return Symbol(other, true);
  else if( other.empty() )
    return Symbol(*this, true);
  else {
    size_t lme = size(), lyou = other.size();
    Symbol res(true);
    res.m_content = (char *)calloc(lme+lyou+1, sizeof(char));
    res.m_end = res.m_content+lme+lyou+1;
    char *i = res.m_content;
    char const *j;

    for(j=m_content ; (*i=*j)!='\0'; ++i, ++j );
    for(j=other.m_content ; (*i=*j)!='\0'; ++i, ++j );
    return res;
  }
}

size_t Symbol::find_first_of(size_t pos, char c) const {
  size_t const endp = size();

  for( ;endp>pos && m_content[pos]!=c; ++pos );
  return pos;
}

size_t Symbol::find_first_not_of(size_t pos, char c) const {
  size_t const endp = size();

  for( ;endp>pos && m_content[pos]==c; ++pos );
  return pos;
}

Symbol Symbol::subSymbol(size_t from) const {
  return subSymbol(from, size());
}

Symbol Symbol::subSymbol(size_t from, size_t to) const {
  if( to>from ) {
    Symbol res(true);
    size_t len = to-from;
    res.m_content = (char *)calloc(len, sizeof(char));
    res.m_end = res.m_content+len;
    char *i = res.m_content;
   
    for( ; from<to; ++from, ++i )
      *i = m_content[from];
    *i = '\0';
    return res;
  } else
    return Symbol(true);
}

// related :

Symbol operator+ (char *a, Symbol const &b) {
  Symbol tmp(a, true);
  tmp += b;
  return tmp;
}
