/*
 * Copyright (C) 2005  SilverSoft.Net
 * All rights reserved
 *
 * $Id: gameboard.h,v 0.1 2005/01/08 13:00:57 denis Exp $
 *
 * Author: Denis Kozadaev (denis@silversoft.net)
 * Description:
 *
 * See also: style(9)
 *
 * Hacked by:
 */

#ifndef GAMEBOARD_H
#define GAMEBOARD_H

#include <QCloseEvent>
#include <QDialog>
#include <QFocusEvent>
#include <QLineEdit>
#include <QMouseEvent>
#include <QPaintEvent>
#include <QPainter>
#include <QPixmap>
#include <QResizeEvent>
#include <QTimer>
#include <QWidget>
#include <stdlib.h>

#define MAX(a, b) (((a) > (b)) ? (a) : (b))
#define SEP ' '
#define EOL '\n'
#define LONG_XCHG "@-@"
#define SHORT_XCHG "o-o"
#define SOCK_WAIT 900
#define GAMEOVER_TXT "****"

class Drawer;
class Figure;
class GameBoard;
class GameProtocol;

class GameBoard : public QWidget {
    Q_OBJECT
public:
    enum GameType { NOGAME = 0x0, BLACK = 0x1, WHITE = 0x2 };

    enum FigureType {
        NONE         = 0x00,
        WHITE_PAWN   = 0x01,
        WHITE_CASTLE = 0x02,
        WHITE_BISHOP = 0x03,
        WHITE_KING   = 0x04,
        WHITE_QUEEN  = 0x05,
        WHITE_KNIGHT = 0x06,
        BLACK_PAWN   = 0x11,
        BLACK_CASTLE = 0x12,
        BLACK_BISHOP = 0x13,
        BLACK_KING   = 0x14,
        BLACK_QUEEN  = 0x15,
        BLACK_KNIGHT = 0x16,
        DUMMY        = 0xFF
    };

    GameBoard(GameType, const QString &, QWidget *parent = NULL, const char *name = NULL);
    GameBoard(int, QWidget *parent = NULL, const char *name = NULL);
    ~GameBoard();

    void saveImage();

    GameType type() const { return (gt); }
    QString  status() const { return (my_stat); }

public slots:
    void receiveData(const QString &data);

private:
    Drawer *      drw;
    GameType      gt;
    FigureType *  map;
    QString       hst, my_stat;
    Q3Socket *    sock;
    Q3GroupBox *  box, *hist;
    QListWidget * lst, *hw, *hb;
    QLineEdit *   edt;
    QTimer *      tmr, *tmr2;
    int           sock_tout;
    GameProtocol *protocol;

    void initMap();
    void parseString(const QString &);
    void updateChat(const QString &);
    void updateHistory(const QString &, bool);
    void updateHistory(int, bool);

protected:
    void resizeEvent(QResizeEvent *);
    void closeEvent(QCloseEvent *);
    void focusInEvent(QFocusEvent *);

private slots:
    void showHostFound();
    void sockConnected();
    void sockRead(const QString &data);
    void sockClosed();
    void sendMove(const QString &);
    void sendText();
    void sendFigure(const QString &, GameBoard::FigureType);
    void sockTest();
    void sockError(int);
    void gameover(int);

signals:
    void showStatus(const QString &);
    void sendData(const QString &data);
};

//-----------------------------------------------------------------------------

class Drawer : public QWidget {
    Q_OBJECT
public:
    Drawer(GameBoard::FigureType *, GameBoard::GameType *, QWidget *parent = NULL, const char *name = NULL);
    ~Drawer();

    void makeMove(const QString &);
    void newFigure(const QString &, int);

private:
    int                    top_margin, left_margin, hl;
    int                    x_brd, y_brd, cs;
    int                    tfx, tfy;
    QPixmap                fig[12];
    GameBoard::FigureType *map;
    GameBoard::GameType *  gt;
    bool                   km, lcm, rcm, kk;

    void drawBoard(QPainter *, int, int);
    void drawMap(QPainter *, int, int);
    void win2map(int &, int &);
    void map2win(int, int, int &, int &);
    void takeFigure(int, int);
    void makeMove(GameBoard::GameType, int, int, int, int, bool, bool);
    bool xchg(GameBoard::FigureType, GameBoard::FigureType, int, int, int, int);
    bool checkWhiteCastle(int, int, int, int, bool);
    bool checkBlackCastle(int, int, int, int, bool);

    bool canTake(int, int);
    bool hasTakenFigure();
    bool makeXchg();

protected:
    void paintEvent(QPaintEvent *);
    void mousePressEvent(QMouseEvent *);

signals:
    void touchFigure(int, int);
    void moved(const QString &);
    void newFigure(const QString &, GameBoard::FigureType);
    void gameover(int);
};

//-----------------------------------------------------------------------------

class FigureDialog : public QDialog {
    Q_OBJECT
public:
    FigureDialog(const QPixmap *, const GameBoard::GameType, QWidget *parent = NULL, const char *name = NULL);
    ~FigureDialog();

    GameBoard::FigureType figure() const { return (fr); }

private:
    GameBoard::GameType   gt;
    const QPixmap *       fig;
    QString               str;
    int                   step, fh;
    GameBoard::FigureType fr;

protected:
    void paintEvent(QPaintEvent *);
    void mousePressEvent(QMouseEvent *);
};

//-----------------------------------------------------------------------------

class Figure {
public:
    static bool hasMyFigure(GameBoard::GameType, GameBoard::FigureType *, int, int, bool);
    static int  hasEnemyFigure(GameBoard::GameType, GameBoard::FigureType *, int, int, bool);
    static bool hasFigure(GameBoard::GameType, GameBoard::FigureType *, int, int, bool);
    static int  map2map(GameBoard::GameType, int, int, bool);
    static int  validMove(GameBoard::GameType, GameBoard::FigureType *, int, int, int, int, bool);

    static void    moveList(Q3PointArray &, GameBoard::GameType, GameBoard::FigureType *, int, int, bool);
    static void    moveListWhitePawn(Q3PointArray &, GameBoard::GameType, GameBoard::FigureType *, int, int, bool);
    static void    moveListBlackPawn(Q3PointArray &, GameBoard::GameType, GameBoard::FigureType *, int, int, bool);
    static void    moveListCastle(Q3PointArray &, GameBoard::GameType, GameBoard::FigureType *, int, int, bool);
    static void    moveListBishop(Q3PointArray &, GameBoard::GameType, GameBoard::FigureType *, int, int, bool);
    static void    moveListKing(Q3PointArray &, GameBoard::GameType, GameBoard::FigureType *, int, int, bool);
    static void    moveListQueen(Q3PointArray &, GameBoard::GameType, GameBoard::FigureType *, int, int, bool);
    static void    moveListKnight(Q3PointArray &, GameBoard::GameType, GameBoard::FigureType *, int, int, bool);
    static bool    hasPoint(const Q3PointArray &, int, int);
    static bool    hasKingsMeeting(GameBoard::GameType, GameBoard::FigureType *, int, int, bool);
    static bool    validPoint(GameBoard::GameType, GameBoard::FigureType *, int, int, bool);
    static QString map2str(int, int);
    static void    str2map(const QString &, int *, int *);
    static int     checkKing(GameBoard::GameType, GameBoard::FigureType *, bool, Q3PointArray &, bool);
};

//-----------------------------------------------------------------------------

class GameProtocol : public QDialog {
    Q_OBJECT
public:
    void send(Q3Socket *, const QString &);
    void setGameType(Q3Socket *, GameBoard::GameType);
    void acceptGame(Q3Socket *);
    void sendMove(Q3Socket *, const QString &);
    void sendQuit(Q3Socket *);
    void sendText(Q3Socket *, const QString &);
    void sendFigure(Q3Socket *, const QString &, int);
    void sendGameover(Q3Socket *, const QString &);
signals:
    void sendData(const QString &data);
};

#endif // GAMEBOARD_H
