#ifndef QzCrossWord_H
#define QzCrossWord_H

#include <qobject.h>
#include <qobjectlist.h>
#include <qwidget.h>
#include <qpainter.h>
#include <qcolor.h>
#include <qfontmetrics.h>
#include <qstring.h>
#include <qlistbox.h>
#include <qlayout.h>
#include <qsplitter.h>
#include <qmainwindow.h>
#include <qmenubar.h>
#include <qpopupmenu.h>
#include <qvgroupbox.h>
#include <qhgroupbox.h>
#include <qvbox.h>
#include <qvaluevector.h>
#include <qmessagebox.h>
#include "libacrosslite.h"

class QzCrossWordClue : public QListBoxText {
    public:
       QzCrossWordClue (const int number, QListBox* listbox, const QString& text=QString::null);
       QzCrossWordClue (const int number, const QString& text=QString::null);
       QzCrossWordClue (const int number, QListBox* listbox, const QString& text, QListBoxItem* after);
      ~QzCrossWordClue ();

       int                                  number               () const;

    private:
       int                                  _number;
};

class QzCrossWordClueList : public QListBox {
    Q_OBJECT

    public:
        QzCrossWordClueList ( AcrossLitePuzzleBase* puzzle, AcrossLiteClue::Orientation clueList, QWidget* parent, char* name = 0 );
        QzCrossWordClueList ( QWidget* parent, char* name = 0 );
       ~QzCrossWordClueList ();

        void                                setPuzzle           (AcrossLitePuzzleBase* puzzle, AcrossLiteClue::Orientation clueList);
        AcrossLitePuzzleBase*               puzzle              ();
        AcrossLiteClue::Orientation         clueList            ();

    signals:
        void                                clueSelected        (AcrossLiteClue::Orientation o, int number);
 
    public slots:
        void                                clueSelected        (int number);

    private slots:
        void                                _selected           (QListBoxItem* item);

    private:
        QzCrossWordClueList ( );

        AcrossLitePuzzleBase*               _puzzle;
        AcrossLiteClue::Orientation         _clueList;
};

class QzCrossWordCell : public QWidget {
    Q_OBJECT

    public:
        QzCrossWordCell (QWidget* parent, char* name = 0);
       ~QzCrossWordCell ();

        void                                setColRowLabel      (const int col, const int row);
        int                                 colLabel            () const;
        int                                 rowLabel            () const;
        void                                setSolution         (const char letter);
        void                                setGuess            (const char letter);
        char                                solution            () const;
        char                                guess               () const;
        void                                revealSolution      (const bool flag);
        bool                                isSolutionRevealed  () const;
        void                                setShowCorrectness  (const bool flag);
        bool                                showCorrectness     () const;
        bool                                isSolutionCorrect   () const;
        void                                setNumber           (const int number = 0);
        int                                 number              () const;
        void                                showNumber          (const bool flag);
        bool                                isNumberShown       () const;
        void                                hilite              (const bool flag);
        bool                                isHilited           () const;

        virtual QSize                       sizeHint            () const;
        virtual QSizePolicy                 sizePolicy          () const;
        virtual void                        paintEvent          (QPaintEvent* e);
        virtual void                        paintNumber         (QPainter& p);
        virtual void                        paintFrame          (QPainter& p);
        virtual void                        paintLetter         (QPainter& p);
        virtual void                        paintBlock          (QPainter& p);

    private:
        QzCrossWordCell ();

        int                                 _colLabel;
        int                                 _rowLabel;
        char                                _solution;
        char                                _guess;
        bool                                _isSolutionRevealed;
        bool                                _showCorrectness;
        int                                 _number;
        bool                                _isNumberShown;
        bool                                _isHilited;
};

class QzCrossWordGrid : public QWidget {
    Q_OBJECT

    public:

        enum FocusOrientation {
            FocusUnknown    = 0,
            FocusHorizontal = 1,
            FocusVertical   = 2
        };

        QzCrossWordGrid (QWidget* parent, char* name = 0);
        QzCrossWordGrid (AcrossLitePuzzleBase* puzzle, QWidget* parent, char* name = 0);
       ~QzCrossWordGrid ();

        void                                setPuzzle           (AcrossLitePuzzleBase* puzzle);
        AcrossLitePuzzleBase*               puzzle              ();
        void                                savePuzzle          (const QString& filename);

        void                                revealSolution      (const bool flag);
        void                                revealWord          (const bool flag);
        void                                revealLetter        (const bool flag);
        void                                uncheckSolution     ();
        void                                checkSolution       ();
        void                                checkWord           ();
        void                                checkLetter         ();

        QzCrossWordCell*                    focusCell           ();
        QzCrossWordCell*                    cell                (const int col, const int row);
        QzCrossWordCell*                    cell                (const int number);
        void                                setFocusCell        (const int col, const int row);
        void                                retreatFocusCell    ();
        void                                advanceFocusCell    (const int count=1);
        void                                setFocusOrientation (const QzCrossWordGrid::FocusOrientation orientation);
        QzCrossWordGrid::FocusOrientation   focusOrientation    () const;

        void                                hiliteSolution      (const bool flag);
        void                                hiliteFullSolution  (const bool flag);

        void                                colRowToDownAcross  (const int col, const int row, int& down, int& across);

        virtual QSize                       minimumSizeHint     () const;
        virtual QSize                       sizeHint            () const;
        virtual QSizePolicy                 sizePolicy          () const;
        virtual void                        keyPressEvent       (QKeyEvent*   e);
        virtual void                        mousePressEvent     (QMouseEvent* e);
        virtual bool                        eventFilter         (QObject* o, QEvent *e);

    public slots:
        void                                setFocusCell        (AcrossLiteClue::Orientation o, int number);

    signals:
        void                                rowFocused          (int row);
        void                                colFocused          (int col);
        void                                colRowFocused       (int col, int row);

    private:
        QzCrossWordGrid ();

        AcrossLitePuzzleBase*               _puzzle;
        QGridLayout*                        _gridLayout;
        FocusOrientation                    _focusOrientation;
        QValueVector<QzCrossWordCell*>      _cells;
};

class QzCrossWord : public QWidget {
    Q_OBJECT

    public:
        QzCrossWord (QWidget* parent, char* name = 0);
       ~QzCrossWord ();

        void                                setPuzzle               (const QString& filename);
        void                                savePuzzle              (const QString& filename);

        void                                clearSolution           ();
        void                                revealSolution          (const bool flag);
        void                                revealWord              (const bool flag);
        void                                revealLetter            (const bool flag);
        void                                checkSolution           ();
        void                                checkWord               ();
        void                                checkLetter             ();

    public slots:
        void                                handleNewColRowFocused  (int newCol, int newRow);

    private:
       AcrossLitePuzzleBase*                _puzzle;
       QHGroupBox*                          _puzzleGroupBox;
       QzCrossWordGrid*                     _grid;
       QzCrossWordClueList*                 _acrossClues;
       QzCrossWordClueList*                 _downClues;
};

#endif

