/*
	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/>.
 */

#include "P2PNetwork.h"
#include "Utility.h"
#include "World.h"
#include "MainFrame.h"

BEGIN_EVENT_TABLE(P2PNetwork,wxEvtHandler)
	EVT_SOCKET(P2PNetwork::ID_SOCKET_SERVER,P2PNetwork::onServerSocketEvent)
	EVT_SET(P2PNetwork::onSet)
END_EVENT_TABLE()

P2PNetwork::P2PNetwork(uint16_t listenPort,const wxString &initNodeHost,uint16_t initNodePort) : error(false) {
	wxIPV4address addr;

	addr.Service(listenPort);

	//サーバーソケットを作成
	serverSocket=new wxSocketServer(addr);

	if ((!serverSocket->Ok())||serverSocket->Error()) {
		error=true;
		return;
	}

	serverSocket->SetEventHandler(*this,ID_SOCKET_SERVER);
	serverSocket->SetNotify(wxSOCKET_CONNECTION_FLAG);

	if (!initNodeHost.IsEmpty()) {
		//初期ノードに接続
		wxIPV4address initNodeAddr;
		Node *initNode;
		wxSocketClient *client;

		initNodeAddr.Hostname(initNodeHost);
		initNodeAddr.Service(initNodePort);

		client=new wxSocketClient;
		if (!client->Connect(initNodeAddr,true)) {
			error=true;
			client->Destroy();
			serverSocket->Destroy();
			return;
		}

		initNode=new Node(*client,nodes,nodeListLockMutex,*this);
		initNode->sendJoin(listenPort);
		initNode->getNodeList(listenPort);
	}

	serverSocket->Notify(true);
	for (Nodes::iterator i=nodes.begin();i!=nodes.end();++i) (*i)->Run();
}

P2PNetwork::~P2PNetwork() {
	//切断
	wxMutexLocker locker(nodeListLockMutex);

	while(nodes.size()) (*nodes.begin())->stop();
	serverSocket->Destroy();
}

void P2PNetwork::onServerSocketEvent(wxSocketEvent &event) {
	switch(event.GetSocketEvent()) {
	case wxSOCKET_CONNECTION: {
		//接続受付
		wxSocketBase *newClient;
		Node *newNode;
		wxMutexLocker locker(nodeListLockMutex);

		newClient=serverSocket->Accept(true);
		if (!newClient) break;

		newNode=new Node(*newClient,nodes,nodeListLockMutex,*this);
		newNode->Run();

		break;
	}
	default:
		break;
	}
}

void P2PNetwork::sendPosition(const Point3d &position) {
	wxMutexLocker locker(nodeListLockMutex);

	for (Nodes::const_iterator i=nodes.begin();i!=nodes.end();++i) (*i)->sendPosition(position);
}

void P2PNetwork::sendMessage(const wxString &message) {
	wxMutexLocker locker(nodeListLockMutex);

	for (Nodes::const_iterator i=nodes.begin();i!=nodes.end();++i) (*i)->sendMessage(message);
}

void P2PNetwork::sendName(const wxString &name) {
	wxMutexLocker locker(nodeListLockMutex);

	for (Nodes::const_iterator i=nodes.begin();i!=nodes.end();++i) (*i)->sendName(name);
}

void P2PNetwork::sendMap(const Map &map) {
	wxMutexLocker locker(nodeListLockMutex);

	for (Nodes::const_iterator i=nodes.begin();i!=nodes.end();++i) (*i)->sendMap(map);
}

void P2PNetwork::drawCharacter() {
	wxMutexLocker locker(nodeListLockMutex);

	for (Nodes::const_iterator i=nodes.begin();i!=nodes.end();++i) (*i)->drawCharacter();
}

void P2PNetwork::onSet(class SetEvent &event) {
	event.set();
}
