/******************************************************************
*  $Id: soap-client.c,v 1.23 2006/02/18 20:14:36 snowdrop Exp $
*
* CSOAP Project:  A SOAP client/server library in C
* Copyright (C) 2003  Ferhat Ayaz
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA  02111-1307, USA.
* 
* Email: ayaz@jprogrammer.net
******************************************************************/
#include <libcsoap/soap-client.h>
#include <nanohttp/nanohttp-client.h>
#include <string.h>

/*--------------------------------- */
static int _block_socket = 0;
static herror_t _soap_client_build_result(hresponse_t * res, SoapEnv ** out);
/*--------------------------------- */

void
soap_client_block_socket(int block)
{
  _block_socket = block;
}

int
soap_client_get_blockmode()
{
  return _block_socket;
}

herror_t
soap_client_init_args(int argc, char *argv[])
{

  return httpc_init(argc, argv);

}

void
soap_client_destroy()
{
  httpc_destroy();
}

herror_t
soap_client_invoke(SoapCtx * call, SoapCtx ** response, const char *url,
                   const char *soap_action)
{
  /* Status */
  herror_t status;

  /* Result document */
  SoapEnv *res_env;

  /* Buffer variables */
  xmlBufferPtr buffer;
  char *content;
  char tmp[15];

  /* Transport variables */
  httpc_conn_t *conn;
  hresponse_t *res;

  /* multipart/related start id */
  char start_id[150];
  static int counter = 1;
  part_t *part;

  /* for copy attachments */
  char href[MAX_HREF_SIZE];

  /* Create buffer */
  buffer = xmlBufferCreate();
  xmlNodeDump(buffer, call->env->root->doc, call->env->root, 1, 0);
  content = (char *) xmlBufferContent(buffer);

  /* Transport via HTTP */
  conn = httpc_new();
  if (!conn)
  {
    return herror_new("soap_client_invoke", SOAP_ERROR_CLIENT_INIT,
                      "Unable to create SOAP client!");
  }
  conn->sock.block = soap_client_get_blockmode();

  /* Set soap action */
  if (soap_action != NULL)
  {
    httpc_set_header(conn, "SoapAction", soap_action);
  }

  /* check for attachments */
  if (!call->attachments)
  {
    /* content-type is always 'text/xml' */
    httpc_set_header(conn, HEADER_CONTENT_TYPE, "text/xml");

    sprintf(tmp, "%d", (int) strlen(content));
    httpc_set_header(conn, HEADER_CONTENT_LENGTH, tmp);
    status = httpc_post_begin(conn, url);

    if (status != H_OK)
    {
      httpc_close_free(conn);
      xmlBufferFree(buffer);
      return status;
    }

    status = http_output_stream_write_string(conn->out, content);
    if (status != H_OK)
    {
      httpc_close_free(conn);
      xmlBufferFree(buffer);
      return status;
    }

    status = httpc_post_end(conn, &res);
    if (status != H_OK)
    {
      httpc_close_free(conn);
      xmlBufferFree(buffer);
      return status;
    }
  }
  else
  {

    /* Use chunked transport */
    httpc_set_header(conn, HEADER_TRANSFER_ENCODING,
                     TRANSFER_ENCODING_CHUNKED);

    sprintf(start_id, "289247829121218%d", counter++);
    status = httpc_mime_begin(conn, url, start_id, "", "text/xml");
    if (status != H_OK)
    {
      httpc_close_free(conn);
      xmlBufferFree(buffer);
      return status;
    }

    status = httpc_mime_next(conn, start_id, "text/xml", "binary");
    if (status != H_OK)
    {
      httpc_close_free(conn);
      xmlBufferFree(buffer);
      return status;
    }

    status = http_output_stream_write(conn->out, content, strlen(content));
    if (status != H_OK)
    {
      httpc_close_free(conn);
      xmlBufferFree(buffer);
      return status;
    }


    for (part = call->attachments->parts; part; part = part->next)
    {
      status = httpc_mime_send_file(conn, part->id,
                                    part->content_type,
                                    part->transfer_encoding, part->filename);
      if (status != H_OK)
      {
        log_error2("Send file failed. Status:%d", status);
        httpc_close_free(conn);
        xmlBufferFree(buffer);
        return status;
      }
    }

    status = httpc_mime_end(conn, &res);
    if (status != H_OK)
    {
      httpc_close_free(conn);
      xmlBufferFree(buffer);
      return status;
    }
  }

  /* Free buffer */
  xmlBufferFree(buffer);

  /* Build result */
  status = _soap_client_build_result(res, &res_env);
  if (status != H_OK)
  {
    hresponse_free(res);
    httpc_close_free(conn);
    return status;
  }

  /* Create Context */
  *response = soap_ctx_new(res_env);
/*	soap_ctx_add_files(*response, res->attachments);*/

  if (res->attachments != NULL)
  {
    part = res->attachments->parts;
    while (part)
    {
      soap_ctx_add_file(*response, part->filename, part->content_type, href);
      part->deleteOnExit = 0;
      part = part->next;
    }
    part = (*response)->attachments->parts;
    while (part)
    {
      part->deleteOnExit = 1;
      part = part->next;
    }
  }


  hresponse_free(res);
  httpc_close_free(conn);
  return H_OK;
}


static herror_t
_soap_client_build_result(hresponse_t * res, SoapEnv ** env)
{
  herror_t err;

  log_verbose2("Building result (%p)", res);

  if (res == NULL)
    return herror_new("_soap_client_build_result",
                      GENERAL_INVALID_PARAM, "hresponse_t is NULL");


  if (res->in == NULL)
    return herror_new("_soap_client_build_result",
                      GENERAL_INVALID_PARAM, "Empty response from server");

  if (res->errcode != 200)
    return herror_new("_soap_client_build_result",
                      GENERAL_INVALID_PARAM, "HTTP code is not 200 OK");

  err = soap_env_new_from_stream(res->in, env);

  if (err != H_OK)
  {
    return err;
  }

  return H_OK;
}