#include <stdio.h>

#include "nsCLABCMSDecoder.h"
#include "nsReadableUtils.h"
#include "nsComponentManagerUtils.h"
#include "nsCLABCMSMessage.h"
#include "nsMemory.h"


NS_IMPL_ISUPPORTS1(nsCLABCMSDecoder, nsICLABCMSDecoder)

/* void *arg, const char *buf, unsigned long len */
static void myCallback(void *arg,const char *buf,unsigned long len)
{
  nsCLABCMSDecoder * enc = (nsCLABCMSDecoder *) arg;
  enc->Eat(buf,len);
}

nsCLABCMSDecoder::nsCLABCMSDecoder()
{
  NS_INIT_ISUPPORTS();
  /* member initializers and constructor code */
  dec = do_CreateInstance(NS_CMSDECODER_CONTRACTID);
  output = nsnull;
}

nsCLABCMSDecoder::~nsCLABCMSDecoder()
{
  /* destructor code */
}

/* void start (in nsIOutputStream output); */
NS_IMETHODIMP nsCLABCMSDecoder::Start(nsIOutputStream *output)
{
  this->output = output;
  eating_ns_error = NS_OK;
  eating_error = 0;

  return dec->Start(myCallback,(void *)this);
}

/* void update (in string aBuf, in long aLen); */
NS_IMETHODIMP nsCLABCMSDecoder::Update(const char *aBuf, PRInt32 aLen)
{
  return dec->Update(aBuf,aLen);
}

/* void updateIstream (in nsIInputStream input); */
NS_IMETHODIMP nsCLABCMSDecoder::UpdateIstream(nsIInputStream *input)
{
    return NS_ERROR_NOT_IMPLEMENTED;
}

/* void finish ([retval] out nsICLABCMSMessage msg); */
NS_IMETHODIMP nsCLABCMSDecoder::Finish(nsICLABCMSMessage **msg)
{
  nsresult rv;
  nsCOMPtr<nsICMSMessage> cmsMsg;
  *msg = nsnull;

  rv = dec->Finish(getter_AddRefs(cmsMsg));
  if (NS_FAILED(rv))
    return rv;

  if (!cmsMsg)
    return NS_ERROR_FAILURE;

  nsCLABCMSMessage* obj;

  obj = new nsCLABCMSMessage(cmsMsg);
  NS_ENSURE_TRUE(obj, NS_ERROR_OUT_OF_MEMORY);
  
  NS_ADDREF(obj);

  rv = CallQueryInterface(obj, msg);

  NS_RELEASE(obj);

  return rv;
}

/* void decode (in nsIOutputStream output, in nsIInputStream input, [retval] out nsICLABCMSMessage msg); */
NS_IMETHODIMP nsCLABCMSDecoder::Decode(nsIOutputStream *output, nsIInputStream *input, nsICLABCMSMessage **msg)
{
  nsresult rv;

  this->output = output;
  rv = Start(output);
  if (NS_FAILED(rv)){
    return rv;
  }
  if (input != nsnull){
    rv = UpdateIstream(input);
    if (NS_FAILED(rv)){
      return rv;
    }
  }
  return  Finish(msg);
}


void nsCLABCMSDecoder::Eat(const char *buf,unsigned long len)
{
  nsresult rv;
  PRUint32 written;

  if (eating_error)
    return;

  if (!output){
    eating_error = 1;
    eating_ns_error = NS_ERROR_NULL_POINTER;
    return;
  }
    
  rv = output->Write((char *)buf,(PRUint32)len,&written);

  if (NS_FAILED(rv)){
    eating_ns_error = rv;
    eating_error = 1;
  }
  if (len != written){
    eating_error = rv;
    eating_ns_error =  NS_ERROR_FAILURE;//NS_ERROR_CANNOT_CONVERT_DATA;
  }
}
