/////////////////////////////////////////////////////////////////////////////
// Name:        server.cpp
// Purpose:     Simple Soap Server
// Author:      Guy
// Modified by:
// Created:     21/08/2002
// Copyright:   (c) 2002 Guy
// Licence:     wxWindows licence
/////////////////////////////////////////////////////////////////////////////

// ==========================================================================
// declarations
// ==========================================================================

// --------------------------------------------------------------------------
// headers
// --------------------------------------------------------------------------

#include <wx/wx.h>
#include <wx/socket.h>
#include "wx/wfstream.h"

#include <wx/config.h>
#include <wx/msw/iniconf.h> 

#include "http.h"
#include "soap.h"

// --------------------------------------------------------------------------
// classes
// --------------------------------------------------------------------------

// Define a new application type
class SoapServerApp : public wxApp
{
	wxEvtHandler* m_server;

public:
  virtual bool OnInit();
  virtual int OnExit();
};

enum 
{
  SERVER_ID = 1001,
  SOCKET_ID = 1002
};

class SoapServer : public wxEvtHandler
{
  wxSocketServer* m_server;
	wxFileOutputStream* m_log;

protected:
	int GetDefaultPort() const;
	void AppendText(const char* str);
  void ProcessSoapCommand(wxSocketBase *sock);

public:
	bool Ok() const { return m_server->Ok(); }
	SoapServer();
	~SoapServer();

  void OnServerEvent(wxSocketEvent& event);
  void OnSocketEvent(wxSocketEvent& event);
	DECLARE_EVENT_TABLE();
};

BEGIN_EVENT_TABLE(SoapServer, wxEvtHandler)
  EVT_SOCKET(SERVER_ID, SoapServer::OnServerEvent)
  EVT_SOCKET(SOCKET_ID, SoapServer::OnSocketEvent)
END_EVENT_TABLE()

void SoapServer::AppendText(const char* str)
{
	*m_log << str << "\r\n";
}

void SoapServer::ProcessSoapCommand(wxSocketBase *sock)
{
	sock->SetFlags(wxSOCKET_NOWAIT);

  // Read the data
  wxChar buf[4096]; memset(buf, 0, sizeof(buf));
 	unsigned int len = sock->Read(buf, sizeof(buf)).LastCount();
	AppendText(buf);

	wxString str;
	if (strncmp(buf, "POST", 4) == 0)
	{	
		wxString strAnswer = SoapProcessMessage(buf, len);
    sock->Write(strAnswer, strAnswer.Length());
    AppendText(strAnswer);
	} else
	if (strncmp(buf, "GET ", 4) == 0)
	{
		str = buf;
		HttpProcessMessage(str, sock, *m_log);
	}
}


void SoapServer::OnServerEvent(wxSocketEvent& event)
{
  wxString s = "OnServerEvent: ";

  switch(event.GetSocketEvent())
  {
    case wxSOCKET_CONNECTION : s.Append("wxSOCKET_CONNECTION"); break;
    default                  : s.Append("Unexpected event!"); break;
  }

  AppendText(s);

  // Accept new connection if there is one in the pending
  // connections queue, else exit. We use Accept(FALSE) for
  // non-blocking accept (although if we got here, there
  // should ALWAYS be a pending connection).

  wxSocketBase* sock = m_server->Accept(FALSE);
  if (sock)
  {
    AppendText("New client connection accepted");
  }
  else
  {
    AppendText("Error: couldn't accept a new connection");
    sock->Destroy();
    return;
  }

  sock->SetEventHandler(*this, SOCKET_ID);
  sock->SetNotify(wxSOCKET_INPUT_FLAG | wxSOCKET_LOST_FLAG);
  sock->Notify(TRUE);
}

void SoapServer::OnSocketEvent(wxSocketEvent& event)
{
  wxString s = "OnSocketEvent: ";
  wxSocketBase *sock = event.GetSocket();

  // First, print a message
  switch(event.GetSocketEvent())
  {
    case wxSOCKET_INPUT : s.Append("wxSOCKET_INPUT\n"); break;
    case wxSOCKET_LOST  : s.Append("wxSOCKET_LOST\n"); break;
    default             : s.Append("Unexpected event !\n"); break;
  }

  AppendText(s);

  // Now we process the event
  switch(event.GetSocketEvent())
  {
    case wxSOCKET_INPUT:
    {
      // We disable input events, so that the test doesn't trigger
      // wxSocketEvent again.
      sock->SetNotify(wxSOCKET_LOST_FLAG);

			ProcessSoapCommand(sock);

      // Enable input events again.
      sock->SetNotify(wxSOCKET_LOST_FLAG | wxSOCKET_INPUT_FLAG);
      break;
    }
    case wxSOCKET_LOST:
    {
      // Destroy() should be used instead of delete wherever possible,
      // due to the fact that wxSocket uses 'delayed events' (see the
      // documentation for wxPostEvent) and we don't want an event to
      // arrive to the event handler (the frame, here) after the socket
      // has been deleted. Also, we might be doing some other thing with
      // the socket at the same time; for example, we might be in the
      // middle of a test or something. Destroy() takes care of all
      // this for us.

      AppendText("Deleting socket.");
      sock->Destroy();
      break;
    }
    default: ;
  }
}

int SoapServer::GetDefaultPort() const
{
	int nPort = 3883;
  wxIniConfig ini("", "", "./campo.ini");
	ini.SetPath("/Server");
	const wxString str = ini.Read("Dictionary", "");
	const int colon = str.Find(':');
  if (colon > 0)
		nPort = atoi(str.Mid(colon+1));
	return nPort;
}

SoapServer::SoapServer()
{
  // Create the address - defaults to localhost:0 initially
  wxIPV4address addr;
  addr.Service(GetDefaultPort());

  // Create the socket
  m_server = new wxSocketServer(addr);

	m_log = new wxFileOutputStream("soaplog.txt");

	wxString str;

	// We use Ok() here to see if the server is really listening
  if (m_server->Ok())
  {
		// Setup the event handler and subscribe to connection events
		m_server->SetEventHandler(*this, SERVER_ID);
		m_server->SetNotify(wxSOCKET_CONNECTION_FLAG);
		m_server->Notify(TRUE);

		str << "Server listening on port " << addr.Service();
	}
  else
  {
		str << "Could not listen to port " << addr.Service();
  }
	AppendText(str);
}

SoapServer::~SoapServer()
{
	delete m_server;
	delete m_log;
}

IMPLEMENT_APP(SoapServerApp)

bool SoapServerApp::OnInit()
{
  m_server = new SoapServer;
	return TRUE;
}

int SoapServerApp::OnExit()
{
	delete m_server;
	return wxApp::OnExit();
}