/*                      QBCC Project

This source file is licensed under the GNU Public Licence which should be 
included with the distribution of this source.

*/
// Function output

#include "qbcc.h"
#include "variable.h"
#include "scanner.h"
#include "translate.h"
#include "function.h"
#include "error.h"
#include "info.h"
#include "number.h"


///////////////////
// Translates a FUNCTION call
void TranslateFUNCTION(char *retstr,char *name)
{
	func_t *tempfunc = NULL;
	char buf[128];

	// First check if it's a QB 'special' func
	tempfunc = curFUNC;
	if(FindFunction(name,TRUE))
	{
		curFUNC = tempfunc;
		if(TranslateQBFUNC(retstr,name))
			return;
	}
	else
	{
		sprintf(buf,"Function '%s' not defined",name);
		BASWarning(LineNumber,buf);
	}

	curFUNC = tempfunc;


	strcat(retstr,name);
	strcat(retstr,"(");

	TranslateFUNCTION_args(retstr);
}

///////////////////
// Translates the Functions Arg's (Never called directly)
void TranslateFUNCTION_args(char *retstr)
{
	int FuncType = FN_SUB;			// Default

	if(strcmp(LookToken->text,"(") == 0)
	{
		GetToken();
		FuncType = FN_FUNCTION;
	}
	if(LookToken->type == TK_SOFTLINE || LookToken->type == TK_NEWLINE)
	{
		strcat(retstr,")");
		return;
	}

	while(curToken->type != TK_NEWLINE && curToken->type != TK_SOFTLINE && curToken->type != TK_KEYWORD)
	{
		Expression(retstr,FALSE,FALSE,TRUE);

		GetToken();
		if(strcmp(curToken->text,",") == 0)		
			strcat(retstr,",");
		if(strcmp(curToken->text,")") == 0)
			break;
	}
	strcat(retstr,")");
}

///////////////////
// Translates the 'Special' QB functions
int TranslateQBFUNC(char *retstr,char *name)
{
	// Returns TRUE/FALSE if we parsed the function or not
	
	
	if(strcmp(name,"PRINT") == 0)						// PRINT
	{
		Function_PRINT(retstr);
		return TRUE;
	}
	if(strcmp(name,"FREEFILE") == 0)					// FREEFILE
	{
		strcat(retstr,"FREEFILE()");
		return TRUE;
	}
	if(strcmp(name,"INKEY") == 0)						// INKEY
	{
		strcat(retstr,"INKEY()");
		return TRUE;
	}
	if(strcmp(name,"OPEN") == 0)						// OPEN
	{
		Function_OPEN(retstr);
		return TRUE;
	}
	if(strcmp(name,"LINE") == 0)						// LINE
	{
		Function_LINE(retstr);
		return TRUE;
	}
	if(strcmp(name,"RND") == 0)							// RND
	{
		strcat(retstr,"RND()");
		return TRUE;
	}
	if(strcmp(name,"TIMER") == 0)						// TIMER
	{
		strcat(retstr,"TIMER()");
		return TRUE;
	}
	if(strcmp(name,"PSET") == 0)						// PSET
	{
		Function_PSET(retstr);
		return TRUE;
	}
	if(strcmp(name,"PUT") == 0)							// PUT
	{
		Function_PUT(retstr);
		return TRUE;
	}
	if(strcmp(name,"GET") == 0)							// GET
	{
		Function_GET(retstr);
		return TRUE;
	}
	if(strcmp(name,"OUT") == 0)							// OUT
	{
		Function_OUT(retstr);
		return TRUE;
	}
	if(strcmp(name,"WAIT") == 0)						// WAIT
	{
		Function_WAIT(retstr);
		return TRUE;
	}
	if(strcmp(name,"INP") == 0)							// INP
	{
		Function_INP(retstr);
		return TRUE;
	}
	if(strcmp(name,"INPUT") == 0)						// INPUT
	{
		Function_INPUT(retstr);
		return TRUE;
	}
	if(strcmp(name,"LEN") == 0)							// LEN
	{
		Function_LEN(retstr);
		return TRUE;
	}
	if(strcmp(name,"CLOSE") == 0)						// CLOSE
	{
		Function_CLOSE(retstr);
		return TRUE;
	}

	return FALSE;
}



///////////////////
// Parses 'PRINT' function
void Function_PRINT(char *retstr)
{
	char Fmt[64];
	int FilePrint = FALSE;
	char Arg[1024];
	int StringExpr = FALSE;
	int HasNewline = TRUE;
	char buf[1024];
	int TabCount = 0;

	strcpy(Fmt,"\"");
	strcpy(Arg,"");
	strcpy(buf,"");

	if(LookToken->flags & TKF_FILE)		
		FilePrint = TRUE;
	
	if(FilePrint)
	{
		strcat(retstr,"FPRINT(");
		HasNewline = FALSE;		// Don't have a newline after file number
	}
	else
		strcat(retstr,"PRINT(");
	
	while(curToken->type != TK_NEWLINE && curToken->type != TK_SOFTLINE && curToken->type != TK_KEYWORD)
	{
		strcpy(buf,"");
		StringExpr = Expression(buf,FALSE,FALSE,TRUE);
		GetToken();

		if(strcmp(buf,"") != 0)
		{
			strcat(Arg,",");
			strcat(Arg,buf);
			if(StringExpr)
				strcat(Fmt,"s");
			else
				strcat(Fmt,"i");
		}		
				
		if(strcmp(curToken->text,";") == 0)
		{
			HasNewline = FALSE;
		}

		if(strcmp(curToken->text,",") == 0)
		{
			if(!FilePrint)
				strcat(Fmt,"\\t");
			else
				if(TabCount++ != 0)
					strcat(Fmt,"\\t");
			
				HasNewline = TRUE;			
			continue;
		}
		if(curToken->type == TK_NEWLINE)
		{			
			if(HasNewline)
				strcat(Fmt,"\\n");
			break;
		}
	}

	strcat(retstr,Fmt);
	strcat(retstr,"\"");
	strcat(retstr,Arg);
	strcat(retstr,")");
}

///////////////////
// Parses 'OPEN' function
void Function_OPEN(char *retstr)
{
	strcat(retstr,"OPEN(");
	
	Expression(retstr,FALSE,FALSE,TRUE);

	Match("FOR");

	GetToken();
	strcat(retstr,",FL_");
	strcat(retstr,curToken->text);

	Match("AS");
	strcat(retstr,",");
	Expression(retstr,FALSE,FALSE,TRUE);
	
	strcat(retstr,")");
}

///////////////////
// Parses 'PSET' function
void Function_PSET(char *retstr)
{
	strcat(retstr,"PSET_(");			// DJGPP has a winge when it compiles PSET in allegro?
	
	Match("(");
	Expression(retstr,FALSE,FALSE,TRUE);
	Match(",");
	strcat(retstr,",");
	Expression(retstr,FALSE,FALSE,TRUE);
	Match(")");
	
	if(strcmp(LookToken->text,",") == 0)
	{
		Match(",");
		strcat(retstr,",");
		Expression(retstr,FALSE,FALSE,TRUE);
	}
	else
		strcat(retstr,",0");
		
	
	strcat(retstr,")");
}

///////////////////
// Parses 'LINE' function's
void Function_LINE(char *retstr)
{
	// First check which type of LINE function this is
	if(strcmp(LookToken->text,"INPUT") == 0)
	{
		Function_LINEINPUT(retstr);
		return;
	}

	// Handle graphics Line function
	strcat(retstr,"LINE(");
	
	Match("(");
	Expression(retstr,FALSE,FALSE,TRUE);				// Start X
	Match(",");
	strcat(retstr,",");
	Expression(retstr,FALSE,FALSE,TRUE);				// Start Y
	Match(")");
	Match("-");
	Match("(");
	strcat(retstr,",");
	Expression(retstr,FALSE,FALSE,TRUE);				// End X
	Match(",");
	strcat(retstr,",");
	Expression(retstr,FALSE,FALSE,TRUE);				// End Y
	Match(")");
	strcat(retstr,",");
	
	if(strcmp(LookToken->text,",") == 0)
	{
		Match(",");
		Expression(retstr,FALSE,FALSE,TRUE);			// Colour	
	
		if(strcmp(LookToken->text,",") == 0)			// Line Type
		{
			Match(",");
			GetToken();
			strcat(retstr,",LINE_");
			strcat(retstr,curToken->text);
		}
		else
			strcat(retstr,",LINE_NORMAL");
	}
	else
		strcat(retstr,"0,LINE_NORMAL");


	strcat(retstr,")");
}

///////////////////
// Parses 'LINE INPUT' function
void Function_LINEINPUT(char *retstr)
{
	int FileLine = FALSE;


	NextLine(TK_SOFTLINE);
}

///////////////////
// Parses 'PUT' function's
void Function_PUT(char *retstr)
{
	// File I/O PUT
	if(strcmp(LookToken->text,"(") != 0)
	{
		Function_FPUT(retstr);
		return;
	}

	// Graphics PUT
	strcat(retstr,"PUT(");
	Match("(");
	Expression(retstr,FALSE,FALSE,TRUE);					// X coordinate
	Match(",");
	strcat(retstr,",");
	Expression(retstr,FALSE,FALSE,TRUE);					// Y coordinate
	Match(")");	
	Match(",");
	strcat(retstr,",");
	Expression(retstr,FALSE,FALSE,TRUE);					// Image Array
	strcat(retstr,",");

	if(strcmp(LookToken->text,",") == 0)					// Action Verb
	{
		Match(",");
		GetToken();
		strcat(retstr,"IMG_");
		strcat(retstr,curToken->text);
	}
	else
		strcat(retstr,"IMG_AND");

	strcat(retstr,")");
}

///////////////////
// Parses 'PUT' (file) function
void Function_FPUT(char *retstr)
{
	NextLine(TK_SOFTLINE);
}

///////////////////
// Parses 'GET' function's
void Function_GET(char *retstr)
{
	// File I/O GET
	if(strcmp(LookToken->text,"(") != 0)
	{
		Function_FGET(retstr);
		return;
	}	
	
	// Graphics GET
	strcat(retstr,"GET(");
	Match("(");
	Expression(retstr,FALSE,FALSE,TRUE);				// Start X
	Match(",");
	strcat(retstr,",");
	Expression(retstr,FALSE,FALSE,TRUE);				// Start Y
	Match(")");
	Match("-");
	Match("(");
	strcat(retstr,",");
	Expression(retstr,FALSE,FALSE,TRUE);				// End X
	Match(",");
	strcat(retstr,",");
	Expression(retstr,FALSE,FALSE,TRUE);				// End Y
	Match(")");
	Match(",");
	strcat(retstr,",");
	Expression(retstr,FALSE,FALSE,TRUE);				// Img Array

	strcat(retstr,")");
}

///////////////////
// Parses 'GET' (file) function
void Function_FGET(char *retstr)
{
	NextLine(TK_SOFTLINE);
}


///////////////////
// Parses 'OUT' function
void Function_OUT(char *retstr)
{
	strcat(retstr,"outportb(");
	TranslateFUNCTION_args(retstr);
}

///////////////////
// Parses 'WAIT' function
void Function_WAIT(char *retstr)
{
	strcat(retstr,"while( inportb(");
	Expression(retstr,FALSE,FALSE,FALSE);
	Match(",");
	strcat(retstr,") & (");
	Expression(retstr,FALSE,FALSE,FALSE);
	
	// TODO: Xor expressions
	if(strcmp(LookToken->text,",") == 0)
	{
		Match(",");
		strcat(retstr,",");
	}

	strcat(retstr,"))");
}

///////////////////
// Parses 'INP' function
void Function_INP(char *retstr)
{
	strcat(retstr,"inportb(");
	TranslateFUNCTION_args(retstr);
}

///////////////////
// Parses 'INPUT' function's
void Function_INPUT(char *retstr)
{
	char fmt[128];	
	char promptstr[512];
	char args[4096];
	char buf[768];
	int FileInput = FALSE;
	int UseNewline = TRUE;
	int UsePrompt = FALSE;
	int StrLength = 0;
	int VarType = DefStruct->DefaultType;
	var_t Variable;

	if(strcmp(LookToken->text,"(") == 0)
	{
		// It's a INPUT$ function that returns a string
		Function_STRINPUT(retstr);
		return;
	}

	strcpy(fmt,"\"");
	strcpy(promptstr,"");
	strcpy(args,"");
	
	if(LookToken->flags & TKF_FILE)
		FileInput = TRUE;
	
	if(FileInput)
		strcat(retstr,"FINPUT(");
	else
		strcat(retstr,"INPUT(");
		

	GetToken();

	if(strcmp(curToken->text,";") == 0)
	{
		UseNewline = FALSE;
		GetToken();
	}
	if(curToken->type == TK_STRINGCONSTANT)
	{
		UsePrompt = TRUE;
		strcpy(promptstr,curToken->text);
		strcat(fmt,"p");
		GetToken();
			
		if(strcmp(curToken->text,";") == 0)
		{
			// Question mark after prompt
			promptstr[strlen(promptstr)-1] = '\0';
			strcpy(buf,promptstr);
			strcat(buf,"? \"");
			strcpy(promptstr,buf);			
		}
		else if(strcmp(curToken->text,",") != 0)
			BASError(LineNumber,"Expected ',' or ';'\n");
		
		strcat(args,",");
		GetToken();
	}	

	while(curToken->type != TK_NEWLINE
		&& curToken->type != TK_SOFTLINE
		&& curToken->type != TK_KEYWORD)
	{
		
		if(strcmp(curToken->text,",") == 0)
			strcat(args,",");

		if(curToken->type == TK_VARIABLE)
		{
			strcpy(buf,"");
			
			if(!(curToken->flags & TKF_ARGUEMENT))
				strcat(buf,"&");
			Variable = TranslateVARIABLE(buf,curToken->text);
			VarType = Variable.type;
			if(VarType == VAR_STRING)
			{
				strcat(fmt,"s");
			}
			if(VarType == VAR_INTEGER || VarType == VAR_LONG || VarType == VAR_FILE)
				strcat(fmt,"i");
			if(VarType == VAR_SINGLE || VarType == VAR_DOUBLE)
				strcat(fmt,"f");
			
			strcat(args,buf);
		}
		if(curToken->type == TK_NUMBER)
		{
			// This better be the file input function
			if(!FileInput)
				BASError(LineNumber,"Cannot use numbers!");
	
			TranslateNUMBER(args,curToken->text);
			strcat(fmt,"i");
		}

		GetToken();
	}	

	strcat(retstr,fmt);
	if(UseNewline)
		strcat(retstr,"\\n");
	strcat(retstr,"\",");
	if(UsePrompt)
		strcat(retstr,promptstr);
	strcat(retstr,args);
	strcat(retstr,")");
}

///////////////////
// Parses 'INPUT$' functions
void Function_STRINPUT(char *retstr)
{
	int FileINPUT = FALSE;
	char buf[1024];

	strcpy(buf,"");

	Match("(");

	Expression(buf,FALSE,FALSE,TRUE);
	if(strcmp(LookToken->text,",") == 0)
	{
		// It's a file INPUT$
		FileINPUT = TRUE;
		GetToken();
		strcat(buf,",");
		Expression(buf,FALSE,FALSE,TRUE);
	}

	Match(")");

	strcat(buf,")");

	if(FileINPUT)
		strcat(retstr,"FSTRINPUT(");
	else
		strcat(retstr,"STRINPUT(");

	strcat(retstr,buf);
}

///////////////////
// Parses 'LEN' function
void Function_LEN(char *retstr)
{
	char buf[1024];	
	var_t varstruct;
	
	Match("(");
	GetToken();
	strcpy(buf,"");
	
	varstruct = TranslateVARIABLE(buf,curToken->text);

	if(varstruct.type == VAR_STRING)
		strcat(retstr,"LENSTR(");
	else
		strcat(retstr,"LEN(");

	if(!(varstruct.flags & VRF_POINTER))
		strcat(retstr,"&");

	Match(")");
	strcat(buf,")");

	strcat(retstr,buf);	
}

///////////////////
// Parses 'CLOSE' function
void Function_CLOSE(char *retstr)
{
	strcat(retstr,"CLOSE(");

	if(LookToken->type == TK_NEWLINE || LookToken->type == TK_SOFTLINE || LookToken->type == TK_EOF)
		strcat(retstr,"GetINTptr(-1)");
	else
		Expression(retstr,FALSE,FALSE,TRUE);

	strcat(retstr,")");
}