//
// $Id: Main.cc 80 2006-01-07 18:28:18Z amackenz $
// 


using namespace::std;

#include <stdio.h>
#include <stdlib.h>

#include <ncurses.h>
#include <signal.h>
#include <time.h>
#include <vector>
#include <unistd.h>
#include <string>

#include <sys/time.h>
#include <sys/types.h>

// FreeBSD didn't like this...
#ifdef __linux__
#include <getopt.h>
#endif

#include "Frame.h"
#include "Util.h"
#include "config.h"

vector <char *> fileList;
vector<Frame> frameList;

#ifdef __DEBUG__
FILE * ferr=NULL;
#endif 

long bufferSize;

extern char *optarg;
extern int optind, opterr, optopt;

string config;

#define ALL_FRAMES -1

int curFrame = ALL_FRAMES;

void sig_winch(int x)
{
    endwin();
    initscr();
}

int init()
{
    for (unsigned long i=0; i<fileList.size(); i++)
    {
        frameList.push_back( Frame(fileList[i],i, fileList.size(), config) );
    }

    return 1;
}

void selectAllFrames(bool b)
{
    for (unsigned long i=0; i<frameList.size(); i++)
    {
        frameList[i].enable(b);
        frameList[i].print();
    }
}

void rotateFrames(int dir)
{
    // Scrolled down beyond ALL_FRAMES
    if ( curFrame + dir < ALL_FRAMES )
    {
        selectAllFrames(false);
        curFrame = frameList.size() - 1;
        frameList[curFrame].enable(true);
        frameList[curFrame].print();
    }
    else if ( curFrame + dir >= frameList.size() )
    {
        // We're out of range, select all frames.
        curFrame = ALL_FRAMES;
        selectAllFrames(true);
    }
    else
    { 
        if ( curFrame == ALL_FRAMES )
        {
            // We are going from 'all selected' to 'one selected'.  Disable
            // all frames.
            selectAllFrames(false);
        }
        else
        {
            // Just disable the old frame.
            frameList[curFrame].enable(false);
            frameList[curFrame].print();
        }
        curFrame+=dir;

        frameList[curFrame].enable(true);
        frameList[curFrame].print();
    }
    refresh();
}

void display()
{
    int c;
    int scrollUp=0;
    int scrollRight=0;
    int scrollLeft=0;
    int scrollDown=0;
    int reset_bottom=0;
    int reset_top=0;
    int reset_left=0;
    bool keyPressed=false;

    // This must be false for screen resizing to work.
    //nodelay(stdscr, false);
    halfdelay(1);
    keypad(stdscr, true);

    while(1)
    {

        for (unsigned long i=0; i<frameList.size(); i++)
        {
            if ( scrollUp )
                frameList[i].incrScrollBack(scrollUp);
            if ( scrollDown )
                frameList[i].decrScrollBack(scrollDown);
            if ( scrollLeft )
                frameList[i].decrScrollRight(scrollLeft);
            if ( scrollRight )
                frameList[i].incrScrollRight(scrollRight);
            if ( reset_bottom )
                frameList[i].setScrollBack(0);
            if ( reset_left )
                frameList[i].setScrollRight(0);
             if ( reset_top )
                frameList[i].setScrollBack(frameList[i].maxScrollBack());

            // Read returns 'true' if any new info is read.
            // Saves some bandwith if we are remote, by 
            // only redrawing if changes have been made.
            // TODO: Scrolling can be done frame-by-frame, why not redraw
            // frame-by-fram?
            if (frameList[i].read() || keyPressed )
                frameList[i].print();
        }

        scrollUp = 0;
        scrollDown = 0;
        reset_bottom = 0;
        reset_top = 0;
        reset_left = 0;
        scrollRight = 0;
        scrollLeft = 0;
        keyPressed=false;

        if ( (c=getch()) != ERR )
        {
            // do something.
            // Handle our character.
            //fprintf(ferr,"Got : %d\n",c);
            switch(c)
            {
                case '\t':
                case 'w':
                    rotateFrames(1);
                    break;
                case 'W':
                    rotateFrames(-1);
                    break;
                case 'a':
                    selectAllFrames(true);
                    curFrame = ALL_FRAMES;
                    refresh();
                    break;
                case KEY_UP:
                case 'k':
                    keyPressed=true;
                    scrollUp=1;
                    break;
                case KEY_RIGHT:
                case 'l':
                    keyPressed=true;
                    scrollRight=1;
                    break;
                case KEY_LEFT:
                case 'h':
                    keyPressed=true;
                    scrollLeft=1;
                    break;
                case KEY_DOWN:
                case 'j':
                    keyPressed=true;
                    scrollDown=1;
                    break;
                case KEY_NPAGE:
                case 'J':
                    keyPressed=true;
                    scrollDown=frameList[0].height();
                    break;
                case KEY_PPAGE:
                case 'K':
                    keyPressed=true;
                    scrollUp=frameList[0].height();
                    break;
                case KEY_HOME:
                    keyPressed=true;
                    reset_left=1;
                    break;
                case KEY_END:
                    keyPressed=true;
                    reset_bottom=1;
                    break;
                case 'g': // top.
                    keyPressed=true;
                    reset_top=1;
                    break;
                case KEY_RESIZE:
                    sig_winch(0);
                    refresh();
                    keyPressed=true;
                    for (unsigned long i=0; i<frameList.size(); i++)
                        frameList[i].resize();
                    break;
                case ' ':
                case 'G':
                    keyPressed=true;
                    reset_bottom=1;
                    reset_left=1;
                    break;

                case 'q':
                case 'Q':
                    clean_exit();
                default:
                    break;
            }
        }
    }

}

int usage(string prog)
{
    printf("Usage:\n\n\t%s [-v] [-b buffer_size] [-f config_file] <file1> <file2> ...\n\n", prog.c_str());
    return 0;
}



extern char *optarg;
extern int optind, opterr, optopt;

int main( int argc, char ** argv )
{
    (void) signal(SIGINT, sig_int);

    char c;

#ifdef __DEBUG__
    ferr = fopen("err.txt","w");
    // Set to non-buffered.
    setbuf(ferr,NULL);
#endif 

    // Set default values for command line args.
    bufferSize = 1000;

    while ( (c=getopt(argc, argv, "d:b:f:v")) != -1)
    {
        switch(c)
        {
            case 'd':
            case 'b':
                bufferSize=atoi(optarg);
                break;
            case 'v':
                printf("%s - %s\n",argv[0],VERSION);
                clean_exit();
            case 'f':
                config=optarg; // Set our config file name.
                break;
            default:
                printf("Unknown option <%c>\n",c);
                usage(argv[0]);
                clean_exit();
        }
    }
    // Get each file...
    if ( optind < argc )
    {

        for (int i=optind; i<argc; i++)
        {
            fileList.push_back(argv[i]);
        }
    }
    else
    {
        // No more 'dipshit', thought I'd be nice. :-)
        printf("No files!\n");
        usage(string(argv[0]));
        clean_exit();
    }

    // Initialize our ncurses window.
    initscr(); 
    cbreak(); 
    noecho(); 
    clear(); 
    refresh();

    init();
    //settings.init(config);

    display();

    clean_exit();

    return 0;
}
