
#include "method.h"

// todo 

//

//	method_operatorOverload.h

	// method_operator_processOperatorSymbols

	// method_operator_processOperatorSymbol

	//


//	method_chaining.h



int total_libc_function				= 293;

char * libcFunctionNames[293]		= {"abort","abs","acos","asctime","asctime_r","asin","assert","atan","atan2","atexit","atof","atoi","atol","bsearch","btowc","calloc","catclose<sup>6</sup>","catgets<sup>6</sup>","catopen<sup>6</sup>","ceil","clearerr","clock","cos","cosh","ctime","ctime64","ctime_r","ctime64_r","difftime","difftime64","div","erf","erfc","exit","exp","fabs","fclose","fdopen<sup>5</sup>","feof","ferror","fflush<sup>1</sup>","fgetc<sup>1</sup>","fgetpos<sup>1</sup>","fgets<sup>1</sup>","fgetwc<sup>6</sup>","fgetws<sup>6</sup>","fileno<sup>5</sup>","floor","fmod","fopen","fprintf","fputc<sup>1</sup>","fputs<sup>1</sup>","fputwc<sup>6</sup>","fputws<sup>6</sup>","fread","free","freopen","frexp","fscanf","fseek<sup>1</sup>","fsetpos<sup>1</sup>","ftell<sup>1</sup>","fwide<sup>6</sup>","fwprintf<sup>6</sup>","fwrite","fwscanf<sup>6</sup>","gamma","getc<sup>1</sup>","getchar<sup>1</sup>","getenv","gets","getwc<sup>6</sup>","getwchar<sup>6</sup>","gmtime","gmtime64","gmtime_r","gmtime64_r","hypot","isalnum","isalpha","isascii<sup>4</sup>","isblank","iscntrl","isdigit","isgraph","islower","isprint","ispunct","isspace","isupper","iswalnum<sup>4</sup>","iswalpha<sup>4</sup>","iswblank<sup>4</sup>","iswcntrl<sup>4</sup>","iswctype<sup>4</sup>","iswdigit<sup>4</sup>","iswgraph<sup>4</sup>","iswlower<sup>4</sup>","iswprint<sup>4</sup>","iswpunct<sup>4</sup>","iswspace<sup>4</sup>","iswupper<sup>4</sup>","iswxdigit<sup>4</sup>","isxdigit<sup>4</sup>","j0","j1","jn","labs","ldexp","ldiv","localeconv","localtime","localtime64","localtime_r","localtime64_r","log","log10","longjmp","malloc","mblen","mbrlen<sup>4</sup>","mbrtowc<sup>4</sup>","mbsinit<sup>4</sup>","mbsrtowcs<sup>4</sup>","mbstowcs","mbtowc","memchr","memcmp","memcpy","memmove","memset","mktime","mktime64","modf","nextafter","nextafterl","nexttoward","nexttowardl","nl_langinfo<sup>4</sup>","perror","pow","printf","putc<sup>1</sup>","putchar<sup>1</sup>","putenv","puts","putwc<sup>6</sup>","putwchar<sup>6</sup>","qsort","quantexpd32","quantexpd64","quantexpd128","quantized32","quantized64","quantized128","samequantumd32","samequantumd64","samequantumd128","raise","rand","rand_r","realloc","regcomp","regerror","regexec","regfree","remove","rename","rewind<sup>1</sup>","scanf","setbuf","setjmp","setlocale","setvbuf","signal","sin","sinh","snprintf","sprintf","sqrt","srand","sscanf","strcasecmp","strcat","strchr","strcmp","strcoll","strcpy","strcspn","strerror","strfmon<sup>4</sup>","strftime","strlen","strncasecmp","strncat","strncmp","strncpy","strpbrk","strptime<sup>4</sup>","strrchr","strspn","strstr","strtod","strtod32","strtod64","strtod128","strtof","strtok","strtok_r","strtol","strtold","strtoul","strxfrm","swprintf","swscanf","system","tan","tanh","time","time64","tmpfile","tmpnam","toascii","tolower","toupper","towctrans","towlower<sup>4</sup>","towupper<sup>4</sup>","ungetc<sup>1</sup>","ungetwc<sup>6</sup>","va_arg","va_copy","va_end","va_start","vfprintf","vfscanf","vfwprintf<sup>6</sup>","vfwscanf","vprintf","vscanf","vsprintf","vsnprintf","vsscanf","vswprintf","vswscanf","vwprintf<sup>6</sup>","vwscanf","wcrtomb<sup>4</sup>","wcscat","wcschr","wcscmp","wcscoll<sup>4</sup>","wcscpy","wcscspn","wcsftime","wcslen","wcslocaleconv","wcsncat","wcsncmp","wcsncpy","wcspbrk","wcsptime","wcsrchr","wcsrtombs<sup>4</sup>","wcsspn","wcsstr","wcstod","wcstod32","wcstod64","wcstod128","wcstof","wcstok","wcstol","wcstold","wcstombs","wcstoul","wcsxfrm<sup>4</sup>","wctob","wctomb","wctrans","wctype<sup>4</sup>","wcwidth","wmemchr","wmemcmp","wmemcpy","wmemmove","wmemset","wprintf<sup>6</sup>","wscanf<sup>6</sup>","y0","y1","yn"};

char * libcReturnTypes[293]			= {"void","int","double","char","char","double","void","double","double","int","double","int","long","void","wint_t","void","int","char","nl_catd","double","void","clock_t","double","double","char","char","char","char","double","double","div_t","double","double","void","double","double","int","FILE","int","int","int","int","int","char","wint_t","wchar_t","int","double","double","FILE","int","int","int","wint_t","int","size_t","void","FILE","double","int","int","int","long","int","int","size_t","int","double","int","int","char","char","wint_t","wint_t","struct","struct","struct","struct","double","int","int","int","int","int","int","int","int","int","int","int","int","int","int","int","int","int","int","int","int","int","int","int","int","int","int","double","double","double","long","double","ldiv_t","struct","struct","struct","struct","struct","double","double","void","void","int","int","int","int","size_t","size_t","int","void","int","void","void","void","time_t","time64_t","double","double","long","double","long","char","void","double","int","int","int","int","int","wint_t","wint_t","void","_Decimal32","_Decimal64","_Decimal128","int","int","int","__bool__","__bool__","__bool__","int","int","int","void","int","size_t","int","void","int","int","void","int","void","int","char","int","void(*signal","double","double","int","int","double","void","int","int","char","char","int","int","char","size_t","char","int","size_t","size_t","int","char","int","char","char","char","char","size_t","char","double","_Decimal32","_Decimal64","_Decimal128","float","char","char","long","long","unsigned","size_t","int","int","int","double","double","time_t","time64_t","FILE","char","int","int","int","wint_t","wint_t","wint_t","int","wint_t","<em>var_type</em>","void","void","void","int","int","int","int","int","int","int","int","int","int","int","int","int","int","wchar_t","wchar_t","int","int","wchar_t","size_t","size_t","size_t","struct","wchar_t","int","wchar_t","wchar_t","wchar_t","wchar_t","size_t","size_t","wchar_t","double","_Decimal32","_Decimal64","_Decimal128","float","wchar_t","long","long","size_t","unsigned","size_t","int","int","wctrans_t","wctype_t","int","wchar_t","int","wchar_t","wchar_t","wchar_t","int","int","double","double","double"};



void method_sortLineNumbers( struct array * lineNumbers ) {

	int count 	= array_length( lineNumbers );

	int i		= 0;

	int j		= 0;

	void * temp;


	for (i = 0; i < (count - 1); ++i)
	{
		for (j = 0; j < count - 1 - i; ++j )
		{
			struct codeBundle * a = array_get( lineNumbers, j );

			struct codeBundle * b = array_get( lineNumbers, j + 1 );

			if ( a->lineNumber > b->lineNumber )
			{
				temp 					= lineNumbers->items[ j + 1 ];
	
				lineNumbers->items[ j + 1 ] 	= lineNumbers->items[ j ];

				lineNumbers->items[ j ] 			= temp;

			}
		}
	}
}




char * method_getReturnTypeFromDeclerationParts( struct array * methodDeclerationParts, int methodDeclerationCount ) {

	struct text * returnType 			= text_new( "" );

	//returnType[0] 				= '\0';

	for (int i = 0; i < methodDeclerationCount - 1; ++i)
	{

		char * returnPart = ( char * ) array_get( methodDeclerationParts, i );

		if( i != 0 ) {

			text_append( returnType, " " ); 
			
		} 

		if( strcmp( text_removeWhiteSpaces(returnPart), "*" ) == 0 ) {


		} else {


		}

		//printf("				------------------------return type: %s\n", returnPart );

		char * temporary	= malloc(2);//text_removeWhiteSpaces(returnPart);

		char * cleanedReturnPart = text_removeWhiteSpaces( returnPart );

		if( strlen( cleanedReturnPart ) < 3 ) {

			strcpy( temporary,  cleanedReturnPart);

		}

		text_append( returnType, cleanedReturnPart );

	}

	return returnType->value;

}

char * method_extractTemplate( lexer * currentLexer, int i, char * source ) {

	int closeTypeLexerIndex 		= lexer_findNextTokenIndex( currentLexer, i, ">" );

	int closeTypeDefinition 		= lexer_getKey( currentLexer, closeTypeLexerIndex );

	int key 						= lexer_getKey( currentLexer, i );

	char * className				= text_extractWordBeforeKey( source, key );

	int keyBeforeClassName			= text_getIndexBeforeWord( source, key - 1 );


	struct class * classInstance 	= application_getClassByClassName( allClasses, className );

	if( classInstance == NULL ) {

		//printf("Error:	class with template not found:		%s \n\n\n\n\n", className );

		return source;

	} 

	if( !classInstance->usesTemplate ) {

		//printf("Error:	This class does not have an template:	%s \n\n", classInstance->className );

		return source;

	}

	char * templateArguments = text_slice( source, key + 1, closeTypeDefinition - 1 );

	template_addArgumentValue( classInstance, templateArguments );

	char * replaceWith			= template_extractTemplateName( classInstance->template, templateArguments );


	replaceWith					= text_replace( replaceWith, "*", "_pointer" );

	replaceWith					= text_regexReplaceAll( replaceWith, "struct ", "struct ", "" );

	replaceWith					= text_removeAllWhiteSpaces( replaceWith );


	char * newName 				= text_copy( classInstance->className );

	newName 					= text_concatenate( newName, "_" );

	newName 					= text_concatenate( newName, replaceWith );

	source 						= text_replaceAt( keyBeforeClassName, closeTypeDefinition + 1, source, newName );
	

	return source;

}

char * method_extractTemplates( char * source ) {

	lexer * currentLexer		= lexer_new();

	lexer_tokenize( currentLexer, source, "<" );

	lexer_tokenize( currentLexer, source, ">" );

	lexer_sortKeys( currentLexer );


	int count 				= lexer_length( currentLexer );

	for (int i = count - 1; i >= 0; --i)
	{

		char * token 		= lexer_getToken( currentLexer, i );

		if ( strcmp( token, "<" ) == 0 ) {

			source = method_extractTemplate( currentLexer, i, source );

		}

	}

	return source;

}

void method_extractMethodNameAndReturnType( int previousKey, int key, char * source, struct method * methodInstance ) {


	char * methodDecleration 					= text_removeWhiteSpaces( text_slice( source, previousKey + 1, key - 1 ));

	struct array * methodDeclerationParts		= text_split( methodDecleration, " \t" );

	int methodDeclerationCount					= array_length( methodDeclerationParts );




	char * returnType								= method_getReturnTypeFromDeclerationParts( methodDeclerationParts, methodDeclerationCount );

	char * methodName								= text_removeWhiteSpaces( array_get( methodDeclerationParts, methodDeclerationCount - 1 ) );

	int maxOperatorNameLength					= 20;

	int methodNameLength							= strlen( methodName );

	methodInstance->isOperator					= -1;



	if( methodNameLength > 7 ) {

		char* methodNameStart = malloc( 8 + 1 );

		strncpy( methodNameStart, methodName, 8 );


		if( strcmp( methodNameStart, "operator" ) == 0 ) {

			//char * newMethodName	= malloc( strlen( methodName ) + maxOperatorNameLength );

			char * operatorFull	= malloc( methodNameLength - 7 );

			strncpy( operatorFull, methodName + 8, methodNameLength );

			char * operator			= text_removeWhiteSpaces( operatorFull );

			char * operatorName		= method_getOperatorNameByOperatorSymbol( operator );


			text * newMethodName	= text_new( "" );

			text_append( newMethodName, "operator_" );

			text_append( newMethodName, operatorName );

			methodName 						= newMethodName->value;

			methodInstance->operator		= operator;

			methodInstance->isOperator		= 1;


			printf("			this is an operator:	%s  %s %s", methodNameStart, operator, operatorName);

		}

	}
	
	printf("		%s(){}\n", methodName );

	methodInstance->returnType  				= text_copy( returnType );

	methodInstance->methodName 					= methodName;

	if( strcmp( text_removeWhiteSpaces( methodInstance->returnType ), "set" ) == 0 ) {


		methodInstance->returnType 	= "";

		methodInstance->isSetter	= true;


		struct text * newMethodName				= text_new( "" );

		text_append( newMethodName, "setter_" );

		text_append( newMethodName, methodName );

		methodInstance->methodName		= text_copy( newMethodName->value );


	}

	//printf("methodName:	%s\n\n", methodName);

}

void method_extractVariablesFromArguments( struct array * arguments, array * classesArray, struct array * variables ) {


	int argumentCount 				= array_length( arguments );

	for ( int j = 0; j < argumentCount; ++j )
	{
		char * argumentText 			= (char *) array_get( arguments, j );

		struct array * argumentParts 	= text_split( argumentText, " \t" );

		//printf("\n\n ?????????? find out if this is an variable: '%s' \n\n", argumentText);

		variable_getVariablesByArgumentParts( argumentParts, variables, classesArray );

	}

	

}

void method_processVariadicMethodArguments( struct  class * classInstance, struct method * methodInstance ) {

/*
	char * thisExpression				= malloc( 3500 );

	strcat( thisExpression, ( char * ) text_copy( classInstance->className ) );

	strcat( thisExpression, " * this" );

	array_unshift( methodInstance->arguments, thisExpression );

*/

	array * arguments = methodInstance->arguments;

	int count = array_length( arguments );

	float isVariadic		= -1;

	for (int i = 0; i < count; ++i)
	{
		char * currentArgument	= text_removeWhiteSpaces( array_get( arguments, i ) );

		if( strcmp( currentArgument, "..." ) == 0 ) {

			isVariadic = 1;

		}

	}

	if( isVariadic == 1 ) {

		array_unshift( methodInstance->arguments, "int datatypes[]" );

		array_unshift( methodInstance->arguments, "int count" );

	} 

}

void method_addThisVariableToVariables( struct  class * classInstance, array * variables ) {

	struct variable * variableInstance 	= malloc( sizeof( struct variable ) );

	variableInstance->variableName 		= "this";

	variableInstance->datatype 			= classInstance->className;

	//variableInstance->isPointer 		= 1;

	array_add( variables, variableInstance );

}


struct array * method_getArguments_new( lexer * currentLexer, int key, int i, char * source,  struct array * variables ) {

	int argumentCloseIndex				= 0;

	int count							= lexer_length( currentLexer );

	int depth							= 1;

	for (int j = i + 1; j < count; ++j)
	{
		
		char * token	= lexer_getToken( currentLexer, j );

		if( strcmp( token, "(" ) == 0 ) {

			depth++;

		}

		if( strcmp( token, ")" )  == 0 ) {

			depth--;

		}

		//printf("???????????????? token %s %i \n", token, depth);

		if( depth == 0 ) {

			argumentCloseIndex = lexer_getKey( currentLexer, j );

			break;

		}

	}

	char * argumentsText 					= text_removeWhiteSpaces( text_slice( source, key + 1, argumentCloseIndex - 1 ));

	struct array * argumentsArray			= text_split( argumentsText, "," );

	int argumentCount						= array_length( argumentsArray );



	for (int i = 0; i < argumentCount; ++i)
	{
		
		char * currentArgument 					= array_get( argumentsArray, i );

		struct array * argumentParts			= text_split( currentArgument, " \t" );

		//char * datatype 						= tools_findDatatype( argumentParts );


		if( text_contains( currentArgument, "<" ) ) {

			printf("\n\n\n\n						This is a template:			%s\n\n\n", currentArgument);

			int templateOpenKey						= text_text_findFirstCharacterIndexFromIndex( currentArgument, "<", 0  );

			int templateCloseKey					= text_text_findFirstCharacterIndexFromIndex( currentArgument, ">", 0  );


			char * templateArgument					= text_slice( currentArgument, templateOpenKey + 1, templateCloseKey - 1 );

			char * className						= text_removeWhiteSpaces( text_slice( currentArgument, 0 , templateOpenKey - 1 ) ) ;

			char * classNameClean					= tools_findDatatype( text_split( className, " \t" ) );

			struct array * parts					= text_split( currentArgument, " \t" );


			char * variableName						=  array_get( parts, array_length( parts ) - 1 );


			struct text * newVariableName			= text_new( "" );



			templateArgument					= text_regexReplaceAll( templateArgument, "struct ", "struct ", "" );

			text_removeSpaces( templateArgument );

			text_append( newVariableName, classNameClean );

			text_append( newVariableName, "_" );

			text_append( newVariableName, templateArgument );


			currentArgument = text_replaceAt( 0, templateCloseKey + 1, currentArgument, newVariableName->value );

			printf("\n\n\n\n						This is a template:			%s\n\n\n", currentArgument);

			printf("\n\n\n\n						%i -  %i	%s	%s  \n\n\n", templateOpenKey, templateCloseKey, templateArgument, classNameClean );

			array_set( argumentsArray, i, currentArgument );



			struct variable * variableInstance = malloc( sizeof( struct variable ) );

			variableInstance->variableName 	= variableName;

			variableInstance->datatype 		= newVariableName->value;

			printf("\n\n\n			add argument as variable:	variable->variableName 	 %s    variableInstance->datatype  %s\n\n\n", variableInstance->variableName, variableInstance->datatype);

			variableInstance->isPointer 	= variable_isPointer( parts );



			array_add( variables, variableInstance );

		}

		



	}



	//printf("argumentsText: %s %i\n", argumentsText, array_length(argumentsArray));

	return argumentsArray;

}



void method_addThisVariableToMethodArguments( struct  class * classInstance, struct method * methodInstance ) {

	struct text * thisExpression				= text_new( "" );

	text_append( thisExpression, classInstance->className );

	text_append( thisExpression, " * this" );

	array_unshift( methodInstance->arguments, thisExpression->value );

}


struct array * method_addArgumentsToMethod( struct  class * classInstance, struct method * methodInstance, struct array * classesArray, struct array * argumentsArray ) {

	method_extractVariablesFromArguments( methodInstance->arguments, classesArray, methodInstance->variables );

	method_addThisVariableToVariables( classInstance, methodInstance->variables );

	method_processVariadicMethodArguments( classInstance, methodInstance );

	method_addThisVariableToMethodArguments( classInstance, methodInstance );

	return methodInstance->variables;

}

struct array * method_extractArguments( lexer * currentLexer, int key, char * source, int i, struct  class * classInstance, struct method * methodInstance, struct array * classesArray ) {

	methodInstance->arguments 				= array_new();

	methodInstance->variables				= array_new();

	methodInstance->arguments				= method_getArguments_new( currentLexer, key, i, source, methodInstance->variables );

	methodInstance->isVariadic				= method_methodIsVaradic( methodInstance->arguments );

	method_addArgumentsToMethod( classInstance, methodInstance, classesArray, methodInstance->arguments );

	return methodInstance->variables;

}


int method_checkIfSymbolIsOperator( char * functionName ) {

	array * functionNameParts					= text_split( text_copy( functionName ), "_" );

	int partsCount							= array_length( functionNameParts );

	if( partsCount > 1 ) {

		char * operatorPart					= array_get( functionNameParts, 1 );

		if( strcmp( operatorPart, "operator" ) == 0 ) {

			return 1;

		}

	}

	return -1;

}

int method_methodIsVaradic( array * arguments ) {

	float isVariadic		= -1;

	int count = array_length( arguments );

	for (int i = 0; i < count; ++i)
	{
		char * currentArgument	= text_removeWhiteSpaces( array_get( arguments, i ) );

		if( strcmp( currentArgument, "..." ) == 0 ) {


			isVariadic = 1;

		}

	}

	return isVariadic;

}

char * method_composeOperatorOverloadOpeningDeclaration( char * baseClassName, char * operatorName, int leftSideIsPointer ) {

	struct text * newMethodDecleration 		= text_new( "" );

	text_append( newMethodDecleration, baseClassName );

	text_append( newMethodDecleration, "_operator_" );

	text_append( newMethodDecleration, operatorName );

	text_append( newMethodDecleration, "( " );

	if( leftSideIsPointer != 1 ) {

		text_append( newMethodDecleration, "&" );

	}

	return newMethodDecleration->value;

}

char * method_getOperatorNameByOperatorSymbol( char * symbol ) {

	if( strcmp( symbol, "+" ) == 0 ) {

		return "plus";

	}

	if( strcmp( symbol, "+=" ) == 0 ) {

		return "add";

	}

	if( strcmp( symbol, "==" ) == 0 ) {

		return "compare";

	}

	if( strcmp( symbol, "=" ) == 0 ) {

		return "is";

	}

	return symbol;

}

struct method * method_extractMethodFromSymbol( char * functionName ) {

	struct array * nameParts			= text_split( text_copy( functionName ), "_" );

	int partsCount						= array_length( nameParts );

	char * className					= array_get( nameParts, 0 );

	array_delete( nameParts, 0 );

	char * methodName 				= text_join( nameParts, "_" );

	struct class * classInstance 	= application_getClassByClassName( allClasses, className );

	if( classInstance != NULL ) {

		return method_getMethodByMethodName( classInstance, methodName );

	} else {

		return NULL;

	}

}

// exists
int method_findMethodByName( struct  class * classInstance, char * methodName ) {

	struct array * methods = classInstance->methods;

	int count	= array_length( methods );

	for (int k = 0; k < count; ++k)
	{
		struct method * methodInstance = array_get( methods, k );

		if( strcmp( methodInstance->methodName, methodName ) == 0 ) {

			return 1;

		}

	}

	return -1;

}

struct method * method_getMethodByMethodName( struct class * classInstance, char * methodName ) {

	struct array * methods 	= classInstance->methods;

	int count 				= array_length( methods );

	struct array * output 	= array_new();

	for (int i = 0; i < count; ++i)
	{
		
		struct method * currentMethod = array_get( methods, i );

		//printf("		getMethodByName  %s  %s\n", currentMethod->methodName, methodName );

		if( strcmp( currentMethod->methodName, methodName ) == 0 ) {

			return currentMethod;

		}


	}

	if( classInstance->hasExtended == 1 ) {

		return NULL;

	}

	struct array * extends		= classInstance->extends;

	int extendCount				= array_length( extends );

	for ( int i = 0; i < extendCount; ++i )
	{

		char * extendName 				= text_removeWhiteSpaces( array_get( extends, i ) );

		struct class * extendedClass	= application_getClassByClassName( allClasses, extendName );

		struct method * foundMethod 	= method_getMethodByMethodName( extendedClass, methodName );

		if( foundMethod != NULL ) {

			return foundMethod;

		}

	}


	return NULL;

}

void method_parseFirstNextMethodInChain( lexer * currentLexer, int i, char * body, int key, struct array * replacements ) {

	int keyAfterMethod 		= text_extractIndexAfterWord( body, key + 1 );

	if( body[ keyAfterMethod ] == 40 || body[keyAfterMethod + 1] == 40 ){

		void * previousToken 		= lexer_getToken( currentLexer, i - 1 );

		//                      ↓ 
		// variable->method( "" )->method()
		if ( strcmp( previousToken, ")" ) == 0 ) {

			int previousKey 			= lexer_getKey( currentLexer, i );

			int keyAfterMethod 			= text_extractIndexAfterWord( body, key + 1 );

			int argumentOpenIndex 		= text_text_findFirstCharacterIndexFromIndex( body, "(", keyAfterMethod -1 );

			int argumentCloseIndex		= text_findArgumentCloseIndex( body, (int ) keyAfterMethod - 1 );

			char * methodName			= text_removeWhiteSpaces( text_slice( body, key + 2, keyAfterMethod - 1 ) );

			//					caller				     current
			//
			// caller    'char_concatenate( a, b )->concatenate->( d )'
			int callerArgumentCloseIndex			= tools_findArgumentCloseIndexReverse( body, (int ) previousKey );

			int indexBeforeCaller					= text_getIndexBeforeWord( body, callerArgumentCloseIndex );

			char * variableName						= text_removeWhiteSpaces( text_slice( body, indexBeforeCaller, previousKey ) );

			char * callerFunctionName				= text_removeWhiteSpaces( text_slice( body, indexBeforeCaller, callerArgumentCloseIndex -1 ) );

			struct array * callerFunctionNameParts	= text_split( callerFunctionName, "_" );

			if( array_length( callerFunctionNameParts ) == 1 ) {

				// previouse "->something()" is not yet processed
				//printf("Previous '->something()' is not yet processed");

				return;

			}

			char * callerClassName					= array_get( callerFunctionNameParts, 0 );

			char * callerMethodName					= text_removeWhiteSpaces( text_slice( body, indexBeforeCaller + strlen(callerClassName) + 1, callerArgumentCloseIndex - 1 ) );

			struct class * callerClass				= application_getClassByClassName( allClasses, callerClassName );

			struct method * callerMethod			= method_getMethodByMethodName( callerClass, callerMethodName );

			if( callerMethod == NULL ) {

				//printf("method not found");

			}

			

			struct array * returnParts				= text_split( callerMethod->returnType, " \t" );

			char * returnDatatype 					= tools_findDatatype( returnParts );

			if( strcmp( returnDatatype, "void *" ) ) {

				printf( ANSI_COLOR_RED "	Error:	you are not supposed to use void pointers within method chaining.	%s()->%s() \n\n" ANSI_COLOR_RESET, callerMethodName,  methodName);


				//exit( 0 );


			}

			char * partToRemove							= text_removeWhiteSpaces( text_slice( body, previousKey, argumentOpenIndex  ) );// replace with a ','

			char * argumentsText						= text_slice( body, argumentOpenIndex + 1, argumentCloseIndex - 2  );


			printf("			Processing chain:		%s->%s() : %s		%s \n", callerClassName, callerMethodName, callerMethod->returnType, variableName);
			char * testLastIndex						= text_slice( body, (int)previousKey, argumentCloseIndex  );

			if( argumentCloseIndex == -1 ) {

				//continue;

			}

			// todo check if returnDatatype is a valid class

			if( strlen( text_removeWhiteSpaces( argumentsText ) ) == 0 ) {

				replacement_add( previousKey, argumentOpenIndex + 1, " ", replacements );

			} else {

				replacement_add( previousKey, argumentOpenIndex + 1, ", ", replacements );

			}
			
			struct text * newMethodDecleration = text_new( "" );

			text_append( newMethodDecleration, returnDatatype );

			text_append( newMethodDecleration, "_" );

			text_append( newMethodDecleration, methodName);

			text_append( newMethodDecleration, "(" );

			replacement_add( indexBeforeCaller, indexBeforeCaller, newMethodDecleration->value, replacements );

/*
			printf("---------------- newMethodDecleration = %s\n", newMethodDecleration);

			printf("---------------- methodName = %s\n", methodName);

			printf("---------------- argumentsText = %s\n", argumentsText);

			printf("---------------- testLastIndex = %s\n", testLastIndex);

			printf("---------------- partToRemove = %s\n", partToRemove);

			printf("---------------- returnType = %s\n", returnDatatype);

			printf("-------------------------**********argumentCloseIndex: %s  %s  %s  %s \n\n", callerMethodName, callerClassName, callerFunctionName, variableName);
*/
		}

		// class methodName
		//
		// char_concatenate  
		//						  ↓ 
		// char_concatenate( "	" )->concatenate( " and this end." ) 
		

	}

}



char * method_replaceMultiMethods( char * body ) {


	array * replacements 		= array_new();

	lexer * currentLexer		= lexer_new();


	lexer_tokenize( currentLexer, body, "{");

	lexer_tokenize( currentLexer, body, "}");

	lexer_tokenize( currentLexer, body, "(");

	lexer_tokenize( currentLexer, body, ")");

	lexer_tokenize( currentLexer, body, ";");

	lexer_tokenize( currentLexer, body, "=");

	lexer_tokenize( currentLexer, body, "->");

	lexer_tokenize( currentLexer, body, ".");


	lexer_add( currentLexer, 0, ";" );

	lexer_sortKeys( currentLexer );

	int count 				= lexer_length( currentLexer );

	for (int i = count - 1; i >= 0; --i)
	{

		char * token 		= lexer_getToken( currentLexer, i );

		int key 			= lexer_getKey( currentLexer, i );


		if ( strcmp( token, "->" ) == 0 ) {

			method_parseFirstNextMethodInChain( currentLexer, i, body, key, replacements );

		}
		
		if ( strcmp( token, "." ) == 0 ) {


		}


	}

	replacement_sort( replacements );

	count = array_length( replacements );

	for (int i = count - 1; i >= 0; --i){
		
		struct replacement * a = array_get( replacements, i );

		body = text_replaceAt( a->fromIndex, a->toIndex, body, a->content );

	}

	if( count > 0 ) {

		body = method_replaceMultiMethods( body );
	} 

	return body;


}


void processCallback( int key, int i, char * body, array * variables, array * functions, array * replacements ) {

	int keyAfterMethod = text_extractIndexAfterWord( body, key + 1 );

	if( body[keyAfterMethod] != 40 ) {

		// this is for callbacks  this->somecallback
		int keyAfterMethod 			= text_extractIndexAfterWord( body, key + 1 );

		int beforeMethodNameKey 	= text_getIndexBeforeWord( body, key );

		char * variableName			= text_removeWhiteSpaces( text_slice( body, beforeMethodNameKey, key -1 ) );

		char * methodName 			= text_removeWhiteSpaces( text_slice( body, key + 2, (int) keyAfterMethod - 1 ) );

		//char * test 				= text_removeWhiteSpaces( text_slice( body, beforeMethodNameKey, (int) keyAfterMethod - 1 ) );

		struct variable * variable 	= variable_getByName( variables,  variableName );

		struct class * currentClass	= application_getClassByClassName( allClasses, variable->datatype );

		if( currentClass == 0 ) {

			return;

		}

		int isMethod 				= method_findMethodByName( currentClass, methodName );

		//printf("Current class found! ------------------------- %s %s %s %i \n\n", currentClass->className, variableName, methodName, isMethod );
		// this doesnt work yet -> replace inline callback functions
		// transform 'sqlite->print'   to    'print'
		// replacement_add( (int) beforeMethodNameKey, (int) keyAfterMethod - 1, methodName, replacements );

		if( isMethod == 1 ) {

			struct method * currentMethod		= method_getMethodByMethodName( currentClass, methodName );

			struct text * newName 				= text_new( "" );


			text_append( newName, "callback_" );

			text_append( newName, currentClass->className ); 

			text_append( newName, "_" );

			text_append( newName, methodName );


			int functionExistsCheck 				= functionExists( functions, newName->value );

			if( functionExistsCheck == -1 ) {

				cloneMethodToFunction( currentMethod, functions, newName->value );

			}

			//printf("this is a callback replace '%s' with '%s' \n\n", variableName, currentClass->className);

			replacement_add( (int) beforeMethodNameKey, (int) keyAfterMethod, newName->value, replacements );

		}
		
	}

}

void method_parseFirstChainMethodCall( 	lexer * currentLexer, 
										int i, 
										char * body, 
										int currentKey, 
										char * currentToken, 
										struct array * variables, 
										struct array * replacements, 
										int methodSeparatorLength ) {

	void * nextToken 		= lexer_getToken( currentLexer, i + 1 );

	void * previousToken 	= lexer_getToken( currentLexer, i - 1 );

	//printf("this is a method: %s\n", nextToken);

	//                      ↓ 
	// variable->method( "" )->method()
	if ( strcmp( previousToken, ")" ) == 0 ) {

		return;

	}

	if ( strcmp( nextToken, "(" ) == 0 ) {

		int nextKey 						= lexer_getKey( currentLexer, i + 1 );

		char * methodName 					= text_slice( body, currentKey + methodSeparatorLength, nextKey - 1 );

		char * variableName 				= text_extractWordBeforeKey( body, currentKey );


		struct class * callerClass;

		int isVariadic	= -1;


		int beforeVariableNameKey;

		char * datatype;

		int isPointer;

		//		  |
		// this->something->someMethod();
		if( variableName[0] == 62 ) {

			int indexBeforeVariableName			= text_getIndexBeforeWord( body, currentKey );

			char * baseClassName						= text_extractWordBeforeKey( body, indexBeforeVariableName-1 );


			beforeVariableNameKey					= text_getIndexBeforeWord( body, indexBeforeVariableName-1 );

			char * propertyName 						= text_slice( body, indexBeforeVariableName + 1, currentKey -1 );

			struct variable * variableInstance 		= variable_getByName( variables,  baseClassName );

			struct class * baseClass				= application_getClassByClassName( allClasses, variableInstance->datatype );

			int propertyIndex							= class_getPropertyIndexByName( baseClass, propertyName );

			struct property * propertyInstance 		= array_get( baseClass->properties, propertyIndex );

			//callerClass 								= propertyInstance->datatype;

			datatype										= propertyInstance->datatype;

			isPointer									= propertyInstance->isPointer;

			variableName								= text_slice( body, beforeVariableNameKey, currentKey -1 );


			//printf("get property of class:		%s		%s %s  %s  ", variableInstance->datatype, propertyName, propertyInstance->datatype,  methodName);

		} else {

			beforeVariableNameKey 			= text_getIndexBeforeWord( body, currentKey );


			struct variable * variableInstance 	= variable_getByName( variables,  variableName );

			if( strcmp( variableInstance->datatype, "this_variable_is_missing" ) == 0 ) {

				printf( ANSI_COLOR_RED "Error:	Variable with name '%s' is missing, You probably need to include a file containing a class associated with this variable. " ANSI_COLOR_RESET, variableName );

				exit( 0 );

			}

			if( isalpha( variableInstance->datatype[0] ) == 0 ) {

				printf("		this is not a datatype\n\n");

				return;

			}

			isPointer				= variableInstance->isPointer;

			datatype				= variableInstance->datatype;

/*

			if ( strcmp( variableName, "test" ) == 0 ) {

				datatype = "vector2";
			}
			*/

		}


		callerClass				= application_getClassByClassName( allClasses, datatype );

		if( callerClass == NULL ) {

			printf( ANSI_COLOR_RED "ERROR:	" ANSI_COLOR_RESET "Class '%s' not found, Maybe you need to include the file containing this the class '%s'.	line number: ?? \n\n", datatype, datatype );



			exit( 0 );
			
		}

		struct method * callerMethod			= method_getMethodByMethodName( callerClass, methodName );

		if( callerMethod == NULL ) {

			printf(ANSI_COLOR_RED "ERROR:	" ANSI_COLOR_RESET "	Method '%s' not found. Class '%s' does not have an method called '%s'. \n\n", methodName, callerClass->className, methodName );

			struct property * currentProperty = class_getPropertyByName( callerClass, methodName );

			if( currentProperty == NULL ) {

				exit( 0 );



			} else {

				if( strcmp( currentProperty->type, "function" ) != 0 ) {

					exit( 0 );

				} else {

					printf("return\n\n\n\n\n");
					
					// this is an function callback 		this->somecallback();

					return;

				}

			}

			

		} else {

			//struct method * callerMethod			= array_get( methods, 0 );

			isVariadic = callerMethod->isVariadic;

			//printf("this method is isVariadic: %s   %i		%s\n\n", variableInstance->variableName, callerMethod->isVariadic, callerClass->className);

		}


		char * toReplace 								= text_slice( body, beforeVariableNameKey, nextKey - 1 );

		struct text * newFunctionDeclaration	= text_new( "" );

		//char * newFunctionDeclaration 		= malloc(1000);

		text_append( newFunctionDeclaration, datatype );

		text_append( newFunctionDeclaration, "_" );

		text_append( newFunctionDeclaration, text_copy( methodName ) );



		int openArgumentKey 					= lexer_findNextToken( currentLexer, i, "(" );

		int closeArgumentKey 					= lexer_findNextToken( currentLexer, i, ")" );

		char * argumentsText 					= text_removeWhiteSpaces( text_slice( body, openArgumentKey +1 , closeArgumentKey - 1 ) );

		struct array * argumentsArray 			= text_splitArguments( argumentsText );

		int argumentCount 						= array_length( argumentsArray );

		struct text * newFirstArgument 		= text_new( "" );

		text_append( newFirstArgument, " " ); 

		if( isPointer == -1 ) {

			text_append( newFirstArgument, "&" ); 
			
		}

		text_append( newFirstArgument, text_copy( variableName ) ); 

		if( argumentCount > 0 ) {

			text_append( newFirstArgument, ", " );	

		} else {

			text_append( newFirstArgument, " " ); 

		}

		if( isVariadic == 1 ) {

			//printf("----------------------------------============================================================ this method is variadic. %i \n\n\n\n", isVariadic);

			struct array * argumentDatatypes			= argument_getArgumentDatatypes( argumentsArray, variables );

			int argumentDatatypeCount 					= array_length( argumentDatatypes );

			char * numberOfVariadicArguments 		= text_fromNumber( argumentDatatypeCount ); 


			text_append( newFirstArgument, numberOfVariadicArguments );	

			text_append( newFirstArgument, ", " );

			text_append( newFirstArgument, "(int[" );

			text_append( newFirstArgument, numberOfVariadicArguments );

			text_append( newFirstArgument, "]){ " );	

			

			for (int k = 0; k < argumentDatatypeCount; ++k)
			{

				uintptr_t datatypeIndex	= ( uintptr_t ) array_get( argumentDatatypes, k );

				if( k != 0 ) {

					text_append( newFirstArgument, "," );

				}

				text_append( newFirstArgument, text_fromNumber( datatypeIndex ) );	

			}

			text_append( newFirstArgument, " }" );	

			text_append( newFirstArgument, ", " );	

		}


		replacement_add( beforeVariableNameKey, nextKey, newFunctionDeclaration->value, replacements );

		replacement_add( (int) openArgumentKey+ 1, (int) openArgumentKey + 1, newFirstArgument->value, replacements );

	}

}

struct property * method_getArrowRecursive( struct array * arrows, char * datatype ) {


	struct class * variableDatatypeClass 	= application_getClassByClassName( allClasses, datatype );

	struct array * properties				= variableDatatypeClass->properties;

	int propertyCount						= array_length( properties );

	char * secondVariableName 				= array_get( arrows, 0 );


	array_delete( arrows, 0 );

	for (int j = 0; j < propertyCount; ++j)
	{
		
		struct property * currentProperty	= array_get( properties, j );

		if ( strcmp( currentProperty->propertyName, secondVariableName ) == NULL )
		{

			if( array_length( arrows ) > 0 ) {

				return method_getArrowRecursive( arrows, currentProperty->datatype );

			} else {

				return currentProperty;

			}

			//return currentProperty->datatype;


		}

	}

	return NULL;

}


void method_replaceNewSymbol( 	lexer * currentLexer, 
								int i, 
								char * body, 
								int currentKey, 
								struct array * variables, 
								struct array * replacements ) {



	int classOpenArgumentKey 	= lexer_findNextToken( currentLexer, i, "(" );

	int isKey					= lexer_findPreviousKeyByToken( currentLexer, i, "=" );

	int previousLineBreak		= text_findPreviousLineBreak( body, currentKey );

	char * className 			= text_removeWhiteSpaces( text_slice( body, currentKey + 3 , classOpenArgumentKey - 1 ) );

	if( isKey > 0 ) {

		isKey--;

	}

	char * defineText  				= text_removeWhiteSpaces( text_slice( body, previousLineBreak + 1, isKey ) );

	struct array * defineParts		= text_split( defineText, " \t" );

	char * variableName				= array_get( defineParts, array_length( defineParts ) - 1 );


	char * classDefinition			= array_get( defineParts, 0 );

	if( strcmp( classDefinition, "struct" ) == 0 ) {

		classDefinition			= array_get( defineParts, 1 );

	}


	int isPointer = -1;


	if( array_length( defineParts ) == 1 ) {

		struct variable * variableInstance 	= variable_getByName( variables,  text_removeWhiteSpaces( defineText ) );

		printf("define text:		%s\n", text_removeWhiteSpaces( defineText ));

		if( variableInstance == NULL ) {

			printf("this is not a global variable\n\n");

		} else {

			printf("	This is an global variable %s  %i\n\n ", variableInstance->variableName, variableInstance->isPointer);


		}

		isPointer	= variableInstance->isPointer;

	}

	if( array_length( defineParts ) == 1 ) {

		struct array * arrows		= text_split( classDefinition, "->" );

		struct array * dotted		= text_split( classDefinition, "." );


		if( array_length( dotted ) > 1 ) {

			arrows = dotted;

		}

		if( array_length( arrows ) > 1 ) {

			char * firstVariableName = array_get( arrows, 0 );

			array_delete( arrows, 0 );

			struct variable * firstVariableInstance 	= variable_getByName( variables,  firstVariableName );

			char * variableDatatype = firstVariableInstance->datatype;


			

			struct property * currentProperty = method_getArrowRecursive( arrows, variableDatatype );

			// arrow    instance -> background


			int isKey				= lexer_findPreviousKeyByToken( currentLexer, i, "=" );

			int endOfDefinition 	= lexer_findNextTokenIndex( currentLexer, i, ";" );

			int endOfDefinitionKey	= lexer_getKey( currentLexer, endOfDefinition ) - 1;

			char * afterIs			= text_removeWhiteSpaces( text_slice( body, isKey + 1, (endOfDefinitionKey) ) );


			int from = text_indexOff( afterIs, "new", 0);

			int to 	= text_indexOff( afterIs, "(", 0);

			char * definedDatatype			= text_removeWhiteSpaces( text_slice( text_copy(afterIs), from + 3, to -1 ) );


			printf("find out between new and (  '%s'  %s \n", currentProperty->datatype, definedDatatype);

			if( !currentProperty ) {

				printf("	Setter doesnt have an defined variable of the same name.	%s\n", variableDatatype);

			}


			printf("arrow part:		%s  %s \n\n", firstVariableName, variableDatatype);


			classDefinition = currentProperty->datatype;

			isPointer = currentProperty->isPointer;


			if( strcmp( definedDatatype, classDefinition )  != NULL ) {


				classDefinition = definedDatatype; 

				isPointer		= -1;

			}

		} else {

			struct variable * firstVariableInstance 	= variable_getByName( variables,  classDefinition );

			classDefinition = firstVariableInstance->datatype;

		}



		printf("							find out datatype \n\n\n\n\n");

	} else {

		isPointer = variable_isPointer( defineParts );

	}

	className			= classDefinition;


	char * newFunctionDeclaration = text_copy( classDefinition );

	if( isPointer == -1 ) {

		newFunctionDeclaration = text_concatenate( newFunctionDeclaration, "_new" );

	} else {

		newFunctionDeclaration = text_concatenate( newFunctionDeclaration, "_newPointer" );

	}
	
	replacement_add( currentKey, classOpenArgumentKey, newFunctionDeclaration, replacements );



	// dont save this as variable:  'somefunction( new classname() )'
	if( array_length( defineParts ) > 1 && strcmp( defineText, "" ) != 0 ) {

		struct variable * variableInstance 	= malloc( sizeof( struct variable ) );

		printf("\n\n\n\n			Error:			%s  %s	\n\n\n", className, defineText);


		//className	= text_regexReplaceAll( className, "*", "*", "_");

		variableInstance->variableName 		= variableName;

		variableInstance->datatype 			= className;

		variableInstance->isPointer 		= isPointer;

		array_add( variables, variableInstance );
	}
	
}


void parsePropertySetter( struct lexer * currentLexer, int i, int key, char * body, array * variables, struct array * replacements, int separatorWidth ) {



	int nextKey	 		= lexer_getKey( currentLexer, i + 1 );

	char * propertyName		= text_removeWhiteSpaces( text_slice( body, key + separatorWidth, nextKey - 1 ) );


	int endOfDefinition 	= lexer_findNextTokenIndex( currentLexer, i, ";" );

	int endOfDefinitionKey	= lexer_getKey( currentLexer, endOfDefinition ) - 1;

	char * afterIs			= text_removeWhiteSpaces( text_slice( body, nextKey + 1, endOfDefinitionKey ) );


	char * variableName		= text_extractWordBeforeKey( body, key );

	int keyBeforeVariableName	= text_getIndexBeforeWord( body, key - 1 );


	struct variable * variableInstance	= variable_getByName( variables, variableName );

	char * variableType					= variableInstance->datatype;

	struct class * classInstance 		= application_getClassByClassName( allClasses, variableType );

	if( classInstance == NULL ) {

		printf("Error:	class with template not found:		%s \n\n\n\n\n", variableType );

		return;

	} 


		struct text * newMethodName				= text_new( "" );

		text_append( newMethodName, "setter_" );

		text_append( newMethodName, propertyName );



	struct method	* methodInstance 	= method_getMethodByMethodName( classInstance, newMethodName->value );




	if( methodInstance == NULL ) {

		printf("method not found: %s	%s \n", variableType,   newMethodName->value);

		return;

	} 


	if( !methodInstance->isSetter ) {

		return;

	}

	printf("	this is a setter\n\n\n");

	struct text * setterCallback			= text_new( "" );

	text_append( setterCallback, variableInstance->datatype );

	text_append( setterCallback, "_setter_" );

	text_append( setterCallback, propertyName );

	text_append( setterCallback, "( " );


	if( variableInstance->isPointer == -1 ) {

		text_append( setterCallback, "&" );

	}

	text_append( setterCallback, variableName);

	text_append( setterCallback, ", " );

	if( methodInstance->isVariadic == 1 ) { 

		int argumentDatatypeCount 					= 1;

		char * numberOfVariadicArguments 			= text_fromNumber( argumentDatatypeCount ); 

		text_append( setterCallback, numberOfVariadicArguments );	

		text_append( setterCallback, ", " );

		text_append( setterCallback, "(int[" );

		text_append( setterCallback, numberOfVariadicArguments );

		text_append( setterCallback, "]){ " );

		uintptr_t datatypeIndex	= ( uintptr_t ) argument_determineDatatypeOfArgument( afterIs, variables );

		if( text_contains( afterIs, "(" ) ) {

			struct array * functionNameParts 	= text_split( text_copy( afterIs ), "_" );

			int count = array_length(functionNameParts);

			if( count > 1 ) {

				char * className					= array_get( functionNameParts, 0 );

				struct class * classInstance		= application_getClassByClassName( allClasses, className );

				datatypeIndex = ( int )classInstance->classIndex;

				printf("getDatatypeof function:		%s \n\n", afterIs);

			}

		}

		text_append( setterCallback, text_fromNumber( datatypeIndex ) );	

		text_append( setterCallback, " }" );	

		text_append( setterCallback, ", " );	

	}



			text_append( setterCallback, afterIs );

	text_append( setterCallback, " );" );



	replacement_add( keyBeforeVariableName, endOfDefinitionKey + 2, setterCallback->value, replacements );

	//printf("		Parse property setter:		%s		%s   %s 	%s   %s \n\n		", variableName, propertyName, variableInstance->datatype, afterIs, setterCallback->value);

}

char * method_parse( char * body, struct array * variables, array * functions ) {



	//body = parseAndRemoveTemplateDeclaration( body );


	array * replacements 		= array_new();

	lexer * currentLexer		= lexer_new();


	lexer_tokenize( currentLexer, body, "{");

	lexer_tokenize( currentLexer, body, "}");

	lexer_tokenize( currentLexer, body, "(");

	lexer_tokenize( currentLexer, body, ")");

	lexer_tokenize( currentLexer, body, ";");

	lexer_tokenize( currentLexer, body, "=");

	lexer_tokenize( currentLexer, body, "->");

	lexer_tokenize( currentLexer, body, "\"");

	//    \"
	char * quotesWithinQuotes	= malloc(3);

	quotesWithinQuotes[0]	= 92;

	quotesWithinQuotes[1]	= 34;

	quotesWithinQuotes[2]	= 0;

	lexer_tokenize( currentLexer, body, quotesWithinQuotes);


	lexer_tokenize( currentLexer, body, ".");

	lexer_tokenize( currentLexer, body, ",");

	lexer_tokenizeRegex( currentLexer, body, "\\snew\\s", "new");

	// operators
	lexer_tokenize( currentLexer, body, "+");


	lexer_add( currentLexer, 0, ";" );

	lexer_sortKeys( currentLexer );


	int count 				= lexer_length( currentLexer );

	for (int i = count - 1; i >= 0; --i)
	{

		char * token 		= lexer_getToken( currentLexer, i );

		int key 			= lexer_getKey( currentLexer, i );


		if ( strcmp( token, "=" ) == 0 ) {

			variable_extractFromDeclaration( currentLexer, key, i, body, variables );

		}


	}

	int notWithinQuotes = 1;


	for ( int i = 0; i < count; ++i )
	{

		char * token 		= lexer_getToken( currentLexer, i );

		int key 			= lexer_getKey( currentLexer, i );


		if ( strcmp( token, "\"" ) == 0 ) {

			//int previousCharacter  = body[i-1];

			//if( previousCharacter != 92 ) {

				if( notWithinQuotes == 1 ) {

					notWithinQuotes = 0;

				} else {

					notWithinQuotes = 1;

				}

			//}

		}

		if ( strcmp( token, "new" ) == 0 && notWithinQuotes == 1 ) {

			method_replaceNewSymbol( currentLexer, i, body, key, variables, replacements );

		}

		if ( strcmp( token, "->" ) == 0 ) {

			int keyAfterMethod 		= text_extractIndexAfterWord( body, key + 1 );

			char * nextToken	 	= lexer_getToken( currentLexer, i + 1 );

			// if character after methodName = a "("
			// space after method name is not allowed.
			//body[keyAfterMethod] == 40
			if( nextToken[0]  == 40 ){

				//printf("next token ------------------------------------------- : %i\n\n", (int) ((char *)  array_get( tokens, i+1 ))[0]);

				method_parseFirstChainMethodCall( currentLexer, i, body, key, token, variables, replacements, 2 );
			
			}




		}
		
		if ( strcmp( token, "." ) == 0 ) {

			method_parseFirstChainMethodCall( currentLexer, i, body, key, token, variables, replacements, 1 );

		}


	}

	replacement_sort( replacements );


	count = array_length(replacements);

	for (int i = count - 1; i >= 0; --i){
		
		struct replacement * a = array_get( replacements, i );

		body = text_replaceAt( a->fromIndex, a->toIndex, body, a->content );

	}












	replacements 		= array_new();

	currentLexer		= lexer_new();


	lexer_tokenize( currentLexer, body, "{");

	lexer_tokenize( currentLexer, body, "}");

	lexer_tokenize( currentLexer, body, "(");

	lexer_tokenize( currentLexer, body, ")");

	lexer_tokenize( currentLexer, body, ";");

	lexer_tokenize( currentLexer, body, "=");

	lexer_tokenize( currentLexer, body, "->");

	lexer_tokenize( currentLexer, body, "\"");

	lexer_tokenize( currentLexer, body, quotesWithinQuotes);


	lexer_tokenize( currentLexer, body, ".");

	lexer_tokenize( currentLexer, body, ",");

	lexer_tokenizeRegex( currentLexer, body, "\\snew\\s", "new");

	// operators
	lexer_tokenize( currentLexer, body, "+");


	lexer_add( currentLexer, 0, ";" );

	lexer_sortKeys( currentLexer );

	count 				= lexer_length( currentLexer );

	for ( int i = 0; i < count; ++i )
	{

		char * token 		= lexer_getToken( currentLexer, i );

		int key 			= lexer_getKey( currentLexer, i );

		int keyAfterMethod 		= text_extractIndexAfterWord( body, key + 1 );

		char * nextToken	 	= lexer_getToken( currentLexer, i + 1 );

		if ( strcmp( token, "->" ) == 0 ) {

			if( nextToken[0] == 61 ) {

				parsePropertySetter( currentLexer, i, key, body, variables, replacements, 2 );

			}

		}

		if ( strcmp( token, "." ) == 0 ) {

			if( nextToken[0] == 61 ) {

				parsePropertySetter( currentLexer, i, key, body, variables, replacements, 1 );

			}

		}


	}




	for (int i = 0; i < count; ++i)
	{

		char * token 		= lexer_getToken( currentLexer, i );

		int key 			= lexer_getKey( currentLexer, i );


		if ( strcmp( token, "->" ) == 0 ) {

			processCallback( key, i, body, variables, functions, replacements );

		}


	}


	replacement_sort( replacements );


	count = array_length(replacements);

	for (int i = count - 1; i >= 0; --i){
		
		struct replacement * a = array_get( replacements, i );

		body = text_replaceAt( a->fromIndex, a->toIndex, body, a->content );

	}

	body = method_replaceMultiMethods( body );


	body = method_overloadOperators( body, variables );

	return body;

}



int method_processOperatorSymbols( 	char 	* 	body, 
								int 		currentKey, 
								char 	* 	currentToken,
								array 	* 	replacements,  
								array 	* 	variables ) {

	char * operators[3]	= { "+", "==", "+=" };

	int operatorsCount	= 3;

	for (int k = 0; k < operatorsCount; ++k)
	{
		
		char *  operatorSymbol 	= operators[k];

		int succeeded 		= method_processOperatorSymbol( 	operatorSymbol, 
																body, 
																currentKey, 
																currentToken,
																replacements, 
																variables );
		if( succeeded == 1 ) {

			return 1;

		}

	}

	return -1;

}


char * method_findLeftSideSymbol( char * body, int currentKey, int symbolLength, int * beforeVariableNameKey, array * variables ) {

	char * leftSideSymbol;

	// Handle left side
	// leftside are parentheses
	//					    ↓
	//  		 	'(     ) + ... '
	int firstCharacterBefore 			= text_findFirstCharacterReverse( body, currentKey-symbolLength-1 );

	if( firstCharacterBefore == 41 ) {

		int firstCharacterBeforeIndex 			= text_text_findFirstCharacterIndexbackwards( body, currentKey-symbolLength - 1 );

		//				 ↓	
		//  		 	'(     ) + ... '
		int argumentOpenIndex						= tools_findArgumentCloseIndexReverse( body, ( int ) firstCharacterBeforeIndex  );

		int characterBeforeParenthesisOpen 		= text_findFirstCharacterReverse( body, argumentOpenIndex -1 );

		int characterAfterPerenthesisOpen		= text_findFirstNextCharacterNotWhiteSpaceNotParenthesis( body, argumentOpenIndex );

		//					  ↓	
		//  		 	'something( ( " "    ) + ... '
		if( isalpha( characterBeforeParenthesisOpen ) ) {

			int beforeKey 					= text_getIndexBeforeWord( body, argumentOpenIndex-1 );

			leftSideSymbol 				= text_removeWhiteSpaces( text_slice( body, beforeKey, argumentOpenIndex-1 ) );

			*beforeVariableNameKey 			= beforeKey;

			return leftSideSymbol;

		//					  ↓	
		//  		 	'( ( " "    ) + ... '
		} else if( body[ characterAfterPerenthesisOpen ] == 34 ) {

			printf("these are quotes\n\n");

			leftSideSymbol = "char";

			*beforeVariableNameKey				= argumentOpenIndex;

			return leftSideSymbol;

		} 

		leftSideSymbol 									= text_removeWhiteSpaces( text_extractWordBeforeKey( body, argumentOpenIndex ) );



		struct array * leftSideSymbolParts			= text_split( text_copy( leftSideSymbol ), "_" );

		int partsCount										= array_length( leftSideSymbolParts );

		//                 partsCount = 3
		//  		 	'vector3_operator_add(     ) + ...  '
		if( partsCount > 1 ) {

			*beforeVariableNameKey				= text_getIndexBeforeWord( body, argumentOpenIndex );

		} else {


			//				 →→→→→→→→
			// 			     ↓	   ↓ 
			//  		 	'( ( ( variable   ) )  ) + ... '
			int firstCharacterIndex				= text_seekParenthesesLeftToRight( body, argumentOpenIndex );

			int keyAfterMethod 					= text_extractIndexAfterWord( body, firstCharacterIndex + 1 ) ;


			//  		 	'( ( ( variable->property   ) )  ) + ... '
			if( body[ keyAfterMethod ] == 45 && body[ keyAfterMethod + 1 ] ==  62 ) {

				int keyAfterProperty			= text_extractIndexAfterWord( body, keyAfterMethod + 1 ) ;

				leftSideSymbol					= text_removeWhiteSpaces( text_slice( body, firstCharacterIndex, keyAfterProperty ) );


			//  		 	'( ( ( variable   ) )  ) + ... '
			} else {

				leftSideSymbol							= text_removeWhiteSpaces( text_slice( body, firstCharacterIndex, keyAfterMethod - 1 ) );

			}

			*beforeVariableNameKey 				= argumentOpenIndex;

		}

	//						 	 				  ↓
	// leftSide is not opening parentheses 	'(    ) + '
	// but 						 				 ↓
	//										' someName + somename'		
	} else {

		*beforeVariableNameKey 				= text_getIndexBeforeWord( body, currentKey );

		int firstCharacterReverse			= text_text_findFirstCharacterIndexbackwards( body, currentKey-symbolLength );

		int beforeKey 							= text_getIndexBeforeWord( body, currentKey-symbolLength );

		// variableName->propertyName
		if( body[ beforeKey ] == 62 && body[ beforeKey - 1 ] ==  45 ) {

			int indexBeforeClassName	= text_getIndexBeforeWord( body, beforeKey - 1 );

			*beforeVariableNameKey 		= indexBeforeClassName;

			leftSideSymbol					= text_removeWhiteSpaces( text_slice( body, indexBeforeClassName, currentKey-1 ) );


		//  "something"	+  ...
		} else if( body[ firstCharacterReverse ] == 34 ) {

			leftSideSymbol 	= "char";

			*beforeVariableNameKey = *beforeVariableNameKey-1;

			//printf(" 		method 7\n");

		} else {

		//	printf("				--   this part			");


			int indexBeforeClassName	= text_getIndexBeforeWord( body, currentKey - symbolLength );

			*beforeVariableNameKey 		= indexBeforeClassName;

			leftSideSymbol					= text_removeWhiteSpaces( text_slice( body, indexBeforeClassName, currentKey-symbolLength ) );
/*

			leftSideSymbol				= text_removeWhiteSpaces( text_extractWordBeforeKey( body, currentKey - symbolLength - 1 ) );
*/
		}

	}

	return leftSideSymbol;

}

int method_findRightSideEndIndex( char * body, int currentKey, int symbolLength, struct array * variables ) {


	int firstNextCharacter			= text_findFirstNextCharacterNotWhiteSpace( body, currentKey + symbolLength );

	int keyAfterOperator ;

	// quoted text " sometext "
	if( body[firstNextCharacter] == 34 ) {

		keyAfterOperator 			= text_findQuoteCloseIndex( body, firstNextCharacter );

		keyAfterOperator++;

	} else {

		keyAfterOperator 		= text_extractIndexAtWhiteSpace( body, currentKey + symbolLength );

	}


	//	if       " ... + someObject->property "
	if( body[ keyAfterOperator ] == 45 && body[ keyAfterOperator + 1 ] == 62 ) {

		keyAfterOperator 		= text_extractIndexAtWhiteSpace( body, keyAfterOperator + 1  );

	}


	//								  	  ↓
	// if 		" ... + some_function_name( ... ) "
	if( body[ keyAfterOperator ] == 40 ) {

		// find 					  				        ↓
		// new key			" ... = some_function_name( ... ) "

		// check if rightSideFunction is a valid type

		char * rightSideFunctionName 				= text_removeWhiteSpaces( text_slice( body, currentKey + symbolLength, keyAfterOperator - 1 ) );

		struct array * functionNameParts			= text_split( text_copy( rightSideFunctionName ), "_" );

		int partsCount									= array_length( functionNameParts );

		if( partsCount == 1 ) {

			// find function

			//printf("		rightside is an function:	%s\n\n\n", rightSideFunctionName);

			for (int i = 0; i < total_libc_function; ++i)
			{
				
				char * libcFunctionName	= libcFunctionNames[i];

				if ( strcmp( libcFunctionName, rightSideFunctionName ) == 0 )
				{

					char * returnType		= libcReturnTypes[i];
				
					//printf("function found!! 		return type is %s\n\n\n", returnType);

					if( class_classNameIsPrimitive( returnType ) == 1 ) {

						//printf("			this is an number %s\n\n", returnType);

						return -1;

					}

				}

			}


		}


		keyAfterOperator = text_findArgumentCloseIndex( body, keyAfterOperator  );

	}


	// if the right side is opening parentheses " + ( ) "
	// (
	if( body[keyAfterOperator] == 40 ) {

		int argumentOpenIndex 					= text_text_findFirstCharacterIndexFromIndex( body, "(", currentKey  );

		int argumentCloseIndex					= text_findArgumentCloseIndex( body, ( int ) argumentOpenIndex  );

		keyAfterOperator							= argumentCloseIndex;

	}

	char * rightSideSymbol 					= text_removeWhiteSpaces( text_slice( body, currentKey + symbolLength, keyAfterOperator -1  ) );

	struct variable * rightsideVariable 	= variable_getByName( variables, rightSideSymbol );

	

	if( class_classNameIsPrimitive( rightsideVariable->datatype ) == 1 ) {

		return -1;

	}

	//*rightSideIsPointer	= rightsideVariable->isPointer;


	return keyAfterOperator;

}

int method_processOperatorSymbol( 	char 	* 	currentOperatorSymbol, 
							char 	* 	body, 
							int 		currentKey, 
							char 	* 	currentToken, 
							array * 	replacements, 
							array * 	variables ) {

	int operatorSymbolLength			= strlen( currentOperatorSymbol );

	if( body[ currentKey + operatorSymbolLength ] > 48 ) {

		return -1;

	}

	if ( strcmp( currentToken, currentOperatorSymbol ) != 0 ) {

		return -1;

	}

	int rightSideIsPointer		= 1;

	int keyAfterOperator 		= method_findRightSideEndIndex( body, currentKey, operatorSymbolLength, variables );

	char * rightSideSymbol 		= text_removeWhiteSpaces( text_slice( body, currentKey + operatorSymbolLength, keyAfterOperator ) );


	char * rightSideBaseClass	= class_getBaseClassNameBySymbol( rightSideSymbol, variables, &rightSideIsPointer );

	//printf("				RightSideSymbol:			%s\n\n				RightSideBase:			%s	%i \n\n", rightSideSymbol, rightSideBaseClass, rightSideIsPointer);


	if( keyAfterOperator == -1 ) {

		return -1;

	}

	if( operatorSymbolLength == 1 ) {

		if( body[ currentKey + 1 ] == 43 ) {

			return -1;

		}

	}

	int indexBeforeLeftSideSymbol;

	int leftSideIsPointer				= 1;

	


	char * leftSideSymbol				= method_findLeftSideSymbol( body, currentKey, operatorSymbolLength, &indexBeforeLeftSideSymbol, variables );

	char * baseClassName				= class_getBaseClassNameBySymbol( leftSideSymbol, variables, &leftSideIsPointer );


	//printf("				leftSideSymbol:	%-20s			baseClassName:		%s	 Operator:	%s	\n\n\n", leftSideSymbol, baseClassName, currentOperatorSymbol ,text_slice(body, indexBeforeLeftSideSymbol, keyAfterOperator));

	//printf("		leftSide is pointer?? %i\n\n", leftSideIsPointer);


	if( baseClassName == NULL ) {

		return -1;

	}


	if( strcmp( text_copy( baseClassName ) , "char" ) == 0 ) {

		leftSideIsPointer	= 1;

	}


	char * openingDeclaration			= class_openingDeclarationFromBaseClassName( baseClassName, currentOperatorSymbol, leftSideIsPointer );

	//printf("				openingDeclaration:		%s	  \n\n", openingDeclaration);

	if( openingDeclaration != NULL ) {

		replacement_add( indexBeforeLeftSideSymbol, indexBeforeLeftSideSymbol, openingDeclaration, replacements );


		if( rightSideIsPointer == 1 ) {

			replacement_add( (int) currentKey, (int) currentKey + operatorSymbolLength, ", ", replacements );

		} else {

			replacement_add( (int) currentKey, (int) currentKey + operatorSymbolLength, ", &", replacements );

		}

		replacement_add( (int) keyAfterOperator, (int) keyAfterOperator , ")", replacements );

		return 1;

	}

	return -1;

}


char * method_overloadOperators( char * body, struct array * variables ) {

	lexer * currentLexer				= lexer_new();

	struct array * depthArray 			= array_new();

	struct array * depthIndices 		= array_new();

	struct array * replacements 		= array_new();




	lexer_tokenize( currentLexer, body, "{");

	lexer_tokenize( currentLexer, body, "}");

	lexer_tokenize( currentLexer, body, "(");

	lexer_tokenize( currentLexer, body, ")");

	lexer_tokenize( currentLexer, body, ";");

	lexer_tokenize( currentLexer, body, "=");

	lexer_tokenize( currentLexer, body, "->");

	lexer_tokenize( currentLexer, body, ".");



	lexer_tokenize( currentLexer, body, "+");

	lexer_tokenize( currentLexer, body, "+=");

	lexer_tokenize( currentLexer, body, "==");

	lexer_add( currentLexer, 0, ";" );


	lexer_sortKeys( currentLexer );


	int count	= lexer_length( currentLexer );

	intptr_t depth	= 0;




	for ( intptr_t i = 0; i < count; ++i )
	{

		int key 				= lexer_getKey( currentLexer, i );

		char * token 			= lexer_getToken( currentLexer, i );

		if( strcmp( token, "(" ) ) {

			depth--;

		}

		if( strcmp( token, ")" ) ) {

			depth++;

		}

		array_add( depthArray, ( void * ) depth );

		array_add( depthIndices, ( void  * ) i );


	}

	// replace this with a lexer or something.
	lexer_sortKeys_separate( depthArray, depthIndices );


	for (int i = count - 1; i >= 0; --i)
	{

		intptr_t depthIndex			= ( intptr_t ) array_get( depthIndices, i );

		int key 					= lexer_getKey( currentLexer, depthIndex );

		void * token 				= lexer_getToken( currentLexer, depthIndex );

		int succeeded 				= method_processOperatorSymbols( body, key, token, replacements, variables );

		if( succeeded == 1 ) {

			break;

		}

	}


	replacement_sort( replacements );

	count = array_length(replacements);

	for (int i = count - 1; i >= 0; --i){
		
		struct replacement * a = array_get( replacements, i );

		body = text_replaceAt( a->fromIndex, a->toIndex, body, a->content );

	}

	if( count > 0 ) {

		body = method_overloadOperators( body, variables );

	} 

	return body;


}

void method_compose( struct method * currentMethod, char * className, struct array * sourceArray, struct text * classHeader ) {

	char * methodName					= currentMethod->methodName;

	struct text * methodSource 	= text_new("");



	if( strlen( currentMethod->returnType ) == 0 ) {

		text_append( methodSource, "void" );

	} else {

		text_append( methodSource, text_removeWhiteSpaces( currentMethod->returnType ) );
		
	}

	text_append( methodSource, " " );

	text_append( methodSource, className );

	text_append( methodSource, "_" );

	text_append( methodSource, methodName );

	text_append( methodSource, "( " );


	int argumentsLength	= array_length( currentMethod->arguments );

	for (int j = 0; j < argumentsLength; ++j)
	{
		char * argumentText = text_copy( array_get( currentMethod->arguments, j ) );

		if( j != 0 ) {

			text_append( methodSource, ", " );

		}

		text_append( methodSource, argumentText );

	}


	text_append( classHeader, text_copy( methodSource->value ) );

	text_append( classHeader, " );\n\n" );


	struct text * finalMethodCode = text_new("");

	text_append( finalMethodCode, text_copy( methodSource->value ) );

	text_append( finalMethodCode, " ) {" );

	text_append( finalMethodCode, text_copy( currentMethod->body ) );

	text_append( finalMethodCode, "}" );

	
	struct codeBundle * code 		= malloc( sizeof( struct codeBundle ) );

	code->lineNumber	= currentMethod->lineNumber;

	code->sourceCode	= finalMethodCode->value;

	array_add( sourceArray, code );


	text_free( methodSource );

}