/*
	AramakiOnline
	Copyright (C) 2008 superbacker

	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 3 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
	program. If not, see <http://www.gnu.org/licenses/>.
 */

#ifndef NODE_H_
#define NODE_H_

#include <wx/wx.h>
#include <wx/socket.h>
#include <wx/thread.h>
#include "Point3d.h"
#include "Map.h"
#include "Character.h"
#include <wx/sckstrm.h>
#include <wx/datstrm.h>
#include <list>

class P2PNetwork;

//イベント定義
BEGIN_DECLARE_EVENT_TYPES()
    DECLARE_EVENT_TYPE(wxEVT_SET,1)
END_DECLARE_EVENT_TYPES()

class SetEvent : public wxEvent {
protected:
	Character &character;
public:
	SetEvent(Character &character) : wxEvent(0,wxEVT_SET),character(character) {}
	virtual void set()=0;
};

//名前設定イベント
class SetNameEvent : public SetEvent {
	wxString name;
public:
	SetNameEvent(Character &character,const wxString &name) : SetEvent(character),name(name) {}

	wxEvent *Clone() const {
		return new SetNameEvent(*this);
	}

	void set();
};

//発言イベント
class SetMessageEvent : public SetEvent {
	wxString message;
public:
	SetMessageEvent(Character &character,const wxString &message) : SetEvent(character),message(message) {}

	wxEvent *Clone() const {
		return new SetMessageEvent(*this);
	}

	void set();
};

//イベントハンドラ定義
typedef void (wxEvtHandler::*SetEventFunction)(class SetEvent &);

#define EVT_SET(fn) \
    DECLARE_EVENT_TABLE_ENTRY( \
        wxEVT_SET,0,wxID_ANY, \
        (wxObjectEventFunction)(wxEventFunction)wxStaticCastEvent(SetEventFunction,&fn), \
        (wxObject *)NULL \
    ),

//ノードリスト
class Node;
typedef std::list<Node *> Nodes;

class Node : public wxThread {
	//メッセージのタイプ
	enum {
		MESSAGE_TYPE_JOIN,
		MESSAGE_TYPE_SET_NAME,
		MESSAGE_TYPE_SET_POSITION,
		MESSAGE_TYPE_SET_MESSAGE,
		MESSAGE_TYPE_CHANGE_MAP,
		MESSAGE_TYPE_GET_NODE_LIST
	};

	wxSocketBase &socket;

	//入出力ストリーム
	wxSocketStream socketStream;
	wxDataInputStream inputStream;
	wxDataOutputStream outputStream;

	Nodes &nodes;

	//接続受付ポート
	uint16_t listenPort;
	//現在いるマップのXMLファイル名
	wxString map;
	//ノードリストロック用Mutex
	wxMutex &nodeListLockMutex;

	Character character;
	P2PNetwork &network;

	//削除中フラグ
	bool deleting;

	//エントリーポイント
	ExitCode Entry();

	Node(const Node &);
	void operator=(const Node &);

	~Node();
public:
	Node(wxSocketBase &socket,Nodes &nodes,wxMutex &nodeListLockMutex,P2PNetwork &network);
	//ネットワーク参加メッセージを受信
	void receiveJoin();
	//名前設定メッセージを受信
	void receiveSetName();
	//位置設定メッセージを受信
	void receiveSetPosition();
	//発言メッセージを受信
	void receiveSetMessage();
	//マップ変更メッセージを受信
	void receiveChangeMap();
	//ノードリスト要求メッセージを受信
	void receiveGetNodeList();
	//ネットワーク参加メッセージを送信
	void sendJoin(uint16_t listenPort);
	//名前を送信
	void sendName(const wxString &name);
	//位置を送信
	void sendPosition(const Point3d &position);
	//発言を送信
	void sendMessage(const wxString &message);
	//マップ移動を送信
	void sendMap(const Map &map);
	//ノードリストを取得
	void getNodeList(uint16_t listenPort);
	//スレッドを停止して削除
	void stop();

	inline void renderCharacter() const {
		character.render();
	}

	inline const wxString &getMap() const {
		return map;
	}
};

#endif /* NODE_H_ */
