#include <ncurses.h>
#include <string>
#include <vector>
#include <stdlib.h>
#include <stdio.h>

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

#define BUF_SIZE 2040

using namespace std;

#ifdef __DEBUG__
extern FILE *ferr;
#endif


Frame::Frame()
{
    printf("Frame()\n");
}

Frame::~Frame()
{

    // Close the file.
    if (fin && !executable)
        fclose(fin);
    else if (fin && executable)
        pclose(fin);

    if ( win )
        delwin(win);
}

// This is really the constructor used..
// Filename, Number in queue, Total number of frames, config file name.
Frame::Frame(char* name, long n, long total,string conf)
{

    number=n;
    totalFrames=total;
    strncpy( fileName, name, FILE_NAME_SIZE);
    manip.init(fileName,conf);

    // Derive other info
    lines=LINES/total; // Total lines for this frame.
    prevOpened=0;
    actualBufferSize=0;
    startLine=(LINES/totalFrames) * number; // Where to move to
    totalFileLines=0;
    scrollBackOffset=0;
    scrollRightOffset=0;
    executable=0; // Default to non-executable..

    fin=NULL;
    win=NULL;

}

int Frame::setVariables()
{
    startLine=(LINES/totalFrames) * number ;
    lines=LINES/totalFrames;
    return 1;
}

void Frame::reSize(long l )
{
    printf("reSize(%ld)\n",l);
}

// Take a parameter to determine how far back to read.
long Frame::findPos(long maxLines)
{
    long i=-1;
    long cr_count=0;
    char c;
    maxLines = maxLines?maxLines:lines;

    // Assume file is open.
    if (!fin) clean_exit(1,"Frame::findPos File not open yet!");


    while (    cr_count < maxLines  // defaults to lines.
            && (fseek(fin, i, SEEK_END)==0) 
            && !feof(fin) )
    {

        c=getc(fin);
        if (c == '\n')
            cr_count++;

        i--;
    }
    // Go back to the last char read...
    fseek(fin, i+1, SEEK_END);

    // Remove the lines we counted back, they'll be counted
    // when we read the data into a buffer.
    totalFileLines -= cr_count; 

    return ftell(fin);
}

long Frame::findTotalFileLines()
{
    long total=0;
    long bytes_read;
    char buf[BUF_SIZE];

    rewind(fin);

      while ((bytes_read = fread (buf, 1, BUF_SIZE, fin)) > 0)
      {
         register char *p = buf;
     
         while ((p = (char*) memchr (p, '\n', (buf + bytes_read) - p)))
         {
             ++p; // Move to space after '\n'
             ++total;
         }
      }

    totalFileLines=total;

    rewind(fin);

    return total;
}

bool Frame::read()
{
    string Buf;
    bool newlines=false;
    char *tmp;

    // Only do this if we haven't initialized our buffer.
    if ( !prevOpened )
    {
        newlines=true;

        // If the first character of our filename is '>'
        // we execute the prog..
        if ( !strncmp(fileName, ">",1) )
        {
            tmp = (char*)malloc(strlen(fileName)*(sizeof(char)));
            strcpy(tmp,&fileName[1]);
            strcpy(fileName,tmp); // Trim the leading '>' from the name...
            free (tmp);

            fin = popen(fileName, "r" );
            executable=1;
        }
        else
        {
            executable=0;
            fin = fopen(fileName, "r" );
        }

        if ( !fin ) 
        {
            clean_exit(1, "Frame::read() Error opening file!");
        }

        // Certain things can't be done to non-files...
        if ( !executable )
        {
            findTotalFileLines();

            // Set our starting point at however far back we are to read.
            findPos(bufferSize);
        }

        // Open our new windows.
        win=newwin(lines,0,startLine,0 );
        prevOpened=1;

    }

    // If the screen size has change, reset our variables.
    // TODO: Get this working.. Can ncurses do this?
    setVariables();

    // Read the data in.
    // Our file pos should have already been set, read 
    // til EOF.
    char Tmp[BUF_SIZE];
    while ( !feof(fin) )
    {
        Buf = "";

        if ( fgets(Tmp, BUF_SIZE, fin) )
        {
            newlines=true;
            Buf = Tmp;
            // For whatever reason, Buf seems to be empty after
            // this call...
            if ( !manip.ignore(fileName, Buf))
            {
                Screen.push_back(Tmp);
                totalFileLines++;
            }
        }
    }
    clearerr(fin);
    return newlines;
}

long Frame::setScrollBack(long s)
{
    scrollBackOffset = s;
    return s;
}
long Frame::incrScrollBack(long s)
{
    // Only scroll up if it's not beyond our starting point.
    if ( scrollBackOffset + s < (signed)(Screen.size() - (lines-1)) ) 
        scrollBackOffset +=s;
    return scrollBackOffset;
}

long Frame::decrScrollBack( long s )
{
    // Don't scroll past our starting point.
    // scrollBackOffset min is 0.
    
    if ( (signed)(scrollBackOffset - s) >= 0 ) 
    {
        scrollBackOffset -=s;
    }
    else
    {
        scrollBackOffset=0;
    }

    return scrollBackOffset;
}


long Frame::setScrollRight(long s)
{
    scrollRightOffset = s;
    return s;
}
long Frame::incrScrollRight(long s)
{
    scrollRightOffset +=s;
    return scrollRightOffset;
}

long Frame::decrScrollRight(long s )
{
    // Don't scroll past our starting point.
    if ( scrollRightOffset > 0 ) 
        scrollRightOffset -=s;
    return scrollRightOffset;
}

void Frame::print()
{
    long i,j;
    string padding;
    // To hold the number as a string.
    char numberBuf[100];

    // Print the title, in reverse!
    //move (startLine,0); deleteln();
    werase(win); // clear the screen.
    wmove (win,0,0);

    // Determine the header
    wattron(win,A_REVERSE);
    sprintf(numberBuf,"%ld",totalFileLines);
    for ( i=17 + strlen(fileName) + strlen(numberBuf); i<COLS; i++)
        padding += ' ';

    wprintw(win,"File: <%s> %sLines:<%d>",fileName, padding.c_str(),totalFileLines);
    wattroff(win,A_REVERSE);

    // Set our line in buffer to start from...
    if ( Screen.size() < (unsigned)lines )
        i=0;
    else
        i=Screen.size() - lines+1 - scrollBackOffset;

    for ( j=1; j<lines && (unsigned)i < Screen.size(); j++)
    {
        // Move to the next line.
        wmove (win,j,0); 
        if ( (unsigned)scrollRightOffset < Screen[i].length())
        {

            // Print with coloring.
            manip.printColor(win,Screen[i],scrollRightOffset);
        }

        i++;
    }
    wrefresh(win);

}
