/* GStreamer
 * Copyright (C) <2005,2006> Wim Taymans <wim@fluendo.com>
 *
 * 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., 51 Franklin St, Fifth Floor,
 * Boston, MA 02110-1301, USA.
 */
/* Element-Checklist-Version: 5 */

/**
 * SECTION:element-rtspwms
 * @title: rtspwms
 *
 * A WMS RTSP extension
 */

#include <string.h>

#include <gst/rtsp/gstrtspextension.h>

#include "gstasfelements.h"
#include "gstrtspwms.h"

GST_DEBUG_CATEGORY_STATIC (rtspwms_debug);
#define GST_CAT_DEFAULT (rtspwms_debug)

#define SERVER_PREFIX "WMServer/"
#define HEADER_PREFIX "data:application/vnd.ms.wms-hdr.asfv1;base64,"
#define EXTENSION_CMD "application/x-wms-extension-cmd"

static GstRTSPResult
gst_rtsp_wms_before_send (GstRTSPExtension * ext, GstRTSPMessage * request)
{
  GstRTSPWMS *ctx = (GstRTSPWMS *) ext;

  GST_DEBUG_OBJECT (ext, "before send");

  switch (request->type_data.request.method) {
    case GST_RTSP_OPTIONS:
    {
      /* activate ourselves with the first request */
      ctx->active = TRUE;
      break;
    }
    default:
      break;
  }
  return GST_RTSP_OK;
}

static GstRTSPResult
gst_rtsp_wms_after_send (GstRTSPExtension * ext, GstRTSPMessage * req,
    GstRTSPMessage * resp)
{
  GstRTSPWMS *ctx = (GstRTSPWMS *) ext;

  GST_DEBUG_OBJECT (ext, "after send");

  switch (req->type_data.request.method) {
    case GST_RTSP_OPTIONS:
    {
      gchar *server = NULL;

      gst_rtsp_message_get_header (resp, GST_RTSP_HDR_SERVER, &server, 0);
      if (server && g_str_has_prefix (server, SERVER_PREFIX))
        ctx->active = TRUE;
      else
        ctx->active = FALSE;
      break;
    }
    default:
      break;
  }
  return GST_RTSP_OK;
}


static GstRTSPResult
gst_rtsp_wms_parse_sdp (GstRTSPExtension * ext, GstSDPMessage * sdp,
    GstStructure * props)
{
  const gchar *config, *maxps;
  gint i;
  GstRTSPWMS *ctx = (GstRTSPWMS *) ext;

  if (!ctx->active)
    return GST_RTSP_OK;

  for (i = 0; (config = gst_sdp_message_get_attribute_val_n (sdp, "pgmpu", i));
      i++) {
    if (g_str_has_prefix (config, HEADER_PREFIX)) {
      config += strlen (HEADER_PREFIX);
      gst_structure_set (props, "config", G_TYPE_STRING, config, NULL);
      break;
    }
  }
  if (config == NULL)
    goto no_config;

  gst_structure_set (props, "config", G_TYPE_STRING, config, NULL);

  maxps = gst_sdp_message_get_attribute_val (sdp, "maxps");
  if (maxps)
    gst_structure_set (props, "maxps", G_TYPE_STRING, maxps, NULL);

  gst_structure_set (props, "encoding-name", G_TYPE_STRING, "X-ASF-PF", NULL);
  gst_structure_set (props, "media", G_TYPE_STRING, "application", NULL);

  return GST_RTSP_OK;

  /* ERRORS */
no_config:
  {
    GST_DEBUG_OBJECT (ctx, "Could not find config SDP field, deactivating.");
    ctx->active = FALSE;
    return GST_RTSP_OK;
  }
}

static gboolean
gst_rtsp_wms_configure_stream (GstRTSPExtension * ext, GstCaps * caps)
{
  GstRTSPWMS *ctx;
  GstStructure *s;
  const gchar *encoding;

  ctx = (GstRTSPWMS *) ext;
  s = gst_caps_get_structure (caps, 0);
  encoding = gst_structure_get_string (s, "encoding-name");

  if (!encoding)
    return TRUE;

  GST_DEBUG_OBJECT (ctx, "%" GST_PTR_FORMAT " encoding-name: %s", caps,
      encoding);

  /* rtx streams do not need to be configured */
  if (!strcmp (encoding, "X-WMS-RTX"))
    return FALSE;

  return TRUE;
}

static GstRTSPResult
gst_rtsp_wms_receive_request (GstRTSPExtension * ext, GstRTSPMessage * request)
{
  GstRTSPWMS *ctx;
  GstRTSPResult res = GST_RTSP_ENOTIMPL;
  GstRTSPMessage response = { 0 };

  ctx = (GstRTSPWMS *) ext;

  GST_DEBUG_OBJECT (ext, "before send");

  switch (request->type_data.request.method) {
    case GST_RTSP_SET_PARAMETER:
    {
      gchar *content_type = NULL;

      gst_rtsp_message_get_header (request, GST_RTSP_HDR_CONTENT_TYPE,
          &content_type, 0);

      if (content_type && !g_ascii_strcasecmp (content_type, EXTENSION_CMD)) {
        /* parse the command */

        /* default implementation, send OK */
        res = gst_rtsp_message_init_response (&response, GST_RTSP_STS_OK, "OK",
            request);
        if (res < 0)
          goto send_error;

        GST_DEBUG_OBJECT (ctx, "replying with OK");

        /* send reply */
        if ((res = gst_rtsp_extension_send (ext, request, &response)) < 0)
          goto send_error;

        res = GST_RTSP_EEOF;
      }
      break;
    }
    default:
      break;
  }
  return res;

send_error:
  {
    return res;
  }
}

static void gst_rtsp_wms_extension_init (gpointer g_iface, gpointer iface_data);

G_DEFINE_TYPE_WITH_CODE (GstRTSPWMS, gst_rtsp_wms, GST_TYPE_ELEMENT,
    G_IMPLEMENT_INTERFACE (GST_TYPE_RTSP_EXTENSION,
        gst_rtsp_wms_extension_init));
GST_ELEMENT_REGISTER_DEFINE_WITH_CODE (rtspwms, "rtspwms", GST_RANK_SECONDARY,
    GST_TYPE_RTSP_WMS, asf_element_init (plugin));

static void
gst_rtsp_wms_class_init (GstRTSPWMSClass * g_class)
{
  GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);

  GST_DEBUG_CATEGORY_INIT (rtspwms_debug, "rtspwms", 0, "WMS RTSP extension");

  gst_element_class_set_static_metadata (element_class, "WMS RTSP Extension",
      "Network/Extension/Protocol",
      "Extends RTSP so that it can handle WMS setup",
      "Wim Taymans <wim.taymans@gmail.com>");
}

static void
gst_rtsp_wms_init (GstRTSPWMS * rtspwms)
{
}

static void
gst_rtsp_wms_extension_init (gpointer g_iface, gpointer iface_data)
{
  GstRTSPExtensionInterface *iface = (GstRTSPExtensionInterface *) g_iface;

  iface->parse_sdp = gst_rtsp_wms_parse_sdp;
  iface->before_send = gst_rtsp_wms_before_send;
  iface->after_send = gst_rtsp_wms_after_send;
  iface->configure_stream = gst_rtsp_wms_configure_stream;
  iface->receive_request = gst_rtsp_wms_receive_request;
}
