/* GStreamer
 * Copyright (C) 2017 Sebastian Dröge <sebastian@centricular.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.
 */

#include <gst/gst.h>
#include <gst/rtsp-server/rtsp-onvif-server.h>

#include <string.h>
#include <stdio.h>
#include "iniparser/iniparser.h"

#define CONF "/oem/etc/config.xml"
#define SPK_CONF    "/etc/speaker.conf"
#define MAX_LINE_LENGTH 256

struct SPEAKER_CONF
{
    char hw_version[16];
    char dev_type[32];
    char enable_mic[8];
    char media_stream[8];
};


void find_tag_in_file(const char* file_path, const char* tag, char *value);
void confParse(struct SPEAKER_CONF *conf);


void confParse(struct SPEAKER_CONF *conf)
{
	dictionary * ini ;
	ini = iniparser_load(SPK_CONF);
	
    if (ini==NULL) {
        fprintf(stderr, "cannot parse file: %s\n", SPK_CONF);
        exit(-1);
    }
	strcpy(conf->dev_type, iniparser_getstring(ini, "system:ui_model", ""));
	strcpy(conf->hw_version, iniparser_getstring(ini, "system:hard_version", ""));
	strcpy(conf->enable_mic, iniparser_getstring(ini, "onvif:enable_mic", "no"));
	strcpy(conf->media_stream, iniparser_getstring(ini, "onvif:media_stream", "main"));
    
	iniparser_freedict(ini);
}

static gchar *htdigest_path = NULL;
static gchar *realm = NULL;

static GOptionEntry entries[] = {
  {"htdigest-path", 'h', 0, G_OPTION_ARG_STRING, &htdigest_path,
      "Path to an htdigest file to parse (default: None)", "PATH"},
  {"realm", 'r', 0, G_OPTION_ARG_STRING, &realm,
      "Authentication realm (default: None)", "REALM"},
  {NULL}
};

int
main (int argc, char *argv[])
{
  GMainLoop *loop;
  GstRTSPServer *server;
  GstRTSPMountPoints *mounts;
  GstRTSPMediaFactory *factory;
  GstRTSPAuth *auth;
  GstRTSPToken *token;
  GOptionContext *optctx;
  GError *error = NULL;
  struct SPEAKER_CONF conf;
  confParse(&conf);;
  char launchstr[512];

  char username[64] = { 0 };
  char password[64] = { 0 };
  find_tag_in_file(CONF, "auth_user", username);
  find_tag_in_file(CONF, "auth_pass", password);

  if (strlen(username) == 0 || strlen(password) == 0) {
	  g_print ("Please username or password in config.xml\n");
	  return -1;
  }

  // putenv("GST_DEBUG=4");
  gst_init (&argc, &argv);

  optctx = g_option_context_new (NULL);
  g_option_context_add_main_entries (optctx, entries, NULL);
  g_option_context_add_group (optctx, gst_init_get_option_group ());
  if (!g_option_context_parse (optctx, &argc, &argv, &error)) {
    g_printerr ("Error parsing options: %s\n", error->message);
    g_option_context_free (optctx);
    g_clear_error (&error);
    return -1;
  }
  g_option_context_free (optctx);

  loop = g_main_loop_new (NULL, FALSE);

  /* create a server instance */
  server = gst_rtsp_onvif_server_new ();

  /* get the mount points for this server, every server has a default object
   * that be used to map uri mount points to media factories */
  mounts = gst_rtsp_server_get_mount_points (server);

  /* make a media factory for a test stream. The default media factory can use
   * gst-launch syntax to create pipelines.
   * any launch line works as long as it contains elements named pay%d. Each
   * element with pay%d names will be a stream */
  factory = gst_rtsp_onvif_media_factory_new ();
  //! video/x-raw, format=(string)RGB, width=(int)640, height=(int)480
 
  strcpy(launchstr, "( filesrc loop=true location=\"/usr/share/onvif/speaker.h264\" ! video/x-h264 ! h264parse ! rtph264pay pt=96 config-interval=5 name=pay0 ");

  if(strcmp(conf.enable_mic, "yes") == 0)
  {
    strcat(launchstr, "alsasrc device=plug:mixmic ! queue ! audioconvert ! audioresample ! mulawenc ! rtppcmupay name=pay1 )");
  }
  else
  {
    strcat(launchstr, " )");
  }
  gst_rtsp_media_factory_set_launch (factory,launchstr); 
  
  gst_rtsp_onvif_media_factory_set_backchannel_launch
      (GST_RTSP_ONVIF_MEDIA_FACTORY (factory),
      "( capsfilter caps=\"application/x-rtp, media=audio, payload=0, clock-rate=8000, encoding-name=PCMU, channels=1\" name=depay_backchannel ! rtppcmudepay ! mulawdec ! audioconvert ! audio/x-raw,channels=2 ! audioresample ! alsasink async=false sync=false )");
      //"( capsfilter caps=\"application/x-rtp, media=audio, payload=8, clock-rate=8000, encoding-name=PCMA, channels=1\" name=depay_backchannel ! rtpjitterbuffer latency=80 ! rtppcmadepay ! alawdec ! identity drop-probability=0.01 sync=true ! audioconvert ! audioresample ! alsasink async=false sync=false )");
  gst_rtsp_media_factory_set_shared (factory, FALSE);
  gst_rtsp_media_factory_set_media_gtype (factory, GST_TYPE_RTSP_ONVIF_MEDIA);

  /* attach the test factory to the /test url */
  gst_rtsp_mount_points_add_factory (mounts, "/MainStream", factory);

  /* allow admin to access this resource */
  gst_rtsp_media_factory_add_role (factory, username,
      GST_RTSP_PERM_MEDIA_FACTORY_ACCESS, G_TYPE_BOOLEAN, TRUE,
      GST_RTSP_PERM_MEDIA_FACTORY_CONSTRUCT, G_TYPE_BOOLEAN, TRUE, NULL);

  /* don't need the ref to the mapper anymore */
  g_object_unref (mounts);

  /* make a new authentication manager */
  auth = gst_rtsp_auth_new ();
  gst_rtsp_auth_set_supported_methods (auth, GST_RTSP_AUTH_DIGEST);


  if (realm)
    gst_rtsp_auth_set_realm (auth, realm);
  /* make admin token */
  token =
      gst_rtsp_token_new (GST_RTSP_TOKEN_MEDIA_FACTORY_ROLE, G_TYPE_STRING,
      username, NULL);
  gst_rtsp_auth_add_digest (auth, username, password, token);
  gst_rtsp_token_unref (token);

  /* set as the server authentication manager */
  gst_rtsp_server_set_auth (server, auth);
  g_object_unref (auth);

  /* attach the server to the default maincontext */
  gst_rtsp_server_attach (server, NULL);

  /* start serving */
  g_print ("stream ready at rtsp://0.0.0.0:554/MainStream\n");
  g_main_loop_run (loop);

  return 0;
}

void find_tag_in_file(const char* file_path, const char* tag, char *value) {
    FILE* file = fopen(file_path, "r");
    if (file == NULL) {
        g_print ("Failed to open file: %s\n", file_path);
        return;
    }

    char line[MAX_LINE_LENGTH];
    char start_tag[MAX_LINE_LENGTH] = { 0 };
    char end_tag[MAX_LINE_LENGTH] = { 0 };

    sprintf(start_tag, "<%s>", tag);
    sprintf(end_tag, "</%s>", tag);

    while (fgets(line, MAX_LINE_LENGTH, file)) {
        if (strstr(line, start_tag) && strstr(line, end_tag)) {
            // Extract the data between the start and end tags.
            char* start = strstr(line, start_tag) + strlen(start_tag);
            char* end = strstr(line, end_tag);
            *end = '\0';  // Null-terminate the string at the end of the data.
            strcpy(value, start);
            break;
        }
    }

    fclose(file);
}