/*
 * gamesessionlist.cpp - Battleship game plugin
 * Copyright (C) 2014  Aleksey Andreev
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 *
 */

#ifndef GAMESESSIONLIST_H
#define GAMESESSIONLIST_H

#include <QObject>
#include <QDomElement>
#include <QHash>
#include <QPointer>
#include <QDateTime>
#include <QTimer>

#include "pluginwindow.h"

class GameSession;

namespace XML {
	QString escapeString(const QString &str);
	QString iqErrorString(const QString &jid, const QString &id);
}

class GameSessionList : public QObject
{
Q_OBJECT

public:
	static GameSessionList *instance();
	static void reset();
	GameSession *createSession(int account, const QString &jid, bool first, const QString &gameId);
	void updateGameKey(GameSession *gs);
	void removeGame(GameSession *gs);
	GameSession *findGame(int account, const QString &jid, const QString &gameId);
	GameSession *findGameByStanzaId(int account, const QString &jid, const QString &stanzaId);
	bool processIncomingIqStanza(int account, const QDomElement &xml, const QString &accStatus, bool fromPrivate);
	void invite(int account, const QString &jid, const QStringList &resList);
	QString getStanzaId(bool bigOffset);
	void sendErrorIq(int account, const QString &jid, const QString &id);

private:
	GameSessionList(QObject *parent = 0);
	~GameSessionList();
	QString generateKey(int account, const QString &jid, const QString &gameId);
	static QString getErrorMessage(const QDomElement &xml);

private:
	static GameSessionList *instance_;
	QHash<QString, GameSession *> list_;
	int stanzaId_;

signals:
	void sendStanza(int, QString);
	void doPopup(QString);
	void playSound(QString);
	void doInviteEvent(int, QString, QString, QObject *, const char *);

};

class GameSession : public QObject
{
Q_OBJECT

public:
	enum GameStage { StageNone, StageInvitation, StageInitBoard, StageShooting, StageShowBoard, StageEnd };
	enum GameStatus
	{
		StatusNone, StatusError,
		StatusWaitInviteConfirmation, StatusWaitBoardVerification,
		StatusWaitShotConfirmation, StatusWaitOpponent
	};
	typedef QPointer<QTimer> Timer;
	typedef QPointer<QDialog> InviteDlg;
	typedef QPointer<PluginWindow> BoardWidget;
	void executeNextAction();
	void invite(const QStringList &resList);
	void initOpponentBoard(const QDomElement &xml);
	void checkOpponentBoard(const QDomElement &xml);
	void opponentTurn(const QDomElement &xml);
	bool handleTurnResult(const QDomElement &xml);

private:
	friend class GameSessionList;
	GameSession(GameSessionList *gsl, int account, const QString &jid, bool first, const QString &gameId);
	~GameSession();
	void processIncomingInvite();
	void appendInvitationEvent();
	void generateGameId();
	void sendIqResponse(const QString &id);
	void sendStanzaResult(const QString &id, const QString &body = QString());
	void initBoard();
	void setError();
	void startGame();
	bool checkEndGame();
	bool isMyNextTurn();
	void sendUncoveredBoard();
	void setTimer();

private:
	GameSessionList *gsl_;
	GameStage       stage_;
	GameStatus      status_;
	int             account_;
	QString         jid_;
	bool            first_;
	QString         gameId_;
	QString         stanzaId_;
	QDateTime       modifTime_;
	Timer           timer_;
	InviteDlg       inviteDlg_;
	BoardWidget     boardWid_;
	bool            myBoardChecked_;
	bool            opBoardChecked_;
	bool            resign_;
	//int             lastTurnPos_;
	//bool            lastTurnMy_;
	QString         lastTurnResult_;
	QString         lastTurnSeed_;
	QString         boardStatus_;

private slots:
	void sendInvite(QString jid, bool first);
	void acceptInvitation();
	void rejectInvitation();
	void endSession();
	void boardEvent(QString data);
	void timeout();

public slots:
	void showInvitationDialog();

signals:
	void sendStanza(int, QString);
	void doPopup(const QString);
	void playSound(const QString);
	void doInviteEvent(int, QString, QString, QObject *, const char *);

};

#endif // GAMESESSIONLIST_H
