/* Header file */
#include "iMonxpcom.h" // include nsISupports too
#include "nsISimpleEnumerator.h"
#include "nsIGenericFactory.h"
#include <stdlib.h> // for malloc, free
#include "nsISupportsPrimitives.h" // for nsISupportsCString
#include "nsEmbedString.h" // for nsEmbedCString
#include "nsCOMPtr.h" // for nsCOMPtr
#include "nsIComponentManager.h" // for nsIComponentManager

#define MONXPCOM_DESCRIPTION "Monxpcom est mon premier xpcom"
#define MONXPCOM_CID_STR "03b57938-57f6-4dcc-8bde-d69d8c4b572e"
#define MONXPCOM_CID \
  {0x03b57938, 0x57f6, 0x4dcc, \
    { 0x8b, 0xde, 0xd6, 0x9d, 0x8c, 0x4b, 0x57, 0x2e }}

#define MONXPCOM_CONTRACTID "@progysm.no-ip.org/xpcom/monxpcom"

struct urlNode {
  char* urlString;
  urlNode* next;
};

class urlNodeEnumerator : public nsISimpleEnumerator
{
  public:
    NS_DECL_ISUPPORTS
    NS_DECL_NSISIMPLEENUMERATOR

    urlNodeEnumerator(urlNode* node) {
      mNode = node;
    }
    virtual ~urlNodeEnumerator(void) {}

  protected:
    urlNode* mNode;
    nsCOMPtr<nsIComponentManager> mCompMgr;
};

NS_IMPL_ISUPPORTS1(urlNodeEnumerator, nsISimpleEnumerator);

NS_IMETHODIMP
urlNodeEnumerator::HasMoreElements(PRBool* aResult)
{
  if (!aResult)
    return NS_ERROR_NULL_POINTER;

  if (!mNode) {
    *aResult = PR_FALSE;
    return NS_OK;
  }
  *aResult = PR_TRUE;
  return NS_OK;
}

static NS_DEFINE_CID(kSupportsCStringCID, NS_SUPPORTS_CSTRING_CID);

NS_IMETHODIMP
urlNodeEnumerator::GetNext(nsISupports** aResult)
{
  if (!aResult)
    return NS_ERROR_NULL_POINTER;
  *aResult = nsnull;
  if (!mNode)
    return NS_ERROR_FAILURE;
  if (!mCompMgr)
  {
    NS_GetComponentManager(getter_AddRefs(mCompMgr));
    if(!mCompMgr)
      return NS_ERROR_UNEXPECTED;
  }

  nsISupportsCString* stringSupports;
  mCompMgr->CreateInstance(kSupportsCStringCID,
                           nsnull,
                           NS_GET_IID(nsISupportsCString),
                           (void**)&stringSupports);
  if(!stringSupports)
    return NS_ERROR_UNEXPECTED;

  nsEmbedCString str(mNode->urlString);
  stringSupports->SetData(str);

  *aResult = stringSupports; // addref'ed above
  mNode = mNode->next;
  return NS_OK;
}


class Monxpcom : public iMonxpcom
{
public:
  NS_DECL_ISUPPORTS
  NS_DECL_IMONXPCOM

  Monxpcom();

private:
  ~Monxpcom();
  PRBool mLocked;
  urlNode* mRootURLNode;
  NS_IMETHOD clearSiteList();

protected:
  /* additional members */
};

/* Implementation file */
NS_IMPL_ISUPPORTS1(Monxpcom, iMonxpcom)

Monxpcom::Monxpcom()
{
  /* member initializers and constructor code */
  mLocked = PR_FALSE;
  mRootURLNode = nsnull;
}

Monxpcom::~Monxpcom()
{
  /* destructor code */
  //clearSiteList();
}

/* void lock (); */
NS_IMETHODIMP Monxpcom::Lock()
{
    mLocked = PR_FALSE;
    return NS_OK;
}

/* void unlock (); */
NS_IMETHODIMP Monxpcom::Unlock()
{
    mLocked = PR_TRUE;
    return NS_OK;
}

NS_IMETHODIMP Monxpcom::clearSiteList()
{
  urlNode* node = mRootURLNode;
  urlNode* next = nsnull;
  while(node)
  {
    free(node->urlString);
    next = node->next;
    free(node);
    node = next;
  }
  return NS_OK;
}

/* void addSite (in string url); */
NS_IMETHODIMP Monxpcom::AddSite(const char *url)
{
  urlNode* node = (urlNode*) malloc(sizeof(urlNode));
  node->urlString = strdup(url);
  node->next = mRootURLNode;
  mRootURLNode = node;
  return NS_OK;
}

/* void removeSite (in string url); */
NS_IMETHODIMP Monxpcom::RemoveSite(const char *url)
{
  urlNode* node = mRootURLNode;
  urlNode* prev = nsnull;

  while(node)
  {
    if (strcmp(node->urlString, url) == 0)
    {
      free(node->urlString);
      if (prev)
        prev->next = node->next;
      free(node);
      return NS_OK;
    }
    prev = node;
    node = node->next;
  }
  return NS_ERROR_FAILURE;
}

/* attribute nsISimpleEnumerator sites; */
NS_IMETHODIMP Monxpcom::GetSites(nsISimpleEnumerator * *aSites)
{
  urlNodeEnumerator* enumerator = new urlNodeEnumerator(mRootURLNode);
  if (!enumerator)
    return NS_ERROR_OUT_OF_MEMORY;
  NS_ADDREF(*aSites = enumerator);

  return NS_OK;
}

NS_IMETHODIMP Monxpcom::SetSites(nsISimpleEnumerator * aSites)
{
  PRBool more = PR_TRUE;
  while(more)
  {
    nsCOMPtr<nsISupports> supports;
    aSites->GetNext(getter_AddRefs(supports));

    nsCOMPtr<nsISupportsCString> supportsString = do_QueryInterface(supports);

    if (supportsString)
    {
      nsEmbedCString url;
      supportsString->GetData(url);
      AddSite(url.get());
    }

    aSites->HasMoreElements(&more);
  }
  return NS_OK;
}

/* End of implementation class template. */

NS_GENERIC_FACTORY_CONSTRUCTOR(Monxpcom)

static NS_METHOD MonxpcomRegistration(nsIComponentManager *aCompMgr, 
                                      nsIFile *aPath, 
                                      const char *registryLocation, 
                                      const char *componentType, 
                                      const nsModuleComponentInfo *info)
{
    return NS_OK;
}
static NS_METHOD MonxpcomUnregistration(nsIComponentManager *aCompMgr, 
                                        nsIFile *aPath, 
                                        const char *registryLocation, 
                                        const nsModuleComponentInfo *info)
{
    return NS_OK;
}

static const nsModuleComponentInfo components[] = 
{
  {
    MONXPCOM_DESCRIPTION,
    MONXPCOM_CID,
    MONXPCOM_CONTRACTID,
    MonxpcomConstructor,
    MonxpcomRegistration,
    MonxpcomUnregistration
  }
};

NS_IMPL_NSGETMODULE(Monxpcom, components)
