/*****************************************************************
 * gmerlin - a general purpose multimedia framework and applications
 *
 * Copyright (c) 2001 - 2012 Members of the Gmerlin project
 * gmerlin-general@lists.sourceforge.net
 * http://gmerlin.sourceforge.net
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 * *****************************************************************/

#include <string.h>
#include <unistd.h>
#include <signal.h>

#include "server.h"
#include <gmerlin/http.h>

#define LOG_DOMAIN "ondemand"

// #define CLIENT_TIMEOUT 5000

/*
 *  Original stream is always at /ondemand/<ID>/filename.ext
 *  Transcoded streams are at    /recompress/mp3/ondemand/<ID>/filename.mp3
 *                               /recompress/vorbis/ondemand/<ID>/filename.ogg
 *  etc.
 */

static int open_ondemand_fd(const char * command, bg_subprocess_t ** proc)
  {
  int listen_fd = -1;
  bg_socket_address_t * addr;
  char addr_str[BG_SOCKET_ADDR_STR_LEN];
  char * full_command = NULL;
  
  addr = bg_socket_address_create();
  bg_socket_address_set(addr, "127.0.0.1", 0, SOCK_STREAM);

  listen_fd = bg_listen_socket_create_inet(addr, 0, 1, 0);
  bg_socket_get_address(listen_fd, addr, NULL);

  bg_socket_address_to_string(addr, addr_str);
  
  full_command = bg_sprintf("%s -o http://%s", command, addr_str);

  gavl_log(GAVL_LOG_INFO, LOG_DOMAIN, "Command: %s",
         full_command);
  
  *proc = bg_subprocess_create(full_command, 0, 0, 0);

  bg_socket_address_destroy(addr);
  if(full_command)
    free(full_command);
  
  return listen_fd;
  }

static char * get_log_opt()
  {
  const char * syslog;
  int log_level;

  syslog = gavl_log_syslog_name();
  log_level = gavl_log_get_verbose_level();

  if(syslog)
    return bg_sprintf("-v %d -syslog %s", log_level, syslog);
  else
    return bg_sprintf("-v %d", log_level);
  
  }

static client_t * create_source(server_t * s, char * command,
                                gavl_dictionary_t * res)
  {
  bg_subprocess_t * proc = NULL;
  int fd;
  bg_plug_t * plug = NULL;
  
  
  /* Open plug */
  fd = open_ondemand_fd(command, &proc);
  plug = bg_plug_create_reader(s->plugin_reg);

  return source_client_create(s, &fd, NULL, plug,
                              CLIENT_TYPE_SOURCE_ONDEMAND, proc, 1);
  
  }

int server_handle_ondemand(bg_http_connection_t * conn, void * data)
  {
  int i;
  client_t * source = NULL;
  client_t * sink;
  int64_t id;
  server_t * s = data;
  
  if(conn->protocol_i == BG_HTTP_PROTO_HTTP)
    {
    if(strcmp(conn->method, "GET") && strcmp(conn->method, "HEAD"))
      {
      // Bad request actually
      bg_http_connection_init_res(conn, "HTTP/1.1", 400, "Bad Request");
      return 1;
      }
    }
  
  id = strtoll(conn->path, NULL, 10);

  for(i = 0; i < s->num_clients; i++)
    {
    if((s->clients[i]->type == CLIENT_TYPE_SOURCE_ONDEMAND) &&
       s->clients[i]->id == id)
      {
      source = s->clients[i];
      break;
      }
    }

  if(!source)
    {
    char * log_opt = get_log_opt();
    char * command = NULL;
    bg_db_object_t * obj = NULL;
    
    obj = bg_db_object_query(s->db, id);
    if(!obj)
      {
      bg_http_connection_init_res(conn, "HTTP/1.1", 404, "Not Found");
      goto fail;
      }
    switch(bg_db_object_get_type(obj))
      {
      case BG_DB_OBJECT_PLAYLIST:
        command = bg_sprintf("gavf-decode %s -ch %d -sr %d -loop -shuffle -xspf \"%s/xspf/%"PRId64"/%s.xspf?mode=local\" -m 'Station=%s %s'",
                             log_opt,
                             bg_upnp_playlist_stream_afmt.num_channels,
                             bg_upnp_playlist_stream_afmt.samplerate,
                             s->root_url, bg_db_object_get_id(obj),
                             obj->label,
                             s->upnp_name, obj->label);
        
        break;
      case BG_DB_OBJECT_RADIO_URL:
        {
        bg_db_url_t * u = (bg_db_url_t *)obj;
        command = bg_sprintf("gavf-decode %s -i %s",
                             log_opt, u->stream_url);
        break;
        }
      default:
        bg_http_connection_init_res(conn, "HTTP/1.1", 404, "Not Found");
        goto fail;
        break;
      }

    if(!command)
      return 1;
    
    /* Create ondemand source */
    
    if(!(source = create_source(s, command, &conn->res)))
      {
      bg_http_connection_init_res(conn, conn->protocol,
                                  404, "Not found");
      goto create_fail;
      }
    source->id = id;
    server_attach_client(s, source);
    
    create_fail:
    
    if(obj)
      bg_db_object_unref(obj);
    
    if(command)
      free(command);
    
    if(!source)
      goto fail;

    }

  sink = sink_create_from_source(s, &conn->fd, source, &conn->req, conn->method, conn->protocol_i);
  if(sink)
    server_attach_client(s, sink);
  
  fail:
  return 1;
  }


int server_handle_recompress(bg_http_connection_t * conn, void * data)
  {
  int i;
  client_t * source = NULL;
  client_t * sink;
  server_t * s = data;
  
  if(conn->protocol_i == PROTOCOL_HTTP)
    {
    if(strcmp(conn->method, "GET") && strcmp(conn->method, "HEAD"))
      {
      // Bad request actually
      bg_http_connection_init_res(conn, "HTTP/1.1", 400, "Bad Request");
      return 1;
      }
    }
  
  for(i = 0; i < s->num_clients; i++)
    {
    if((s->clients[i]->type == CLIENT_TYPE_SOURCE_ONDEMAND) &&
       s->clients[i]->name &&
       !strcmp(s->clients[i]->name, conn->path))
      {
      source = s->clients[i];
      break;
      }
    }

  if(!source)
    {
    char * pos1, * pos2;
    char * command      = NULL;
    char * full_command = NULL;
    
    const bg_upnp_recompressor_t * cmp;
    
    /* Name of recompressor */
    if(!(cmp = bg_upnp_recompressor_by_name(conn->path))) // 404
      return 0;

    conn->path += strlen(cmp->name);

    command = cmp->make_command();

    full_command = bg_sprintf("%s -i %s%s",
                              command, s->root_url, conn->path);

    pos1 = strrchr(conn->path, '/');
    pos2 = strrchr(conn->path, '.');

    if(pos1 && pos2 && (pos2 > pos1))
      *pos2 = '\0';
    
    /* Create ondemand source */
    source = create_source(s, full_command, &conn->res);
    if(!source)
      {
      bg_http_connection_init_res(conn, conn->protocol,
                                  404, "Not found");
      goto create_fail;
      }
    source->name = gavl_strdup(conn->path);
    server_attach_client(s, source);

    create_fail:
    
    if(command)
      free(command);
    if(full_command)
      free(full_command);
    
    if(!source)
      goto fail;
    
    }
  
  sink = sink_create_from_source(s, &conn->fd, source, &conn->req, conn->method, conn->protocol_i);
  
  if(sink)
    server_attach_client(s, sink);
  
  fail:
  return 1;
  }
