/*
    Raydium - CQFD Corp.
    http://raydium.org/
    Released under both BSD license and Lesser GPL library license.
    See "license.txt" file.
*/

#ifndef DONT_INCLUDE_HEADERS
#include "index.h"
#else
#include "headers/console.h"
#endif

// proto
void raydium_console_exec_last_command(void);
void raydium_console_history_add(char *str);


void raydium_console_init(void)
{
int i;
FILE *fp;
char line[RAYDIUM_MAX_NAME_LEN];

raydium_console_pos=0;
raydium_console_inc=0;
raydium_console_config_max=50;
raydium_console_config_speed=3;
raydium_init_cli_option_default("consoletexture",raydium_console_config_texture,"rgb(0.2,0.2,0.2)");
raydium_init_cli_option_default("consolefont",raydium_console_config_font,"font2.tga");
raydium_console_line_last=-1;
raydium_console_cursor_blink=0;
for(i=0;i<RAYDIUM_CONSOLE_MAX_LINES;i++)
 raydium_console_lines[i][0]=0;
raydium_console_get_string[0]=0;
raydium_console_get_string_last[0]=0;

raydium_init_cli_option_default("history",raydium_console_history_filename,
                                raydium_file_home_path("raydium_history"));

for(i=0;i<RAYDIUM_CONSOLE_MAX_HISTORY;i++)
    raydium_console_history[i][0]=0;
raydium_console_history_index_current=-1;
raydium_console_history_index=0;

fp=fopen(raydium_console_history_filename,"rt");
if(fp)
    {
    while(fgets(line,RAYDIUM_MAX_NAME_LEN,fp))
        {
        line[strlen(line)-1]=0;
        raydium_console_history_add(line);
        }
    fclose(fp);
    }
}


void raydium_console_history_save(void)
{
int i;
FILE *fp;
char last[RAYDIUM_MAX_NAME_LEN];

last[0]=0;

fp=fopen(raydium_console_history_filename,"wt");
if(!fp)
    {
    raydium_log("console: error: cannot save history file ('%s')",raydium_console_history_filename);
    return;
    }

for(i=0;i<raydium_console_history_index;i++)
    if(strcmp(raydium_console_history[i],last))
        {
        strcpy(last,raydium_console_history[i]);
        fprintf(fp,"%s\n",raydium_console_history[i]);
        }
fclose(fp);
}

// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// Now DISABLED,
// use raydium_console_gets_callback fptr instead.
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
int raydium_console_gets(char *where)
{
raydium_log("ERROR: raydium_console_gets is now DISABLED ! See API doc.");
// always here for compat' only, do not use.
/*if(strlen(raydium_console_get_string_last))
 {
 strcpy(where,raydium_console_get_string_last);
 raydium_console_get_string_last[0]=0;
 return 1;
 } else*/ return 0;
}



void raydium_console_history_previous(void)
{
raydium_console_history_index_current--;

if(raydium_console_history_index_current<0)
    {
    raydium_console_history_index_current=0;
    return;
    }
strcpy(raydium_console_get_string,raydium_console_history[raydium_console_history_index_current]);
}

void raydium_console_history_next(void)
{
raydium_console_history_index_current++;

if(raydium_console_history_index_current>=raydium_console_history_index)
    {
    raydium_console_history_index_current=raydium_console_history_index;
    strcpy(raydium_console_get_string,"");
    return;
    }
strcpy(raydium_console_get_string,raydium_console_history[raydium_console_history_index_current]);
}


void raydium_console_history_add(char *str)
{
int i;


if(raydium_console_history_index==RAYDIUM_CONSOLE_MAX_HISTORY)
    {
    raydium_console_history_index_current=raydium_console_history_index;
    /*
    printf("-----\n");
    for(i=0;i<RAYDIUM_CONSOLE_MAX_HISTORY;i++)
        printf("%s\n",raydium_console_history[i]);
    */

    for(i=0;i<RAYDIUM_CONSOLE_MAX_HISTORY-1;i++)
        strcpy(raydium_console_history[i],raydium_console_history[i+1]);

    strcpy(raydium_console_history[RAYDIUM_CONSOLE_MAX_HISTORY-1],str);
    /*
    printf("-----\n");
    for(i=0;i<RAYDIUM_CONSOLE_MAX_HISTORY;i++)
        printf("%s\n",raydium_console_history[i]);
    */
    return;
    }
raydium_console_history_index_current=raydium_console_history_index+1;
strcpy(raydium_console_history[raydium_console_history_index],str);
raydium_console_history_index++;
}


void raydium_console_exec_script(char *file)
{
FILE *fp;
char command[RAYDIUM_MAX_NAME_LEN];

if(!raydium_console_gets_callback)
    {
    raydium_log("ERROR: console: script: no command callback is defined, aborded.");
    return;
    }

fp=raydium_file_fopen(file,"rt");
if(!fp)
    {
    raydium_log("ERROR: console: script: file not found \"%s\"",file);
    return;
    }
while(fgets(command,RAYDIUM_MAX_NAME_LEN,fp))
    {
    strcpy(raydium_console_get_string_last,command);
    raydium_console_exec_last_command();
    }

fclose(fp);
}


void raydium_console_exec_last_command(void)
{
int treated=0;
void (*f)(char *);
char temp[RAYDIUM_MAX_NAME_LEN];

raydium_console_get_string_last[strlen(raydium_console_get_string_last)-1]=0;
raydium_console_history_add(raydium_console_get_string_last);

if(raydium_console_get_string_last[0]=='!')
    {
    treated=1;
    raydium_console_exec_script(raydium_console_get_string_last+1);
    }

if(raydium_console_get_string_last[0]=='>')
    {
    treated=1;
#ifdef PHP_SUPPORT
    raydium_php_exec(raydium_console_get_string_last+1);
#else
    raydium_log("ERROR: No PHP support compiled");
#endif
    }

if(raydium_console_get_string_last[0]!='/' && !treated)
{
#ifdef PHP_SUPPORT
#define TEMPFILE raydium_file_home_path("temp.delme.php")
FILE *fp;
fp=fopen(TEMPFILE,"wt");
if(!fp) { raydium_log("console: php call: cannot create %s temporary file",TEMPFILE); return; }
fprintf(fp,"<? %s; ?>",raydium_console_get_string_last);
fclose(fp);
raydium_php_exec(TEMPFILE);
treated=1; // all is sended to PHP for now
#endif
}


if(!treated && raydium_console_gets_callback)
    {
    f=raydium_console_gets_callback;
    strcpy(temp,raydium_console_get_string_last+1);
    f(temp);
    }

}

void raydium_console_line_add(char *format, ...)
{
va_list argptr;
int retlen;

raydium_console_line_last++;
if(raydium_console_line_last>=RAYDIUM_CONSOLE_MAX_LINES)
   raydium_console_line_last=0;

va_start(argptr,format);
retlen = vsnprintf(raydium_console_lines[raydium_console_line_last],RAYDIUM_MAX_NAME_LEN - 1,format,argptr);
va_end(argptr);

if(retlen < 0) retlen = 0;
raydium_console_lines[raydium_console_line_last][retlen] = '\0';
}

int raydium_console_history_read(char **hist)
{
int i,start,cpt=0;

cpt=0;
start=raydium_console_line_last;

//for(i=RAYDIUM_CONSOLE_MAX_LINES-1;i>raydium_console_line_last;i--)
for(i=raydium_console_line_last+1;i<RAYDIUM_CONSOLE_MAX_LINES;i++)
 {
 hist[cpt]=raydium_console_lines[i];
 cpt++;
 }

//for(i=start;i>=0;i--)
for(i=0;i<=start;i++)
 {
 hist[cpt]=raydium_console_lines[i];
 cpt++;
 }


return cpt++;
}

void raydium_console_event(void)
{
#ifdef PHP_SUPPORT
static signed char first=1;

if(first)
    {
    raydium_texture_find_by_name(raydium_console_config_texture); // cache
//    raydium_texture_find_by_name(RAYDIUM_CONSOLE_FONT_SIZE); // cache
    raydium_log("    --- This console provides a PHP parser and text completion ---");
    first=0;
    }
#endif

if(raydium_console_inc!=0) raydium_console_inc*=-1;
else {
        if(raydium_console_pos==0) raydium_console_inc=raydium_console_config_speed;
        else raydium_console_inc=-raydium_console_config_speed;
     }
}

void raydium_console_draw(void)
{
GLfloat y,off;
int i,cpt;
//int texsave;
char *hist[RAYDIUM_CONSOLE_MAX_LINES];

raydium_console_pos+=raydium_console_inc*(raydium_frame_time*100);

if(raydium_console_pos<0)
 {
 raydium_console_pos=0;
 raydium_console_inc=0;
 }

if(raydium_console_pos>raydium_console_config_max)
 {
 raydium_console_pos=raydium_console_config_max;
 raydium_console_inc=0;
 }

if(!raydium_console_pos) return;

raydium_osd_start();
//texsave=raydium_texture_current_main;
raydium_texture_current_set_name(raydium_console_config_texture);
raydium_rendering_internal_prepare_texture_render(raydium_texture_current_main);

off=raydium_console_config_max-raydium_console_pos;
glBegin(GL_QUADS);
glTexCoord2f(0,0);
glVertex3f(0,100-raydium_console_pos,0);
glTexCoord2f(1,0);
glVertex3f(100,100-raydium_console_pos,0);
glTexCoord2f(1,1);
glVertex3f(100,100+off,0);
glTexCoord2f(0,1);
glVertex3f(0,100+off,0);
glEnd();

raydium_osd_stop();

y=100-raydium_console_pos+(RAYDIUM_CONSOLE_FONT_SIZE/6.f);

raydium_osd_color_ega('f');
raydium_console_cursor_blink+=(raydium_frame_time*2);
raydium_osd_printf(1,y,RAYDIUM_CONSOLE_FONT_SIZE,RAYDIUM_CONSOLE_FONT_SPACER,raydium_console_config_font,"%s%c",raydium_console_get_string,( (((int)raydium_console_cursor_blink)%2)?'_':' '));
y+=(RAYDIUM_CONSOLE_FONT_SIZE/6.f);

cpt=raydium_console_history_read(hist);

for(i=cpt-1;i>=0;i--)
 {
 raydium_osd_color_ega('f');
 raydium_osd_printf(1,y,RAYDIUM_CONSOLE_FONT_SIZE,RAYDIUM_CONSOLE_FONT_SPACER,raydium_console_config_font,"%s",hist[i]);
 y+=(RAYDIUM_CONSOLE_FONT_SIZE/6.f);
 }

//raydium_texture_current_set(texsave);
//raydium_rendering_internal_prepare_texture_render(raydium_texture_current);
}


// is alpha, num or '_' ?
int raydium_console_internal_isalphanumuscore(char c)
{
if(c=='_' || isalnum(c)) return 1;
return 0;
}


// "str": RAYDIUM_MAX_NAME_LEN only

void raydium_console_complete(char *str)
{
#ifdef PHP_SUPPORT
char candidates[RAYDIUM_CONSOLE_MAX_COMPLETION][RAYDIUM_MAX_NAME_LEN];
char candidates_type[RAYDIUM_CONSOLE_MAX_COMPLETION];
int n_candidates=0;
char word[RAYDIUM_MAX_NAME_LEN];
char candidate[RAYDIUM_MAX_NAME_LEN];
int word_offset;
int i,j;
int len;
int candidate_min_len;
char c;

// 0 - find last word, and store start offset
len=strlen(str);
//if(len==0) return;
for(i=(len-1);i>=0;i--)
    {
    if(!raydium_console_internal_isalphanumuscore(str[i]))
        {
        i++;
        break;
        }
    }
if(i==-1) i=0; // first word of sentence

//if(i<0 || !raydium_console_internal_isalphanumuscore(str[i]))
    //return; // empty word

word_offset=i;
strcpy(word,str+i);
len=strlen(word);

// 1 - build candidates list
for(i=0;i<raydium_register_variable_index;i++)
    {
    strcpy(candidate,raydium_register_variable_name[i]);
    candidate[len]=0;
    if(!strcmp(candidate,word))
        {
        candidates_type[n_candidates]=0; // 0 = variable
        strcpy(candidates[n_candidates++],raydium_register_variable_name[i]);
        }
    if(n_candidates==RAYDIUM_CONSOLE_MAX_COMPLETION) break;
    }

if(n_candidates<RAYDIUM_CONSOLE_MAX_COMPLETION)
for(i=0;i<raydium_register_function_index;i++)
    {
    strcpy(candidate,raydium_register_function_list[i].fname);
    candidate[len]=0;
    if(!strcmp(candidate,word))
        {
        candidates_type[n_candidates]=1; // 1 = function
        strcpy(candidates[n_candidates++],raydium_register_function_list[i].fname);
        }
    if(n_candidates==RAYDIUM_CONSOLE_MAX_COMPLETION) break;
    }

// 2 - no candidate ? only one ?
if(!n_candidates)
    return;

if(n_candidates==1)
    {
    str[word_offset]=0;
    if(strlen(str)+strlen(candidates[0]) >= (RAYDIUM_MAX_NAME_LEN-1))
        return;
    strcat(str,candidates[0]);
    if(candidates_type[0])
        strcat(str,"(");
    else
        strcat(str," ");
    return;
    }

// 3 - more than one candidate : display candidates and find the common root
raydium_console_line_add("> %s",str);

// display
for(i=0;i<n_candidates;i++)
    {
    if(candidates_type[i])
        raydium_console_line_add("%s()",candidates[i]);
    else
        raydium_console_line_add("$%s",candidates[i]);
    }
if(n_candidates==RAYDIUM_CONSOLE_MAX_COMPLETION)
    raydium_console_line_add("..."); // limited results

// root: find shortest candidate
candidate_min_len=RAYDIUM_MAX_NAME_LEN+1;
for(i=0;i<n_candidates;i++)
  if((int)strlen(candidates[i])<candidate_min_len)
    candidate_min_len=strlen(candidates[i]);

// root: find common chars
for(i=strlen(word);i<=candidate_min_len;i++) // '\0' must be tested, too
    {
    c=candidates[0][i];
    for(j=1;j<n_candidates;j++)
      if(c!=candidates[j][i]) // last equiv
        {
        candidates[0][i]=0;
        strcpy(candidate,candidates[0]);
        str[word_offset]=0;
        if(strlen(str)+strlen(candidate) >= (RAYDIUM_MAX_NAME_LEN-1))
            return;
        strcat(str,candidate);
        return;
        }
    }
#endif
}