#include "stdafx.h"
#include "tintin.h"
#include <time.h>
#include <io.h>

struct completenode *complete_head;
void prepare_for_write(char *command, char *left, char *right, char *pr, char* group, char *result);

static BOOL bCurLogHTML = FALSE;

static const char* prolog = "<html>"
						"<head>"
							"<LINK REL=\"stylesheet\" TYPE=\"text/css\" HREF=\"styles.css\">"
						"</head>"
						"<body><pre>\r\n";

static const char* epilog = "</pre></body></html>";

static const char* bspan = "<a>";
static const char* espan = "</a>";

// const char* brk = "<br>\r\n";
static const char* brk = "\r\n";
static char cache[256];

static const char* dtable[] = 
{
	"b",	
	"dr",	
	"dg",
	"dy",	
	"db",	
	"dm",	
	"dc",	
	"dw",
};

static const char* ltable[] = 
{
	"b",
	"lr",
	"lg",
	"ly",
	"lb",
	"lm",
	"lc",
	"lw"
};


static void parse(const char* from, const char* to, int& attrib, int& tcolor, int& bcolor)
{
	char* p = new char[to-from+1];

	memcpy(p, from, to-from);
	p[to-from] = '\0';

	char * ptr = strtok(p, "p:;");
	while( ptr != NULL )
	{
		int val = atoi(ptr);
		switch( val )
		{
		case 0:
		case 1:
			attrib = val;
			break;

		case 30:
		case 31:
		case 32:
		case 33:
		case 34:
		case 35:
		case 36:
		case 37:
			tcolor = val;
			break;

		case 40:
		case 41:
		case 42:
		case 43:
		case 44:
		case 45:
		case 46:
		case 47:
			bcolor = val;
			break;
		}

		ptr = strtok(NULL, "p:;");
	}

	delete [] p;
}

static const char* span(int tcolor, int bcolor, int attrib)
{
	static char buf[64];

	switch( attrib )
	{
	case 0:
		sprintf(buf, "<a class=%s>", dtable[ tcolor-30 ]);
		break;

	case 1:
		sprintf(buf, "<a class=%s>", ltable[ tcolor-30 ]);
		break;

	default:
		sprintf(buf, "<a class=%s>", dtable[ tcolor-30 ]);
		break;
	}

	return buf;
}


static int attrib ;
static int tcolor ;
static int bcolor ;

static int new_attrib = attrib;
static int new_tcolor = tcolor;
static int new_bcolor = bcolor;

  
/********************/
/* the #log command */
/********************/
void log_command(char *arg)
{
	SYSTEMTIME stl;
    char left[BUFFER_SIZE], right[BUFFER_SIZE] ,Timerecord[BUFFER_SIZE];
    BOOL bLogMode = bDefaultLogMode;
    

    arg=get_arg_in_braces(arg, left, 0);
    arg=get_arg_in_braces(arg, right, 1);
    if ( hLogFile ) { // Close log file now opened 
        if ( bCurLogHTML ) {
            DWORD Written;
            WriteFile(hLogFile , epilog, strlen(epilog), &Written, NULL);
        }
        CloseHandle(hLogFile);
        hLogFile = NULL;
        tintin_puts2(rs::rs(1024));
        if ( !*left) 
            return;
    }


    if ( !*left) {
        tintin_puts2(rs::rs(1025));
        return;
    }

    bCurLogHTML = bHTML;
    if ( *right ) {
        if ( !strcmp(right, "append") ) { // try to open in append mode 
            bLogMode = TRUE;
            if ( bCurLogHTML ) 
                tintin_puts2(rs::rs(1026));
        }
        else 
            if ( !strcmp(right, "overwrite") ) { // try to open in append mode 
                bLogMode = FALSE;
            }
            else {
                if ( !strcmpi(right, "html") ) 
                    bCurLogHTML = TRUE;
                else {
                    tintin_puts2(rs::rs(1027));
                    return;
                }
            }
    }


    if ( bLogMode && !bCurLogHTML ) {
        hLogFile = CreateFile(left , GENERIC_READ| GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_ALWAYS, NULL, NULL );
    }
    else 
        hLogFile = CreateFile(left , GENERIC_READ| GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, NULL, NULL );

    if ( hLogFile == INVALID_HANDLE_VALUE ) {
        char buff[128];
        hLogFile = NULL;
        sprintf(buff,rs::rs(1028),left);
        tintin_puts2(buff);
        return;
    }
    SetFilePointer(hLogFile, 0, 0 , FILE_END );

    // Do HTML Log pereference
    if ( bCurLogHTML ) {
        DWORD Written;
        WriteFile(hLogFile , prolog , strlen(prolog), &Written, NULL);

	    attrib = 0;
	    tcolor = 37;
	    bcolor = 40;


        const char* pspan = span(tcolor, bcolor, attrib);
        WriteFile(hLogFile , pspan, strlen(pspan), &Written, NULL);
        strcpy(cache, "");
    }

	GetLocalTime(&stl);
    sprintf(Timerecord, rs::rs(1029) , stl.wDay, stl.wMonth , 
        stl.wYear , stl.wHour, stl.wMinute);
    WriteToLog(Timerecord , strlen(Timerecord) );
    tintin_puts2(rs::rs(1030));
}

/***********************************/
/* read and execute a command file */
/***********************************/
static void process_file(FILE* pfile)
{
    char buffer[BUFFER_SIZE], *cptr;

    while(fgets(buffer, sizeof(buffer), pfile)) {
        for(cptr=buffer; *cptr && *cptr!='\n'; cptr++);
        *cptr='\0';
        if ( *buffer  ) 
            parse_input(buffer); 
    }
}

void read_command(char *filename)
{
    FILE *myfile ;
    char message[80];
    // int flag = TRUE;

    get_arg_in_braces(filename,filename, 1);
    if((myfile=fopen(filename, "r"))==NULL) {
        sprintf(message,rs::rs(1031),filename);
        tintin_puts2(message);
    } else {
        process_file(myfile);
        fclose(myfile);
    }
    if((myfile=fopen("global.set", "r"))==NULL) {
        sprintf(message,rs::rs(1032));
        tintin_puts2(message);
    } else {
        process_file(myfile);
        fclose(myfile);
    }

    
    if (!verbose) {
        tintin_puts2(rs::rs(1033));
        sprintf(message,rs::rs(1034), AliasList.size());
        tintin_puts2(message);
        sprintf(message,rs::rs(1035),ActionList.size());
        tintin_puts2(message);
        sprintf(message,rs::rs(1036),antisubnum);
        tintin_puts2(message);
        sprintf(message,rs::rs(1037),subnum);
        tintin_puts2(message);
        sprintf(message,rs::rs(1038),VarList.size ());
        tintin_puts2(message);
        sprintf(message,rs::rs(1039),HlightList.size());
        tintin_puts2(message);
        sprintf(message,rs::rs(1040),GroupList.size());
        tintin_puts2(message);
    }

    if ( GroupList.find(DEFAULT_GROUP_NAME) == GroupList.end() ) {
        GroupList[DEFAULT_GROUP_NAME] = new CGROUP(DEFAULT_GROUP_NAME);
    }

}

/************************/
/* write a command file */
/************************/
void write_command(char *arg)
{
    FILE *myfile, *globfile;
    char buffer[BUFFER_SIZE], filename[BUFFER_SIZE], group[BUFFER_SIZE];
    struct listnode *nodeptr;
    int i;
    CGROUP* grp ;

    arg=get_arg_in_braces(arg, filename, 0);
    arg=get_arg_in_braces(arg, group, 0);

    if (*filename=='\0') {
        tintin_puts2(rs::rs(1041));
        return;
    }
    
    if ( *group ) {
        GROUP_INDEX ind = GroupList.find(group);
        if ( ind == GroupList .end() ) {
            char result[BUFFER_SIZE];
            sprintf ( result, rs::rs(1042), group);
            tintin_puts2(result);
            return;
        }
        grp = ind->second;
    }


    if ( *group == 0 ) {
        if((myfile=fopen(filename, "w"))==NULL) {
            char buff[128];
            sprintf(buff,rs::rs(1043),filename);
            tintin_puts2(buff);
            return; 
        }
        if((globfile=fopen("global.set", "w"))==NULL) {
            tintin_puts2(rs::rs(1044));
            fclose(myfile);
            return; 
        }

        // save messages state
        if ( !mesvar[MSG_ALIAS] ) {
            buffer[0] = cCommandChar ;
            strcpy(buffer+1, "message alias OFF\n");
            fputs(buffer, myfile);
        }
        if ( !mesvar[MSG_ACTION] ) {
            buffer[0] = cCommandChar ;
            strcpy(buffer+1, "message action OFF\n");
            fputs(buffer, myfile);
        }
        if ( !mesvar[MSG_SUB] ) {
            buffer[0] = cCommandChar ;
            strcpy(buffer+1, "message subst OFF\n");
            fputs(buffer, myfile);
        }
        if ( !mesvar[MSG_ANTISUB] ) {
            buffer[0] = cCommandChar ;
            strcpy(buffer+1, "message antisub OFF\n");
            fputs(buffer, myfile);
        }
        if ( !mesvar[MSG_HIGH] ) {
            buffer[0] = cCommandChar ;
            strcpy(buffer+1, "message high OFF\n");
            fputs(buffer, myfile);
        }
        if ( !mesvar[MSG_VAR] ) {
            buffer[0] = cCommandChar ;
            strcpy(buffer+1, "message variable OFF\n");
            fputs(buffer, myfile);
        }
        if ( !mesvar[MSG_GRP] ) {
            buffer[0] = cCommandChar ;
            strcpy(buffer+1, "message group OFF\n");
            fputs(buffer, myfile);
        }
        if ( !mesvar[MSG_HOT] ) {
            buffer[0] = cCommandChar ;
            strcpy(buffer+1, "message hotkey OFF\n");
            fputs(buffer, myfile);
        }

        // save togglesub/echo/multiaction etc states 
        buffer[0] = cCommandChar ;

        strcpy(buffer+1, "multiaction ");
        strcat (buffer, bMultiAction ? "on\n" : "off\n" );
        fputs(buffer, myfile);

        strcpy(buffer+1, "multihighlight ");
        strcat (buffer, bMultiHighlight ? "on\n" : "off\n" );
        fputs(buffer, myfile);

        strcpy(buffer+1, "presub ");
        strcat (buffer, presub ? "on\n" : "off\n" );
        fputs(buffer, myfile);

        strcpy(buffer+1, "echo ");
        strcat (buffer, echo ? "on\n" : "off\n" );
        fputs(buffer, myfile);

        strcpy(buffer+1, "ignore ");
        strcat (buffer, ignore? "on\n" : "off\n" );
        fputs(buffer, myfile);

        strcpy(buffer+1, "speedwalk ");
        strcat (buffer, speedwalk ? "on\n" : "off\n" );
        fputs(buffer, myfile);

        strcpy(buffer+1, "togglesubs ");
        strcat (buffer, togglesubs ? "on\n" : "off\n" );
        fputs(buffer, myfile);

        strcpy(buffer+1, "verbat ");
        strcat (buffer, verbatim ? "on\n" : "off\n" );
        fputs(buffer, myfile);


        ALIAS_INDEX ind = AliasList.begin();
        while (ind  != AliasList.end() ) {
            ALIAS* pal = ind->second;
            prepare_for_write("alias", (char*)ind->first.data(), (char*)pal->m_strRight.data(), 
                "\0", (char*)pal->m_pGroup->m_strName.data () , buffer);
            fputs(buffer, pal->m_pGroup->m_bGlobal ? globfile : myfile);
            ind++;
        }

        ACTION_INDEX aind = ActionList.begin();
        while (aind  != ActionList.end() ) {
            // CActionPtr pac = *aind;
            ACTION* pac = *aind;
            if ( !pac->m_bDeleted ) {
                char buff[32];
                prepare_for_write("action", (char*)pac->m_strLeft.data(), (char*)pac->m_strRight.data(), 
                    itoa(pac->m_nPriority, buff, 10) , (char*)pac->m_pGroup->m_strName.data() , buffer);
                fputs(buffer, pac->m_pGroup->m_bGlobal ? globfile : myfile);
            }
            aind++;
        }


        VAR_INDEX vind = VarList.begin();
        while ( vind != VarList.end() ) {
            VAR* pvar = vind->second;
            prepare_for_write("variable", (char*)vind->first.data(), (char*)pvar->m_strVal.data(), pvar->m_bGlobal ? "global" : "\0",  "\0", buffer);
            fputs(buffer, pvar->m_bGlobal ? globfile : myfile);
            vind++;
        }

        HLIGHT_INDEX hind = HlightList.begin();
        while ( hind != HlightList.end() ) {
            HLIGHT* ph = hind->second;
            prepare_for_write("highlight", (char*)ph->m_strColor.data(), (char*)hind->first.data(), 
                "\0", (char*)ph->m_pGroup->m_strName.data () , buffer);

            fputs(buffer, ph->m_pGroup->m_bGlobal ? globfile : myfile);
            hind++;
        }
    


      nodeptr=common_antisubs;
      while((nodeptr=nodeptr->next)) {
        prepare_for_write("antisubstitute", nodeptr->left,
        nodeptr->right, "\0",  "\0",buffer);
        fputs(buffer, myfile);
      } 
  
      nodeptr=common_subs;
      while((nodeptr=nodeptr->next)) {
        prepare_for_write("substitute", nodeptr->left, nodeptr->right, "\0",  "\0", buffer);
        fputs(buffer, myfile);
      }

      nodeptr=common_pathdirs;
      // !!! TO prevent default patgs writting
      i = 0;
      do {
        nodeptr=nodeptr->next;
        i++;
      } while ( nodeptr && i < 7 );

      while(nodeptr) {
        prepare_for_write("pathdir", nodeptr->right, nodeptr->left, "\0",  "\0",buffer);
        fputs(buffer, myfile);
        nodeptr=nodeptr->next;
      }

    
        // write groups states
        GROUP_INDEX gind = GroupList.begin();
        while ( gind != GroupList.end() ) {
            CGROUP* pg = gind->second;
            if ( !pg->m_bEnabled ) {
                sprintf( buffer, "%cgroup disable %s\n", cCommandChar , (char*)pg->m_strName.data());
                fputs(buffer, pg->m_bGlobal ? globfile : myfile);
            } 
            if ( pg->m_bGlobal ) {
                sprintf( buffer, "%cgroup global %s\n", cCommandChar , (char*)pg->m_strName.data());
                fputs(buffer, globfile );
            } else {
                sprintf( buffer, "%cgroup local %s\n", cCommandChar , (char*)pg->m_strName.data());
                fputs(buffer, pg->m_bGlobal ? globfile : myfile);
            }

            gind++;
        }

        // write hotkeys here 
        HOTKEY_INDEX hotind = HotkeyList.begin();
        while ( hotind != HotkeyList.end() ) {
            CHotKey* pHotKey= hotind->second;
            prepare_for_write("hot", (char*)pHotKey->m_strKey.data() ,
                (char*)pHotKey->m_strAction.data() , "\0",  "\0",buffer);
            fputs(buffer, myfile);
            hotind++;
        }


        // write ticksize now 
        sprintf(buffer , "%cticksize %d\n" , cCommandChar , tick_size );
        fputs(buffer, myfile);


        fclose(myfile);
        fclose(globfile);
        
    } else {
        if((myfile=fopen(filename, "a"))==NULL) {
            char buff[128];
            sprintf(buff,rs::rs(1045),filename);
            tintin_puts2(buff);
            return; 
        }
        fseek(myfile, 0 , SEEK_END);
        ALIAS_INDEX ind = AliasList.begin();
        while (ind  != AliasList.end() ) {
            ALIAS* pal = ind->second;
            if ( pal->m_pGroup == grp ) {
                prepare_for_write("alias", (char*)ind->first.data(), (char*)pal->m_strRight.data(), 
                    "\0", (char*)pal->m_pGroup->m_strName.data () , buffer);
                fputs(buffer, myfile);
            }
            ind++;
        }

        ACTION_INDEX aind = ActionList.begin();
        while (aind  != ActionList.end() ) {
            // CActionPtr pac = *aind;
            ACTION* pac = *aind;
            char buff[32];
            if ( pac->m_pGroup == grp && !pac->m_bDeleted ) {
                prepare_for_write("action", (char*)pac->m_strLeft.data(), (char*)pac->m_strRight.data(), 
                    itoa(pac->m_nPriority, buff, 10) , (char*)pac->m_pGroup->m_strName.data() , buffer);
                fputs(buffer, myfile);
            }
            aind++;
        }


        HLIGHT_INDEX hind = HlightList.begin();
        while ( hind != HlightList.end() ) {
            HLIGHT* ph = hind->second;
            if ( ph->m_pGroup == grp ) {
                prepare_for_write("highlight", (char*)ph->m_strColor.data(), (char*)hind->first.data(), 
                    "\0", (char*)ph->m_pGroup->m_strName.data () , buffer);

                fputs(buffer, myfile);
            }
            hind++;
        }
    
        fclose(myfile);
    }
    tintin_puts2(rs::rs(1046));
}

void prepare_for_write(char *command, char *left, char *right, char *pr, char* group, char *result)
{
  /* char tmpbuf[BUFFER_SIZE]; */
  *result=cCommandChar;
  *(result+1)='\0';
  strcat(result, command);
  strcat(result, " {");
  strcat(result, left);
  strcat(result, "}");
  if (strlen(right)!=0) {
    strcat(result, " {");
    strcat(result, right);
    strcat(result, "}");
  }
  if (strlen(pr)!=0) {
    strcat(result, " {");
    strcat(result, pr);
    strcat(result, "}");
  }
  if (strlen(group)!=0) {
    strcat(result, " {");
    strcat(result, group);
    strcat(result, "}");
  }
  strcat(result,"\n");
}

void prepare_quotes(char *string)
{
  char s[BUFFER_SIZE], *cpsource, *cpdest;
  int nest=FALSE;
  strcpy(s, string);

  cpsource=s;
  cpdest=string;

 while(*cpsource) {
    if(*cpsource=='\\') {
      *cpdest++=*cpsource++;
      if(*cpsource)
        *cpdest++=*cpsource++;
    }
    else if(*cpsource=='\"' && nest==FALSE) {
      *cpdest++='\\';
      *cpdest++=*cpsource++;
    }
    else if(*cpsource=='{') {
      nest=TRUE;
      *cpdest++=*cpsource++;
    }
    else if(*cpsource=='}') {
      nest=FALSE;
      *cpdest++=*cpsource++;
    }
    else
      *cpdest++=*cpsource++; 
  }
  *cpdest='\0';
}


// Writting to log file without ESC characters

void WriteToLog(char* str, int StrSize )
{
    static DWORD LastTicker = 0;
    char* buff, *src, *out;
    int count;

    

    if ( bCurLogHTML ) {
        bool lookup = true;
        bool new_line = true;
        DWORD Written;
        char * ptr = str;


	    while( lookup )
	    {
		    switch( *ptr )
		    {
		    case '\r':
			    break;

		    case '\n':
                WriteFile(hLogFile , brk, strlen(brk), &Written, NULL);
			    new_line = true;
			    break;

		    case 0x1b:
			    if( *(ptr+1) == '[' )
			    {
				    char* p = ptr+2;
				    while( *p && *p != 'm' )
					    p++;

				    if( p == '\0' )
				    {
					    lookup = false;
					    break;
				    }

				    parse((char*)ptr+2, (char*)p, new_attrib, new_tcolor, new_bcolor);

				    ptr = p;

				    if( attrib != new_attrib || tcolor != new_tcolor || bcolor != new_bcolor )
				    {
					    // _write(dst, espan);
					    // _write(dst, span(tcolor, bcolor, attrib));

					    strcpy(cache, espan);
					    strcat(cache, span(new_tcolor, new_bcolor, new_attrib));

    //					attrib = new_attrib;
    //					tcolor = new_tcolor;
    //					bcolor = new_bcolor;
				    }
			    }
			    else if( *(ptr+1) == 'p' )
			    {
				    char* p = ptr+2;
				    while( *p && *p != 'm' )
					    p++;
				    ptr = p;
			    }

			    break;

		    case '\0':
			    lookup = false;
			    break;

		    default:
			    if( strlen(cache) > 0 )
			    {
				    if( attrib != new_attrib || tcolor != new_tcolor || bcolor != new_bcolor )
					    WriteFile(hLogFile , cache, strlen(cache), &Written, NULL);
				    strcpy(cache, "");

				    attrib = new_attrib;
				    tcolor = new_tcolor;
				    bcolor = new_bcolor;
			    }
			    WriteFile(hLogFile , ptr, 1, &Written, NULL);
			    new_line = false;
			    break;
		    }

		    ptr++;
	    }
        

    } else {
        if ( LastTicker == 0 ) 
            LastTicker = GetTickCount();

        if ( hLogFile == NULL || StrSize <= 0 ) 
            return;
          // fwrite(temp, count, 1, ses->logfile);
        /* removing ESC CHARS */
        buff = (char*)malloc(StrSize*2+18);
        buff[0] = 0;
    
        // Add RMA ANSI command
        if ( bRMASupport ) {
            DWORD Currticker = GetTickCount();
            if ( Currticker - LastTicker ) {
                buff[0] = 0x1B;
                sprintf(buff+1 , "p:%dm" , Currticker - LastTicker);
            }
            LastTicker = Currticker;
        }

        src = str;
        count = strlen(buff);
        out = buff + count;
        do {
            if ( !bANSILog && *src == 0x1B ) {
                // Skip ESC
                do {
                    src++;
                    StrSize--;
                }while ( StrSize && *src != 'm' ) ;
                src++;
                StrSize--;
                continue;
            }
            *out++ = *src++;
            count++;
            StrSize--;
        } while (StrSize >0);

        if ( count ) {
            DWORD Written;
            WriteFile(hLogFile , buff , count , &Written, NULL);
        }
        free(buff);
    }
}

// str must be ESC free
void WriteToLog2(char* str, int StrSize )
{
    DWORD Written;
    WriteFile(hLogFile , str, StrSize, &Written, NULL);
}

