
/***************************************************************************
k   copyright            : (C) 2006 by David Nolden
   email                : david.nolden.kdevelop@art-master.de
***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 ***************************************************************************/

#include "stringhelpers.h"
#include "safetycounter.h"

namespace StringHelpers
{

void clearStr( TQString& str, int start, int end ) {
  for( int a = start; a < end; a++) str[a] = ' ';
}

bool isValidIdentifierSign( const TQChar& c ) {
	if( c.isLetter() || c.isDigit() || c == '_' ) return true;
	else return false;
}


TQString clearComments( TQString str ) {
  if( str.isEmpty() ) return "";
  
  SafetyCounter s( 1000 );
  int lastPos = 0;
  int pos;
  int len = str.length();
  while( (pos = str.find( "/*", lastPos )) != -1 ) {
    if( !s ) return str;
    int i = str.find( "*/", pos );
    if( i != -1 && i <= len - 2 ) {
      clearStr( str, pos, i+2 );
      lastPos = i+2;
      if( lastPos == len ) break;
    } else {
      break;
    }
  }
  
  lastPos = 0;
  while( (pos = str.find( "//", lastPos )) != -1 ) {
    if( !s ) return str;
    int i = str.find( "\n", pos );
    if( i != -1 && i <= len - 1 ) {
      clearStr( str, pos, i+1 );
      lastPos = i+1;
    } else {
      clearStr( str, pos, len );
      break;
    }
  }
  
  return str;
}

TQString cutTemplateParams( TQString str ) {
  int p;
  if( (p = str.find('<') ) != -1) {
    return str.left( p );
  }
  
  return str.stripWhiteSpace().replace('*',"");
}

TQPair<TQString, TQString> splitTemplateParams( TQString str ) {
  TQPair<TQString, TQString> ret;
  int p;
  if( (p = str.find('<') ) != -1) {
    ret.first = str.left( p ).stripWhiteSpace();
    ret.second = str.mid( p ).stripWhiteSpace();
  } else {
    ret.first = str.stripWhiteSpace();
  }
  
  return ret;
}

bool parenFits( TQChar c1, TQChar c2 ) {
  if( c1 == '<' && c2 == '>' ) return true;
  else if( c1 == '(' && c2 == ')' ) return true;
  else if( c1 == '[' && c2 == ']' ) return true;
  else if( c1 == '{' && c2 == '}' ) return true;
  else
    return false;
}

bool isParen( TQChar c1 ) {
  if( c1 == '<' || c1 == '>' ) return true;
  else if( c1 == '(' || c1 == ')' ) return true;
  else if( c1 == '[' || c1 == ']' ) return true;
  else if( c1 == '{' || c1 == '}' ) return true;
  else
    return false;
}

bool isTypeParen( TQChar c1 ) {
  if( c1 == '<' || c1 == '>' ) return true;
  else
    return false;
}

bool isTypeOpenParen( TQChar c1 ) {
  if( c1 == '<' ) return true;
  else
    return false;
}

bool isTypeCloseParen( TQChar c1 ) {
  if( c1 == '>' ) return true;
  else
    return false;
}

bool isLeftParen( TQChar c1 ) {
  if( c1 == '<' ) return true;
  else if( c1 == '(' ) return true;
  else if( c1 == '[' ) return true;
  else if( c1 == '{' ) return true;
  else
    return false;
}

int findClose( const TQString& str , int pos ) {
  int depth = 0;
  TQValueList<TQChar> st;
  TQChar last = ' ';
  
  for( int a = pos; a < (int)str.length(); a++) {
    switch(str[a]) {
    case '<':
    case '(':
      case '[':
        case '{':
        st.push_front( str[a] );
      depth++;
      break;
    case '>':
      if( last == '-' ) break;
    case ')':
      case ']':
        case '}':
        if( !st.isEmpty() && parenFits(st.front(), str[a]) ) {
          depth--;
          st.pop_front();
        }
      break;
    case '"':
      last = str[a];
      a++;
      while( a < (int)str.length() && (str[a] != '"' || last == '\\')) {
        last = str[a];
        a++;
      }
      continue;
      break;
    }
    
    last = str[a];
    
    if( depth == 0 ) {
      return a;
    }
  }
  
  return -1;
}

TQString tagType( const Tag& tag )
{
  if ( tag.hasAttribute( "t" ) )
  {
    TQString type = tag.attribute( "t" ).toString();
    return type;
  }
  else if ( tag.kind() == Tag::Kind_Class || tag.kind() == Tag::Kind_Namespace )
  {
    TQStringList l = tag.scope();
    l << tag.name();
    return l.join("::");
  }
  return TQString();
}

int findCommaOrEnd( const TQString& str , int pos, TQChar validEnd) {
  
  for( int a = pos; a < (int)str.length(); a++) {
    switch(str[a]) {
    case '"':
    case '(':
      case '[':
        case '{':
        case '<':
        a = findClose( str, a );
      if( a == -1 ) return str.length();
      break;
    case ')':
      case ']':
        case '}':
        case '>':
        if( validEnd != ' ' && validEnd != str[a] )
          continue;
    case ',':
      return a;
    }
  }
  
  return str.length();
}

int countExtract( TQChar c, const TQString& str ) {
  int ret  = 0;
  for( int a = 0; a < (int)str.length(); a++) {
    if( str[a] == c ) ++ret;
    switch( str[a] ) {
    case '"':
    case '(':
      case '[':
        case '{':
        case '<':
        a = findClose( str, a );
	if( a == -1 )
	  return ret;
    }
  }
  return ret;
}

TQString templateParamFromString( int num, TQString str ) {
  if( str.endsWith("::") ) str.truncate( str.length() - 2 );
  int begin = str.find('<');
  int end = str.findRev('>');
  
  if(begin == -1 || end == -1) return "";
  
  begin++;
  
  for(int a = 0; a < num; a++) {
    begin = findCommaOrEnd( str, begin );
    if( begin == (int)str.length() ) return "";
    begin++;
  }
  end = findCommaOrEnd( str, begin );
  
  if( end == (int)str.length() ) return "";
  
  return str.mid( begin, end - begin ).stripWhiteSpace();
}

TQStringList splitType( TQString str ) {
  TQStringList ret;
  int currentStart = 0;
  bool was = false;
  for( int a = 0; a < (int)str.length(); ++a ) {
    if( isLeftParen( str[a] ) ) {
      a = findClose( str, a );
      if( a == -1 ) {
      CompletionDebug::dbg() << "misformatted type: " << str << endl;
        return ret;
      }
      was = false;
    } else {
      if( str[a] == ':' ) {
        if( was ) {
          if( currentStart < a - 1 ) 
            ret << str.mid( currentStart, (a - 1) - currentStart ).stripWhiteSpace();
          currentStart = a + 1;
        }
        was = true;
      } else {
        was = false;
      }
    }
  }
  if( currentStart < (int)str.length() ) 
    ret << str.mid( currentStart, str.length() - currentStart ).stripWhiteSpace();
  return ret;
}

TQString stringMult( int count, TQString str ){
	TQString ret;
	for( int a = 0; a < count; a++ ) ret += str;
	return ret;
}

}
