#include <unistd.h>
#include <ncurses.h>
#include <ctype.h>

#include "LineManip.h"
#include "Util.h"

#ifdef __DEBUG__
extern FILE * ferr;
#endif

LineManip::LineManip()
{
}
LineManip::~LineManip()
{
}

string LineManip::printColor( WINDOW *win, string str, long offset)
{
    regmatch_t matchList[MAXMATCHES];
    
    int matches=MAXMATCHES;
    bool ret=false;
    char line[5000]; 
    char c;
    string rStr=""; // Not set yet...

    if (colorOkay && logOpen )
    {
        start_color();
        // Setup some stock colors.
        init_pair(COLOR_RED,     COLOR_RED,     -1);
        init_pair(COLOR_GREEN,   COLOR_GREEN,   -1);
        init_pair(COLOR_BLUE,    COLOR_BLUE,    -1);
        init_pair(COLOR_YELLOW,  COLOR_YELLOW,  -1);
        init_pair(COLOR_CYAN,    COLOR_CYAN,    -1);
        init_pair(COLOR_MAGENTA, COLOR_MAGENTA, -1);
        init_pair(COLOR_BLACK,   COLOR_BLACK,   -1);
        init_pair(COLOR_WHITE,   COLOR_WHITE,   -1);
    }


    // Local char* of our line...
    strncpy(line,str.c_str(),5000);

    // If we have not opened a log file, return false.

    // Get each character to be displayed...
    for ( int j=0; j<(signed)str.size()-offset && j < COLS; j++)
    {
        c = str[j+offset];
        ret=false;

        if (logOpen == true && colorOkay) 
        {
            // What color to make this char???
            // NOTE: ret is used to flag when a color has been determined...
            for ( unsigned int i=0; i<colorExp.size() && !ret; i++)
            {
                // Does this regex exist in this string?
                if (!regexec(&(colorReg[i]),line,matches,matchList,(int)0))
                {
        
                    // Eatch match on the line...
                    // zero'th elt is the entire string...
                    for(int k = 0; matchList[k].rm_so != -1 && k < 20; k++) 
                    {
                        // Does the current char fall within the current regex?
                        if ( matchList[k].rm_so > -1 &&
                            j >= matchList[k].rm_so -offset &&
                            j < matchList[k].rm_eo -offset)
                        {
                            wattron(win,COLOR_PAIR(colorPairs[i]));
                            for (;j < matchList[k].rm_eo -offset;j++)
                            {
                                c=str[j+offset];
                                wprintw(win,"%c",c);
                            }
                            j--;
                            ret=true;
                            use_default_colors();
                            wattroff(win,COLOR_PAIR(colorPairs[i]));
                        }
                    }
                }
            } // color loop.
        }

        // No color matches..
        if (ret==false) 
        {
            wprintw(win,"%c",c);
        }
        ret=false;

    } // character loop.

    return rStr;
}

// Returns true if we ignore the line.
bool LineManip::ignore(char * fileName,string linel)
{
    regex_t reg;
    regmatch_t *matchList=NULL;
    
    int matches=0;
    bool ret=false;
    char line[5000]; 

    strncpy(line,linel.c_str(),5000);

    // Find the 'filename' without path..
    char * tmpFileName = strrchr(fileName,'/')+1;
    if (!tmpFileName) tmpFileName = fileName;

    char merr[255]; int rval=0;
    
    // If we have not opened a log file, return false.
    if (logOpen == false) return false;

    // If no expressions, return...
    if (ignoreExp.size() == 0 ) return false;
    
    // Will be set to true if we find something...
    ret=false;
    for ( unsigned int i=0; i<ignoreExp.size(); i++)
    {
        rval=regcomp(&reg,ignoreExp[i].c_str(),REG_EXTENDED|REG_ICASE|REG_NOSUB);
    
        if (rval!=0)
        {
            regfree(&reg);
            regerror(rval,&reg,merr,255);
            clean_exit(rval,merr);
        }
    
        if (!regexec(&reg,line,matches,matchList,(int)0))
        {
            ret=true;
            regfree(&reg);
            return true;
        }
        regfree(&reg);
    }

    return ret;
}

string LineManip::findConf()
{
    FILE *test;

    string home = getenv("HOME");
    string tmp;

    tmp=home+"/.logmonrc";
    if ( (test=fopen(tmp.c_str(),"r")) )
    {
        fclose(test);
        return tmp;
    }

    tmp="/etc/logmon.conf";
    if ( (test=fopen(tmp.c_str(),"r")) )
    {
        fclose(test);
        return tmp;
    }

    return string("");
}

// Scan our config file for lines pertaining to our filename.
// i.e. If there are 'ignore' lines for our filename, we add them
//      to an array.
void LineManip::init(char* fileName, string config)
{
    FILE *cf;
    string confFile;
    char buf[1024]; 
    string action,tmpFileName,lines;
    char *ptr; char*newbuf;
    char c; int i;
    bool comment=false;
    bool nonspace=false;
    regex_t reg;
    char merr[255]; int rval=0;
    bool isIgnore=false;
    bool Last=false;

    // Two steps.  Find a trailing '/'.  If we don't find one, use the filename,
    // else, use the string from that position plus one.
    char *baseFileName = strrchr(fileName,'/');
    if ( !baseFileName ) baseFileName=fileName;
    else baseFileName++;

    // If a file name isn't specified, find one.
    if ( config == "" )
        confFile=findConf();
    else
        confFile=config;

#ifdef __DEBUG__
    fprintf(ferr,"Using config file=<%s>\n",confFile.c_str());
#endif

    cf=fopen(confFile.c_str(),"r");
    if (!cf)
    {
        logOpen=false;
        return;
    }
    else
    {
        logOpen=true;
#ifdef __DEBUG__
        fprintf(ferr,"open %s\n",confFile.c_str());
#endif
    }

    if (has_colors())
    {
        colorOkay=true;

    }
    else 
        colorOkay=false;

    // for each line.
    while (!feof(cf))
    {
        memset(buf,'\0',1024);
        i=0;
        comment=nonspace=false;
        isIgnore=false; 

        // Read each line, inspecting the input...
        while ( ((c=fgetc(cf)) != '\n') && (!feof(cf)) && i <1024)
        {
            if (!isspace(c)) nonspace=true;

            if (nonspace && c=='#') comment=true;

            buf[i]=c;
            i++;
        }
        // Just in case...
        buf[i]='\0';

        if (comment || !nonspace) continue;

        if ( buf[0] )
        {
            newbuf=buf;
            // Get the action.
            ptr=strchr(newbuf,':');
            *ptr='\0'; ptr++;
            action=newbuf;
            newbuf=ptr;

            // Get the filename.
            ptr=strchr(newbuf,':');
            *ptr='\0'; ptr++;
            tmpFileName=newbuf;
            newbuf=ptr;

            if ( strcmp(tmpFileName.c_str(),baseFileName) )
            {
#ifdef __DEBUG__
                fprintf(ferr,"No match %s:%s\n",tmpFileName.c_str(),fileName);
#endif
            }
            else
            {
#ifdef __DEBUG__
                fprintf(ferr,"Match %s:%s\n",tmpFileName.c_str(),fileName);
#endif

                Last = false;
                // Parse the regex's. (regexi?  regexs? what's plural?)
                while ( (ptr=strchr(newbuf,',')) )
                {
                    // Null terminate our current string..
                    *ptr='\0';
#ifdef __DEBUG__
                    fprintf(ferr,"\tlines=%s\n",newbuf);
#endif

                   // Add this regex to our list...
                    if (action=="ignore")
                    {
                        ignoreExp.push_back(newbuf);
                        isIgnore=true;
                    }

                    // Advance our string position..
                    newbuf=ptr+1;
                }

#ifdef __DEBUG__
                fprintf(ferr,"\tlines=%s\n",newbuf);
#endif
                // the last element..
                if (action=="ignore")
                {
                    ignoreExp.push_back(newbuf);
                } 
                else if (!strcasecmp(action.c_str(), "red") && colorOkay)
                {
                    colorPairs.push_back(COLOR_RED);
                    colorExp.push_back(newbuf);
                }
                else if (!strcasecmp(action.c_str(), "green") && colorOkay)
                {
                    colorPairs.push_back(COLOR_GREEN);
                    colorExp.push_back(newbuf);
                }
                else if (!strcasecmp(action.c_str(), "blue") && colorOkay)
                {
                    colorPairs.push_back(COLOR_BLUE);
                    colorExp.push_back(newbuf);
                }
                else if (!strcasecmp(action.c_str(), "yellow") && colorOkay)
                {
                    colorPairs.push_back(COLOR_YELLOW);
                    colorExp.push_back(newbuf);
                }
                else if (!strcasecmp(action.c_str(), "cyan") && colorOkay)
                {
                    colorPairs.push_back(COLOR_CYAN);
                    colorExp.push_back(newbuf);
                }
                else if (!strcasecmp(action.c_str(), "magenta") && colorOkay)
                {
                    colorPairs.push_back(COLOR_MAGENTA);
                    colorExp.push_back(newbuf);
                }
                else if (!strcasecmp(action.c_str(), "black") && colorOkay)
                {
                    colorPairs.push_back(COLOR_BLACK);
                    colorExp.push_back(newbuf);
                }
                else if (!strcasecmp(action.c_str(), "WHITE") && colorOkay)
                {
                    colorPairs.push_back(COLOR_WHITE);
                    colorExp.push_back(newbuf);
                }
                rval=regcomp(&reg,newbuf,REG_EXTENDED|REG_ICASE);
            
                // Something went *terribly* wrong...
                if (rval!=0)
                {
                    regfree(&reg);
                    regerror(rval,&reg,merr,255);
                    clean_exit(rval,merr);
                }
                if (!isIgnore)
                    colorReg.push_back(reg);
 
           }

        }
    }

    fclose(cf);

}
