/* Swfdec
 * Copyright (C) 2006 Benjamin Otte <otte@gnome.org>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 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
 * Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, 
 * Boston, MA  02110-1301  USA
 */

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include <libsoup/soup.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include "swfdec_fb_loader.h"

extern gboolean notify_init;

/*** FB-DOC ***/

/**
 * SECTION:FbExtensions
 * @title: Fb extensions
 * @short_description: extension objects for @SwfdecFbPlayer
 *
 * Swfdec-Fb provides some objects that implement the various extensions
 * provided by the @SwfdecPlayer object. They are used by default in the 
 * #SwfdecFbPlayer object, but you can use them outside of it, too. 
 * However, they require certain Fb functionality, such as a running glib
 * main loop.
 */

/**
 * SwfdecFbLoader:
 *
 * #SwfdecFbLoader is a #SwfdecLoader that is intended as an easy way to be 
 * access ressources that are not stored in files, such as HTTP. It is a 
 * private object.
 */

struct _SwfdecFbLoader
{
  SwfdecLoader		loader;

  SoupMessage *		message;	/* the message we're sending */
  gboolean		opened;		/* set after first bytes of data have arrived */
  gboolean		need_notify;/* notify_init_ok ? */
};

struct _SwfdecFbLoaderClass {
  SwfdecLoaderClass	loader_class;

  SoupSession *		session;	/* the session used by the loader */
};

/*** SwfdecFbLoader ***/

G_DEFINE_TYPE (SwfdecFbLoader, swfdec_fb_loader, SWFDEC_TYPE_FILE_LOADER)

static void
swfdec_fb_loader_ensure_open (SwfdecFbLoader *fb)
{
  char *real_uri;

  if (fb->opened)
    return;

  real_uri = soup_uri_to_string (soup_message_get_uri (fb->message), FALSE);
  swfdec_loader_set_url (SWFDEC_LOADER (fb), real_uri);
  g_free (real_uri);
  if (soup_message_headers_get_encoding (fb->message->response_headers) == SOUP_ENCODING_CONTENT_LENGTH) {
    swfdec_loader_set_size (SWFDEC_LOADER (fb), 
	soup_message_headers_get_content_length (fb->message->response_headers));
  }
  swfdec_stream_open (SWFDEC_STREAM (fb));
  fb->opened = TRUE;
}

static void
swfdec_fb_loader_push (SoupMessage *msg, SoupBuffer *chunk, gpointer loader)
{
  SwfdecFbLoader *fb = SWFDEC_FB_LOADER (loader);
  SwfdecBuffer *buffer;

  chunk = soup_buffer_copy (chunk);
  g_printerr ("Pushing stream: loader, size : %d\n", chunk->length);

  swfdec_fb_loader_ensure_open (fb);
  buffer = swfdec_buffer_new_full ((unsigned char *) chunk->data, chunk->length,
      (SwfdecBufferFreeFunc) soup_buffer_free, chunk);
  swfdec_stream_push (loader, buffer);
}
  
static void
swfdec_fb_loader_finished (SoupMessage *msg, gpointer loader)
{
  SwfdecFbLoader *fb = SWFDEC_FB_LOADER (loader);
  if (SOUP_STATUS_IS_SUCCESSFUL (msg->status_code)) {
    swfdec_fb_loader_ensure_open (loader);
    swfdec_stream_close (loader);
  } else {
    if (!SWFDEC_FB_LOADER (loader)->opened) {
      char *real_uri = soup_uri_to_string (soup_message_get_uri (msg), FALSE);
      swfdec_loader_set_url (loader, real_uri);
      g_free (real_uri);
    }
    swfdec_stream_error (loader, "%u %s", msg->status_code, msg->reason_phrase);
  }
  // notify init ok!
  if (fb->need_notify)
  {
	notify_init = FALSE;
  }
}

static void
swfdec_fb_loader_dispose (GObject *object)
{
  SwfdecFbLoader *fb = SWFDEC_FB_LOADER (object);

  if (fb->message) {
    g_signal_handlers_disconnect_by_func (fb->message, swfdec_fb_loader_push, fb);
    g_signal_handlers_disconnect_by_func (fb->message, swfdec_fb_loader_finished, fb);
    g_object_unref (fb->message);
    fb->message = NULL;
  }

  G_OBJECT_CLASS (swfdec_fb_loader_parent_class)->dispose (object);
}

static void
swfdec_fb_loader_load (SwfdecLoader *loader, SwfdecPlayer *player, 
    const char *url_string, SwfdecBuffer *buffer, guint n_headers,
    const char **header_names, const char **header_values)
{
  SwfdecURL *url;
  guint i;
  
  g_printerr ("Loading stream: loader, %s\n", url_string);

  if (swfdec_url_path_is_relative (url_string)) {
    url = swfdec_url_new_relative (swfdec_player_get_base_url (player), url_string);
  } else {
    url = swfdec_url_new (url_string);
  }

  if (url == NULL) {
    swfdec_stream_error (SWFDEC_STREAM (loader), "invalid URL %s", url_string);
    return;
  };
  if (!swfdec_url_has_protocol (url, "http") &&
      !swfdec_url_has_protocol (url, "https")) {
    SWFDEC_LOADER_CLASS (swfdec_fb_loader_parent_class)->load (loader, player,
	url_string, buffer, n_headers, header_names, header_values);
  } else {
    SwfdecFbLoader *fb = SWFDEC_FB_LOADER (loader);
    SwfdecFbLoaderClass *klass = SWFDEC_FB_LOADER_GET_CLASS (fb);

	if (strstr(url_string, "apiplayer") && strstr(url_string, ".swf"))
	  fb->need_notify = TRUE;
	else
	  fb->need_notify = FALSE;

    fb->message = soup_message_new (buffer != NULL ? "POST" : "GET",
	swfdec_url_get_url (url));
    soup_message_set_flags (fb->message, SOUP_MESSAGE_OVERWRITE_CHUNKS);

    for (i = 0; i < n_headers; i++) {
      soup_message_headers_append (fb->message->request_headers,
	  header_names[i], header_values[i]);
    }

    g_signal_connect (fb->message, "got-chunk", G_CALLBACK (swfdec_fb_loader_push), fb);
    g_signal_connect (fb->message, "finished", G_CALLBACK (swfdec_fb_loader_finished), fb);
    if (buffer)
      soup_message_set_request (fb->message, "appliation/x-www-form-urlencoded",
	  SOUP_MEMORY_COPY, (char *) buffer->data, buffer->length);
    g_object_ref (fb->message);
    soup_session_queue_message (klass->session, fb->message, NULL, NULL);
  }
  swfdec_url_free (url);
}

static void
swfdec_fb_loader_close (SwfdecStream *stream)
{
  SwfdecFbLoader *fb = SWFDEC_FB_LOADER (stream);

  if (fb->message && !swfdec_stream_is_complete (stream)) {
    SwfdecFbLoaderClass *klass = SWFDEC_FB_LOADER_GET_CLASS (fb);

    soup_session_cancel_message (klass->session, fb->message, SOUP_STATUS_CANCELLED);
    g_object_unref (fb->message);
    fb->message = NULL;
  }
}

static void
swfdec_fb_loader_class_init (SwfdecFbLoaderClass *klass)
{
  GObjectClass *object_class = G_OBJECT_CLASS (klass);
  SwfdecStreamClass *stream_class = SWFDEC_STREAM_CLASS (klass);
  SwfdecLoaderClass *loader_class = SWFDEC_LOADER_CLASS (klass);

  object_class->dispose = swfdec_fb_loader_dispose;

  stream_class->close = swfdec_fb_loader_close;

  loader_class->load = swfdec_fb_loader_load;
  
  klass->session = soup_session_async_new ();

  { // output http header.
	  const char* str = getenv("VA_FLASH_DEBUG");
	  if(str && strcmp(str, "false") != 0) {
		  g_printerr("enable libsoup log\n");
		  SoupLogger* logger = soup_logger_new(SOUP_LOGGER_LOG_HEADERS, -1);
		  soup_session_add_feature(klass->session, logger);
	  }
  }
  
  { // set user agent
	  const char* str = getenv("SWFDEC_USER_AGENT");
	  if(str) {
		  g_printerr("set libsoup User-Agent = %s\n", str);
		  g_object_set (G_OBJECT (klass->session), SOUP_SESSION_USER_AGENT, str, NULL);
	  }
  }

  // http_proxy
  {
	const char *proxy = getenv("http_proxy");
	if (proxy) {
		SoupURI *proxy_uri = NULL;
		char http_proxy[128] = "http://";
		strcat(http_proxy, proxy);
		g_printerr("proxy = %s\n", http_proxy);
		proxy_uri = soup_uri_new (http_proxy);
		if (proxy_uri)
		{
			g_printerr("proxy ok\n");
   			g_object_set (G_OBJECT (klass->session),
				SOUP_SESSION_PROXY_URI, proxy_uri,
        		NULL);
			soup_uri_free (proxy_uri);
		}
	}
  }
}

static void
swfdec_fb_loader_init (SwfdecFbLoader *fb_loader)
{
}

