//  mainwidget.cpp 
//  contains member functions of MainWidget
//
#include <iostream.h>
#include <kapp.h>
#include <mainwidget.h>
#include <qpainter.h>
#include <kmsgbox.h>
#include "mainwidget.moc"

const menuheight = 30;
int window_width = 500;
int window_height = 425;
int small_width = int (window_width/7);
int small_width_y = int ((window_height - menuheight)/6);
int stone_width = int(.85 * small_width);
int stone_height =int( .85 * small_width_y);
int hole_begin = int ((small_width - stone_width) / 2);
QString picsdir = KApplication::kde_datadir() + "/kfour/pics/";
QBrush brush_red (red);
QBrush brush_yellow (yellow);
QBrush brush_blue (blue);

// constructor
MainWidget::MainWidget(QWidget * parent, const char * name) : QWidget(parent,name)
{
    this -> resize (400,370); //default size

    filemenu = new QPopupMenu ();
    filemenu -> insertItem("New game",this,SLOT(newGame() ));
    filemenu -> insertSeparator();
    filemenu -> insertItem("Exit",this,SLOT(fileQuit() ));

    optionsmenu = new QPopupMenu ();
    gbp_id = optionsmenu -> insertItem("Gameboard pixmap",this,SLOT(gameBoardPixmap() ));
    gbc_id = optionsmenu -> insertItem("GameBoard color",this,SLOT(gameBoardColor() ));
    optionsmenu -> setItemChecked(gbc_id, TRUE);
    optionsmenu -> insertSeparator();
    cs_id = optionsmenu -> insertItem("Computer starts",this,SLOT(compStarts() ));
    ps_id = optionsmenu -> insertItem("Player starts",this,SLOT(playerStarts() ));
    optionsmenu -> setItemChecked(ps_id, TRUE);
    optionsmenu -> setCheckable(TRUE);
    optionsmenu -> insertSeparator();
    ds_id = optionsmenu -> insertItem("Default size",this,SLOT(defaultSize() ));
    ss_id = optionsmenu -> insertItem("Small size",this,SLOT(smallSize() ));
    ls_id = optionsmenu -> insertItem("Large size",this,SLOT(largeSize() ));
    optionsmenu -> setItemChecked(ds_id,TRUE);
    
    movemenu = new QPopupMenu ();
    tb_id = movemenu -> insertItem("Take back",this,SLOT(takeBack() ));

    levelmenu = new QPopupMenu ();
    l1_id = levelmenu -> insertItem("Level 1", this,SLOT(level1() ));
    l2_id = levelmenu -> insertItem("Level 2", this,SLOT(level2() ));
    l3_id = levelmenu -> insertItem("Level 3", this,SLOT(level3() ));
    levelmenu -> setItemChecked(l1_id,TRUE);
    
    menu = new KMenuBar(this);
    menu -> insertItem("File",filemenu);
    menu -> insertItem("Options",optionsmenu);
    menu -> insertItem("Move",movemenu);
    menu -> insertItem("Level",levelmenu);

    max_level = 0;
    board_width = 7;
    
    initBoard();
}

void MainWidget::drawCircle(int i,int j,QBrush brush)
{
    QPainter p;
    p.begin(this);
    p.setBrush(brush);
    p.drawChord(hole_begin + i * small_width,menuheight + (5 - j) * small_width_y, stone_width, stone_height, 0, 5760);
    p.end();
}

void MainWidget::compStarts()
{
    optionsmenu -> setItemChecked(cs_id,TRUE);
    optionsmenu -> setItemChecked(ps_id,FALSE);
}

void MainWidget::defaultSize()
{
    this->resize(400,int(400/1.08));
    optionsmenu -> setItemChecked(ds_id,TRUE);
    optionsmenu -> setItemChecked(ss_id,FALSE);
    optionsmenu -> setItemChecked(ls_id,FALSE);
}

void MainWidget::smallSize()
{
    this->resize(300,int(300/1.08));
    optionsmenu -> setItemChecked(ds_id,FALSE);
    optionsmenu -> setItemChecked(ss_id,TRUE);
    optionsmenu -> setItemChecked(ls_id,FALSE);
}

void MainWidget::largeSize()
{
    this->resize(500,int(500/1.08));
    optionsmenu -> setItemChecked(ds_id,FALSE);
    optionsmenu -> setItemChecked(ss_id,FALSE);
    optionsmenu -> setItemChecked(ls_id,TRUE);
}
    
void MainWidget::gameBoardPixmap()
{
    QPixmap pixmap_red(picsdir + "stone1.xpm");
    QPixmap pixmap_yellow(picsdir + "stone2.xpm");
    QPixmap pixmap_blue(picsdir + "board.xpm");
    optionsmenu -> setItemChecked(gbp_id,TRUE);
    optionsmenu -> setItemChecked(gbc_id,FALSE);
    brush_red.setPixmap(pixmap_red);
    brush_yellow.setPixmap(pixmap_yellow);
    brush_blue.setPixmap(pixmap_blue);
    repaint();
}

void MainWidget::gameBoardColor()
{
    optionsmenu -> setItemChecked(gbp_id,FALSE);
    optionsmenu -> setItemChecked(gbc_id,TRUE);
    brush_red.setStyle(SolidPattern);
    brush_yellow.setStyle(SolidPattern);
    brush_blue.setStyle(SolidPattern);
    repaint();
}

void MainWidget::level1()
{
    levelmenu -> setItemChecked(l1_id,TRUE);
    levelmenu -> setItemChecked(l2_id,FALSE);
    levelmenu -> setItemChecked(l3_id,FALSE);
    max_level = 0;
}
void MainWidget::level2()
{
    levelmenu -> setItemChecked(l1_id,FALSE);
    levelmenu -> setItemChecked(l2_id,TRUE);
    levelmenu -> setItemChecked(l3_id,FALSE);
    max_level = 2;
}
void MainWidget::level3()
{
    levelmenu -> setItemChecked(l1_id,FALSE);
    levelmenu -> setItemChecked(l2_id,FALSE);
    levelmenu -> setItemChecked(l3_id,TRUE);
    max_level = 4;
}

    
void MainWidget::mousePressEvent(QMouseEvent * m)
{
    int x = m -> x();
    x = x / small_width;
    rowClicked(x);
}

void MainWidget::resizeEvent(QResizeEvent * r)
{
    QSize s = r -> size();
    window_width = s.width();
    window_height = s.height();
    small_width = int (window_width/7);
    small_width_y = int ((window_height - menuheight)/6);
    stone_width = int(.85 * small_width);
    stone_height =int( .85 * small_width_y);
    hole_begin = int ((small_width - stone_width) / 2);
    optionsmenu -> setItemChecked(ds_id,FALSE);
    optionsmenu -> setItemChecked(ss_id,FALSE);
    optionsmenu -> setItemChecked(ls_id,FALSE);
}

void MainWidget::playerStarts()
{
  optionsmenu -> setItemChecked(cs_id,FALSE);
  optionsmenu -> setItemChecked(ps_id,TRUE);
}

void MainWidget::fileQuit()
{
    KApplication::exit(0);
}

void MainWidget::takeBack()
{
    if (move_nr_red > 0)
    {
        move_nr_red--;
        move_nr_yellow--;
        height[move_yellow[move_nr_yellow]]--;
        drawCircle(move_yellow[move_nr_yellow], height[move_yellow[move_nr_yellow]],black);
        board[move_yellow[move_nr_yellow]] [height[move_yellow[move_nr_yellow]]] = Empty;
        height[move_red[move_nr_red]]--;
        drawCircle(move_red[move_nr_red], height[move_red[move_nr_red]],black);
        board[move_red[move_nr_red]]  [height[move_red[move_nr_red]]] = Empty;
    }
    if (move_nr_red == 0)
        movemenu->setItemEnabled (tb_id,FALSE);
}

void MainWidget::paintEvent(QPaintEvent*)
{
    QPainter p;
    p.begin(this);
    p.fillRect(0, 0, window_width, window_height, brush_blue);
    p.end();
    for (int i=0; i<=6; i++)
        for (int j=0; j<=5; j++)
        {
            drawCircle(i,j,black);
        }
    for (int i=0; i<=6; i++)
        for (int j=0; j<=5; j++)
            if (board[i][j] != Empty)
            {
                if (board[i][j] == Red)
                {
                    drawCircle(i,j,brush_red);
                }
                else
                {
                    drawCircle(i,j,brush_yellow);
                }
            }
}

void MainWidget::rowClicked(int i)
{
    if (height[i] <= 5)
        movePlayer(i); // player does move i
}

void MainWidget::movePlayer(int i)
{
    movemenu->setItemEnabled (tb_id,TRUE);
    int j = height[i];
    move_red[move_nr_red]=i;
    move_nr_red++;
    board[i][height[i]] = Red;
    drawCircle(i,j,brush_red);
    height[i]++;
    if (isWinner(Red))
        endGame(Red);
    computerMove();
}

void MainWidget::computerMove()
{
    cout << "------------------------" << "\n";
    for (int i = 0; i <= 6; i++)
        move[i] = -100;
    for (int i = 0; i <= 6; i++)
    {
        end_tree = ready = FALSE;
        levels_up = 0;
        for (int t = 0; t <= max_level; t++)
        {
            resetScore(t);
            GamePath[t] = 0;
        }
        sublevel = -1;
        if (height[i] < 6)
        {
            board [ i ] [ height [ i ] ] = Yellow;
            height [ i ]++;
            int dummy;
            dummy = onARow (Yellow, i, height [ i ] - 1);
            if (four_on_a_row)
            {
                move[i] = 200;
                height[i]--;
                goto makemove;
            }
        loop:
            while ( !end_tree )
            {
                if (!tooHigh())
                    moveDown();
                else moveRight();
            }
            if (debug)
                cout << "levels_up " << levels_up << "\n";
            changeUpScore(prev_sublevel , levels_up);
            if (debug)
                cout << "------" << "\n";
            prev_sublevel = sublevel;
            if (!ready)
                increment ();
            if (!ready)
                goto loop;
            if (debug)
                cout << "READY" << "\n";
            changeUpScore(prev_sublevel , levels_up);
            remove(i);
            move [ i ] =  score[0];
        }
    }
makemove:
    int m = maximum(move);
    cout << "max " << m << "\n";
    board [ m ] [ height [ m ] ] = Yellow;
    drawCircle ( m, height [ m ], brush_yellow);
    height [ m ]++;
    move_yellow[move_nr_yellow]=m;
    move_nr_yellow++;
    if (isWinner(Yellow))
        endGame(Yellow);
}
void MainWidget::changeScore(int level, int sc)
{
    if ( level % 2  == 0 )
    {
        if (sc < score [ level ] )
        {
            score [ level ] = sc;
            if (debug)
                cout << "level " << level << " -> " << sc << "\n";
        }

    }
    else
    {
        if (sc > score [ level ] )
        {
            score [ level ] = sc;
            if (debug)
                cout << "level " << level << " -> " << sc << "\n";
        }
    }
}

void MainWidget::changeUpScore(int level, int up)
{
    if (up >= 1 )
    {
        for (int t = 0; t <= up - 1; t++)
        {
            changeScore(level - t - 1 , score[ level - t ] );
            resetScore(level - t);
        }
    }
    changeScore(sublevel,computeScore() );
    if (debug)
        cout << "score: " << computeScore() << "\n";
}
            
void MainWidget::resetScore(int l)
{
    if (debug)
        cout << "Resetscore level " << l << "\n";
    if (l % 2 == 0)
        score[l] = 100;
    else
        score[l] = -100;
}

bool MainWidget::tooHigh()
{
    if (height[ GamePath [sublevel + 1] ] > 5)
        return TRUE;
    return FALSE;
}

void MainWidget::increment()
{
    levels_up = 0;
    remove();
    GamePath [sublevel + 1]++;
    if (sublevel > -1)
    {
        for (int t = sublevel + 1 ; t > 0 ; t--)
            if (GamePath[ t ] == board_width)
            {
                levels_up++;
                remove();
                GamePath[ t ] = 0;
                GamePath[ t - 1 ] ++;
            }
    }
    if (GamePath[0] == board_width)
    {
        end_tree = TRUE;
        ready = TRUE;
    }
}

void MainWidget::moveDown()
{
    sublevel++;
    if (sublevel == max_level)
        end_tree = TRUE;
    color cl;
    if (sublevel % 2 == 0)
        cl = Red;
    else
        cl = Yellow;
    board [ GamePath [ sublevel ] ] [ height [GamePath [ sublevel ] ] ] = cl;
    height[ GamePath [ sublevel ] ]++;
    if (debug)
    {
        repaint();
        KMsgBox::message(0,"","Debug");
    }
    // What if four on a row??
    int dummy;
    dummy = onARow(cl,GamePath [ sublevel ],height [GamePath [ sublevel ] ] - 1);
    if (four_on_a_row)
        end_tree = TRUE;
}

void MainWidget::moveRight()
{
    GamePath [sublevel + 1]++;
    if (sublevel > -1)
    {
        for (int t = sublevel + 1 ; t > 0 ; t--)
            if (GamePath[ t ] == board_width)
            {
                remove();
                GamePath[ t ] = 0;
                GamePath[ t - 1 ] ++;
            }
    }
    if (GamePath[0] == board_width)
    {
        end_tree = TRUE;
        ready = TRUE;
    }
}

void MainWidget::remove()
{
    end_tree = FALSE;
    height [ GamePath [sublevel] ]--;
    board[ GamePath [sublevel] ] [ height[ GamePath [sublevel] ] ]= Empty;
    sublevel--;
}

void MainWidget::remove(int i)
{
    height [ i ]--;
    board[ i ] [ height[ i ] ]= Empty;
}


int MainWidget::computeScore()
{
    int score = 0;
    int dummy;
    bool four_Red, four_Yellow;
    four_Red = four_Yellow = FALSE;
    for (int t = 0; t <= 6; t++)
    {
        int on_y1,on_y2,on_y3,on_y4;
        int on_r1,on_r2,on_r3,on_r4;
        if (height[t] < 6)
        {
            on_y1 = onARow( Yellow, t, height[t] );
            score += on_y1;
            on_r1 = onARow( Red, t, height[t] );
            score -= on_r1;
        }
        if (height[t] < 5)
        {
            on_y2 = onARow( Yellow, t, height[t] + 1);
            score += on_y2 - 1;
            on_r2 = onARow( Red, t, height[t] + 1);
            score -= on_r2 - 1;
        }
        if (height[t] < 4)
        {
            on_y3 = onARow( Yellow, t, height[t] + 2);
            score += on_y3 - 2;
            on_r3 = onARow( Red, t, height[t] + 2);
            score -= on_r3 - 2;
        }
        if (height[t] < 3)
        {
            on_y4 = onARow( Yellow, t, height[t] + 3);
            score += on_y4 - 3;
            on_r4 = onARow( Red, t, height[t] + 3);
            score -= on_r4 - 3;
        }
        // punten voor dubbel 3
       if (on_y1 >= 3 && on_y2 >= 3)
            score += 10;
        if (on_y2 >= 3 && on_y3 >= 3)
            score += 7;
        if (on_y3 >= 3 && on_y4 >= 3)
            score += 5;

        if (on_r1 >= 3 && on_r2 >= 3)
            score -= 10;
        if (on_r2 >= 3 && on_r3 >= 3)
            score -= 7;
        if (on_r3 >= 3 && on_r4 >= 3)
            score -= 5;

        dummy = onARow ( Yellow, t, height[t] - 1 );
        if (four_on_a_row)
        {
            four_Yellow = TRUE;
            if (debug)
                cout << "YELLOW 4 :" << t << "\n";
        }
        dummy = onARow ( Red, t,  height[t] - 1 );
        if (four_on_a_row)
        {
            four_Red = TRUE;
            if (debug)
                cout << "RED 4 :" << t << "\n";
        }
    }
    if (four_Red)
        score = -50;
    if (four_Yellow)
        score  = 50;
    return score;
}



void MainWidget::endGame(color winner)
{
    if (winner==Yellow)
    {
        KMsgBox::message(0,"","I won");
        newGame();
    }
    else
    {
        KMsgBox::message(0,"","You won");
        newGame();
    }
}


void MainWidget::newGame()
{
    initBoard();
    for (int k = 0;k <= 6; k++)
        for (int l = 0; l <= 5; l++)
            drawCircle(k,l,black);
    if (optionsmenu -> isItemChecked(cs_id))
    {
        board[3][0] = Yellow;
        height[3]++;
        move_yellow[0]=3;
        move_nr_yellow++;
        drawCircle(3,0,brush_yellow);
    }
}

void MainWidget::initBoard()
{
    debug = FALSE;
    for (int k = 0; k <= 6; k++)
        for (int l = 0; l <= 5; l++)
        {
            board[k][l] = Empty;
            height[k] = 0;
        }
    move_nr_red = move_nr_yellow = 0;
    for (int j = 0; j <= 20; j++)
        move_red[j] = move_yellow[j] = Empty;
    movemenu->setItemEnabled (tb_id,FALSE);

/*
    board[0][0]=Red;
    board[0][1]=Yellow;

    board[1][0]=Red;
    board[1][1]=Yellow;
    board[1][2]=Red;
    
    board[2][0]=Yellow;
    board[2][1]=Red;
    board[2][2]=Yellow;
    board[2][3]=Yellow;
    board[2][4]=Yellow;
    
    board[3][0]=Red;
    board[3][1]=Yellow;
    board[3][2]=Red;
    board[3][3]=Yellow;
    board[3][4]=Red;
    
    board[4][0]=Red;
    board[4][1]=Red;
    
    board[6][0]=Yellow;
    
    height[0]=2;
    height[1]=3;
    height[2]=5;
    height[3]=5;
    height[4]=2;
    height[5]=0;
    height[6]=1;
*/
}

int MainWidget::maximum(int a[])
{
    int max = -100;
    int j = 0;
    for (int k = 0; k <= 6; k++)
        if (a[k] > max && height[k] <= 5)
        {j = k;
            max=a[k];
        }
    return j;
}



int MainWidget::onARow (color kl, int x, int y)
// c controleert of de stenen aaneengesloten zijn en van dezelfde
// kleur.
// m is het aantal mogelijke stenen op een rij.
// v telt de aaneengesloten stenen op een rij
//

{
    int t = 0; int teller = 0; int m = 0; int v = 0; int c = 1;
    int i = x; int j = y;  int max = 0; int maxv = 0;
    
    di = no_dir;
    four_on_a_row = false;

    // horizontal controle
    while ((i <= 6 && t <= 3) && (board[i][j] == kl || board[i][j] == Empty))
    {
        if (board[i][j] == kl)
        { teller++; m++; v = v + c; }
        if (board[i][j] == Empty)
        { m++; c = 0; }
        t++; i++;
    }
    t = 0; c = 1; i = x - 1; j = y;
    while ((i >= 0 && t <= 2) && (board[i][j] == kl || board[i][j] == Empty))
    {
        if (board[i][j] == kl)
        { teller++; m++; v = v + c; }
        if (board[i][j] == Empty)
        { m++; c = 0; }
        t++; i--;
    }
    if (m >= 4 && teller > max)
    {max = teller; di = horizontal; }
    if (v >= maxv)
        maxv = v;
    
    // diagonal 1
    t = teller = m = v = 0; c = 1; i = x; j = y;
    while ((i >= 0 &&  j >= 0 && t <= 3) && (board[i][j] == kl || board[i][j] == Empty))
    {
        if (board[i][j] == kl)
        { teller++; m++; v = v + c; }
        if (board[i][j] == Empty)
        { m++; c = 0; }
        t++; i--; j--;
    }
    t = 0; c = 1; i = x + 1; j = y + 1;
    while ((i <= 6 && j <= 5 && t <= 2) && (board[i][j] == kl || board[i][j] == Empty))
    {
        if (board[i][j] == kl)
        { teller++; m++; v = v + c; }
        if (board[i][j] == Empty)
        { m++; c = 0; }
        t++; i++; j++;
    }
    if (m >= 4 && teller > max)
    {max = teller; di = diagonal_1; }
    if (v >= maxv)
        maxv = v;
    
    // diagonal 2
    t = teller = m = v = 0; c = 1; i = x; j = y;
    while ((i >= 0 && j <= 5 && t <= 3) && (board[i][j] == kl || board[i][j] == Empty))
    {
        if (board[i][j] == kl)
        { teller++; m++; v = v + c; }
        if (board[i][j] == Empty)
        { m++; c = 0; }
        t++; i--; j++;
    }
    t = 0; c = 1; i = x + 1; j = y - 1;
    while ((i <= 6 && j >= 0 && t <= 2) && (board[i][j] == kl || board[i][j] == Empty))
    {
        if (board[i][j] == kl)
        { teller++; m++; v = v + c; }
        if (board[i][j] == Empty)
        { m++; c = 0; }
        t++; i++; j--;
    }
    if (m >= 4 && teller > max)
    {max = teller; di = diagonal_2; }
    if (v >= maxv)
        maxv = v;
    
    // vertical controle
    t = teller = m = v = 0; c = 1; i = x; j = y;
    while ((j >= 0 &&  t <= 3) && (board[i][j] == kl || board[i][j] == Empty))
    {
        if (board[i][j] == kl)
        { teller++; m++; v = v + c; }
        if (board[i][j] == Empty)
        { m++; c = 0; }
        t++; j--;
    }
    t = 0; c = 1; i = x; j = y + 1;
    while ((j <= 5 && t <= 2) && (board[i][j] == kl || board[i][j] == Empty))
    {
        if (board[i][j] == kl)
        { teller++; m++; v = v + c; }
        if (board[i][j] == Empty)
        { m++; c = 0; }
        t++; j++;
    }
    if (m >= 4 && teller > max)
    {max = teller; di = vertical; }
    if (v >= maxv)
        maxv = v;
    
    if (maxv >= 4)
        four_on_a_row = true;
        return max;
}

bool MainWidget::isWinner(color cl) // check for winner color
{
    int dummy;
    for (int k=0; k<=6; k++)
        for (int l=0; l<=5; l++)
        {
            dummy = onARow(cl, k, l);
            if (four_on_a_row)
                return four_on_a_row;
        }
    return four_on_a_row;
}
