#include "Mole.h"
#include <sstream>
#include <iostream>

#include "services/HelloService.hpp"
#include "services/HomepageService.hpp"
#include "services/ConnectionService.hpp"
#include "services/ListChannelsService.hpp"
#include "services/ListUsersService.hpp"
#include "services/JoinChannelService.hpp"

#include "requests/HelloRequest.hpp"
#include "requests/ConnectionRequest.hpp"
#include "requests/JoinChannelRequest.hpp"

#include "requests/xmlrpcpp/HelloRequest.hpp"
#include "requests/xmlrpcpp/ConnectionRequest.hpp"
#include "requests/xmlrpcpp/ListChannelsRequest.hpp"
#include "requests/xmlrpcpp/ListUsersRequest.hpp"
#include "requests/xmlrpcpp/JoinChannelRequest.hpp"
#include "requests/xmlrpcpp/HomepageRequest.hpp"

#include "responses/HomepageResponse.hpp"
#include "responses/HelloResponse.hpp"
#include "responses/ConnectionResponse.hpp"
#include "responses/ListChannelsResponse.hpp"
#include "responses/JoinChannelResponse.hpp"
#include "responses/ListUsersResponse.hpp"

#include "include/XmlRpc.h"
#include "Request.hpp"
#include "Server.hpp"
#include "XmlRpcppClient.hpp"
#include "XmlRpcppServer.hpp"
#include "ServiceManager.hpp"

#include "include/Mole.h"

#define NO_SERV "NOSERVICE"
#define NO_RESP "NORESPONSE"
#define FAILURE "FAILURE"

NS_IMPL_ISUPPORTS1(Mole, IMole)

    using namespace mole;
    using namespace XmlRpc;

Mole::Mole()
{
    /* client / server */
    client = new ctx::xmlrpcpp::XmlRpcppClient(DEFAULT_IP, DEFAULT_PORT, DEFAULT_PATH);
    manager = new serv::ServiceManager(client);
    manager->loadServices();

    /* client / client */
    server = new ctx::xmlrpcpp::XmlRpcppServer(DEFAULT_RPC_PORT);
}

Mole::~Mole()
{
    /* destructor code */
    delete client;
    delete manager;
}


/* string init (in string ip, in string path, in string port); */
NS_IMETHODIMP Mole::Init(const char *ip, const char *path, PRInt32 port, PRBool *_retval)
{
    if (client)
	delete client;

    client = new ctx::xmlrpcpp::XmlRpcppClient(ip, port, path);

    if (manager)
	delete manager;

    manager = new serv::ServiceManager(client);
    manager->loadServices();

    *_retval = true;
    return NS_OK;
}


/* string service (in string entry); */
NS_IMETHODIMP Mole::Hello(const char *entry, char **_retval)
{     
    serv::Service * service = client->getService(std::string(NAME_SERV_HELLO));
    if (service){
	ctx::HelloRequest * request = static_cast <ctx::HelloRequest *> (service->getRequest());
	request->init(std::string(entry));
	if (client->execute(service)){
	    serv::HelloResponse * resp = static_cast <serv::HelloResponse *> (service->getResponse());
	    if (resp && (resp->errorCode() == 0)){
		size_t size = resp->getText().size() + 1;
		char * buffer = new char[size];
		strncpy(buffer, resp->getText().c_str(), size);
		*_retval = buffer;
	    }
	}
	delete service;
    }
    return NS_OK;
}

/* string connect (in string login, in string ip, in string port); */
NS_IMETHODIMP Mole::Connect(const char *login, const char *ip, PRInt32 port, char **_retval)
{
    std::string ret = FAILURE;
    /* Test du service de connection */
    serv::Service * service = client->getService(std::string(NAME_SERV_CONNECT));
    if (service){
	ctx::ConnectionRequest * request = static_cast <ctx::ConnectionRequest *> (service->getRequest());
	request->init(std::string(login), std::string(ip), port);
	if (client->execute(service)){
	    serv::ConnectionResponse * resp = static_cast <serv::ConnectionResponse *> (service->getResponse());
	    if (resp){
		if (resp->errorCode() != 0){
		    std::stringstream out;
		    out << resp->errorCode();
		    ret = out.str();
		} else 
		    ret = resp->getId();
	    } else {
		ret = std::string(NO_RESP);
	    }
	}
    } else {
	ret = std::string(NO_SERV);
    }

    size_t size = ret.size() + 1;
    char * buffer = new char[size];
    strncpy(buffer, ret.c_str(), size);
    *_retval = buffer;
    delete service;
    return NS_OK;
}


/* string joinChannel (in string chan); */
NS_IMETHODIMP Mole::JoinChannel(const char *chan, char **_retval)
{
    std::string ret = FAILURE;
    serv::Service * service = client->getService(NAME_SERV_JOINCHANNEL); 
    if (service){
	ctx::JoinChannelRequest * request = static_cast <ctx::JoinChannelRequest *> (service->getRequest());
	request->init(chan);
	if (client->execute(service)){
	    serv::JoinChannelResponse * resp = static_cast <serv::JoinChannelResponse *> (service->getResponse());
	    if (resp)
		if (resp->errorCode() != 0){
		    std::stringstream out;
		    out << resp->errorCode();
		    ret = out.str();
		} else {
		    ret = resp->getResult();
		}
	    else {
		ret = NO_RESP;
	    }
	}
    }
    else {
	ret = NO_SERV;
    }

    size_t size = ret.size() + 1;
    char * buffer = new char[size];
    strncpy(buffer, ret.c_str(), size);
    *_retval = buffer;
    delete service;
    return NS_OK;
}

/* void ListChannels (out PRUint32 count, [array, size_is (count), retval] out string str); */
NS_IMETHODIMP Mole::ListChannels(PRUint32 *count, char ***str){
    serv::Service * service = client->getService(std::string(NAME_SERV_LISTCHANNELS));
    if (service){
	ctx::ListChannelsRequest * request = static_cast <ctx::ListChannelsRequest *> (service->getRequest());
	if (client->execute(service)){
	    serv::ListChannelsResponse * resp = static_cast <serv::ListChannelsResponse *> (service->getResponse());
	    if (resp && (resp->errorCode() == 0)){
		int scount = resp->channelsCount();
		char** out = (char**) malloc (scount * sizeof(char*));
		size_t size;

		for(int i = 0; i < scount; ++i)
		{		        
		    size = resp->getChannel(i).size() + 1;
		    out[i] = (char*) malloc (size);
		    strncpy(out[i], resp->getChannel(i).c_str(), size);
		}
		*str = out;
		*count = scount;
	    }
	}
	delete service;
    }
    return NS_OK;
}

/* void listChannelUsers (in string chan, out PRUint32 count, [array, size_is (count), retval] out string str); */
NS_IMETHODIMP Mole::ListChannelUsers(const char *chan, PRUint32 *count, char ***str)
{
    serv::Service * service = client->getService(std::string(NAME_SERV_LISTUSERS)); 
    if (service){
	ctx::ListUsersRequest * request = static_cast <ctx::ListUsersRequest *> (service->getRequest());
	request->init(std::string(chan));
	if (client->execute(service)){
	    serv::ListUsersResponse * resp = static_cast <serv::ListUsersResponse *> (service->getResponse());
	    if (resp && resp->errorCode() == 0){
		int scount = resp->usersCount();
		char ** out = (char **) malloc (scount * sizeof(char *));
		size_t size;

		for(int i = 0; i < scount; ++i)
		{   
		    size = resp->getUser(i).size() + 1;
		    out[i] = (char *) malloc (size);
		    strncpy(out[i], resp->getUser(i).c_str(), size);
		}
		*str = out;
		*count = scount;
	    }
	}
	delete service;
    }
    return NS_OK;
}

/* string getHomepage (in string ip, in PRUint32 port); */
NS_IMETHODIMP Mole::GetHomepage(const char *ip, PRUint32 port, char **_retval)
{
    serv::Service * service = client->getService(std::string(NAME_SERV_HOMEPAGE));
    if (service){
	ctx::HomepageRequest * request = static_cast <ctx::HomepageRequest *> (service->getRequest());
	if (client->execute(service)){
	    serv::HomepageResponse * resp = static_cast <serv::HomepageResponse *> (service->getResponse());
	    if (resp){
		std::cout << resp->getContent() << "FEK\n";
		size_t size = resp->getContent().size() + 1;
		char * buffer = new char[size];
		strncpy(buffer, resp->getContent().c_str(), size);
		*_retval = buffer;
	    }
	}
	delete service;
    }
    return NS_OK;
}

