#!/bin/sh


prefix=gst
templatedir=element-templates

while [ "$1" ] ; do
  case $1 in
    --help)
      cat <<-EOF
Usage: element-maker [OPTIONS] _NAME BASE_CLASS
Create a GStreamer application from a template.
Options:
  --help             Print this information
  --prefix PREFIX    Use PREFIX instead of "gst"
Example: 'gst-app-maker my_app' will create the file gstmyapp.c.
EOF
      exit 0
      ;;
    --prefix)
      shift
      prefix=$1
      ;;
    -*)
      echo Unknown option: $1
      exit 1
      ;;
    *)
      if [ "$name" = "" ]; then
        name=$1
      else
        echo Ignored: $1
      fi
  esac
  shift
done

if [ "$name" = "" ] ; then
  echo "Usage: element-maker [OPTIONS] ELEMENT_NAME BASE_CLASS"
  exit 1
fi


PREFIX=$(echo $prefix | sed -e 's/\(.*\)/\U\1/')
NAME=$(echo $name | sed -e 's/\(.*\)/\U\1/')
Prefix=$(echo $prefix | sed -e 's/_\(.\)/\U\1/g' -e 's/^\(.\)/\U\1/')
Name=$(echo $name | sed -e 's/_\(.\)/\U\1/g' -e 's/^\(.\)/\U\1/')

GST_IS_REPLACE=${PREFIX}_IS_${NAME}
GST_REPLACE=${PREFIX}_${NAME}
GST_TYPE_REPLACE=${PREFIX}_TYPE_${NAME}
GstReplace=${Prefix}${Name}
gst_replace=${prefix}_${name}
gstreplace=${prefix}$(echo $name | sed -e 's/_//g')
replace=$(echo $name | sed -e 's/_//g')

if [ "$REAL_NAME" = "" ] ; then
  REAL_NAME=FIXME
fi
if [ "$EMAIL_ADDRESS" = "" ] ; then
  EMAIL_ADDRESS=fixme@example.com
fi



generate ()
{

cat <<-EOF
/* GstReplace
 * Copyright (C) $(date +%Y) $REAL_NAME <$EMAIL_ADDRESS>
 * Copyright (C) 2010 Entropy Wave Inc
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

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

#include <gst/gst.h>
#include <stdlib.h>

#define GETTEXT_PACKAGE "replace"


typedef struct _GstReplace GstReplace;
struct _GstReplace {
  GstElement *pipeline;
  GstBus *bus;
  GMainLoop *main_loop;

  GstElement *source_element;
  GstElement *sink_element;

  gboolean paused_for_buffering;
  guint timer_id;
};

GstReplace * gst_replace_new (void);
void gst_replace_free (GstReplace *replace);
void gst_replace_create_pipeline (GstReplace *replace);
void gst_replace_create_pipeline_playbin (GstReplace *replace, const char *uri);
void gst_replace_start (GstReplace *replace);
void gst_replace_stop (GstReplace *replace);

static gboolean gst_replace_handle_message (GstBus *bus, GstMessage *message,
    gpointer data);
static gboolean onesecond_timer (gpointer priv);


gboolean verbose;

static GOptionEntry entries[] =
{
  { "verbose", 'v', 0, G_OPTION_ARG_NONE, &verbose, "Be verbose", NULL },

  { NULL }

};

int
main (int argc, char *argv[])
{
  GError *error = NULL;
  GOptionContext *context;
  GstReplace *replace;
  GMainLoop *main_loop;

  context = g_option_context_new ("- FIXME");
  g_option_context_add_main_entries (context, entries, GETTEXT_PACKAGE);
  g_option_context_add_group (context, gst_init_get_option_group ());
  if (!g_option_context_parse (context, &argc, &argv, &error)) {
    g_print ("option parsing failed: %s\n", error->message);
    g_clear_error (&error);
    g_option_context_free (context);
    exit (1);
  }
  g_option_context_free (context);

  replace = gst_replace_new ();

  if (argc > 1) {
    gchar *uri;
    if (gst_uri_is_valid (argv[1])) {
      uri = g_strdup (argv[1]);
    } else {
      uri = g_filename_to_uri (argv[1], NULL, NULL);
    }
    gst_replace_create_pipeline_playbin (replace, uri);
    g_free (uri);
  } else {
    gst_replace_create_pipeline (replace);
  }

  gst_replace_start (replace);

  main_loop = g_main_loop_new (NULL, TRUE);
  replace->main_loop = main_loop;

  g_main_loop_run (main_loop);

  exit (0);
}


GstReplace *
gst_replace_new (void)
{
  GstReplace *replace;

  replace = g_new0 (GstReplace, 1);

  return replace;
}

void
gst_replace_free (GstReplace *replace)
{
  if (replace->source_element) {
    gst_object_unref (replace->source_element);
    replace->source_element = NULL;
  }
  if (replace->sink_element) {
    gst_object_unref (replace->sink_element);
    replace->sink_element = NULL;
  }

  if (replace->pipeline) {
    gst_element_set_state (replace->pipeline, GST_STATE_NULL);
    gst_object_unref (replace->pipeline);
    replace->pipeline = NULL;
  }
  g_free (replace);
}

void
gst_replace_create_pipeline_playbin (GstReplace *replace, const char *uri)
{
  GstElement *pipeline;
  GError *error = NULL;
  
  pipeline = gst_pipeline_new (NULL);
  gst_bin_add (GST_BIN(pipeline),
      gst_element_factory_make ("playbin", "source"));

  if (error) {
    g_print("pipeline parsing error: %s\n", error->message);
    g_clear_error (&error);
    gst_object_unref (pipeline);
    return;
  }

  replace->pipeline = pipeline;

  gst_pipeline_set_auto_flush_bus (GST_PIPELINE(pipeline), FALSE);
  replace->bus = gst_pipeline_get_bus (GST_PIPELINE(pipeline));
  gst_bus_add_watch (replace->bus, gst_replace_handle_message, replace);

  replace->source_element = gst_bin_get_by_name (GST_BIN(pipeline), "source");
  g_print("source_element is %p\n", replace->source_element);

  g_print("setting uri to %s\n", uri);
  g_object_set (replace->source_element, "uri", uri, NULL);
}

void
gst_replace_create_pipeline (GstReplace *replace)
{
  GString *pipe_desc;
  GstElement *pipeline;
  GError *error = NULL;
  
  pipe_desc = g_string_new ("");

  g_string_append (pipe_desc, "videotestsrc name=source num-buffers=100 ! ");
  g_string_append (pipe_desc, "timeoverlay ! ");
  g_string_append (pipe_desc, "xvimagesink name=sink ");
  g_string_append (pipe_desc, "audiotestsrc samplesperbuffer=1600 num-buffers=100 ! ");
  g_string_append (pipe_desc, "alsasink ");

  if (verbose) g_print ("pipeline: %s\n", pipe_desc->str);

  pipeline = (GstElement *) gst_parse_launch (pipe_desc->str, &error);
  g_string_free (pipe_desc, FALSE);

  if (error) {
    g_print("pipeline parsing error: %s\n", error->message);
    g_clear_error (&error);
    gst_object_unref (pipeline);
    return;
  }

  replace->pipeline = pipeline;

  gst_pipeline_set_auto_flush_bus (GST_PIPELINE(pipeline), FALSE);
  replace->bus = gst_pipeline_get_bus (GST_PIPELINE(pipeline));
  gst_bus_add_watch (replace->bus, gst_replace_handle_message, replace);

  replace->source_element = gst_bin_get_by_name (GST_BIN(pipeline), "source");
  replace->sink_element = gst_bin_get_by_name (GST_BIN(pipeline), "sink");
}

void
gst_replace_start (GstReplace *replace)
{
  gst_element_set_state (replace->pipeline, GST_STATE_READY);

  replace->timer_id = g_timeout_add (1000, onesecond_timer, replace);
}

void
gst_replace_stop (GstReplace *replace)
{
  gst_element_set_state (replace->pipeline, GST_STATE_NULL);

  g_source_remove (replace->timer_id);
}

static void
gst_replace_handle_eos (GstReplace *replace)
{
  gst_replace_stop (replace);
}

static void
gst_replace_handle_error (GstReplace *replace, GError *error,
    const char *debug)
{
  g_print ("error: %s\n", error->message);
  gst_replace_stop (replace);
}

static void
gst_replace_handle_warning (GstReplace *replace, GError *error,
    const char *debug)
{
  g_print ("warning: %s\n", error->message);
}

static void
gst_replace_handle_info (GstReplace *replace, GError *error,
    const char *debug)
{
  g_print ("info: %s\n", error->message);
}

static void
gst_replace_handle_null_to_ready (GstReplace *replace)
{
  gst_element_set_state (replace->pipeline, GST_STATE_PAUSED);

}

static void
gst_replace_handle_ready_to_paused (GstReplace *replace)
{
  if (!replace->paused_for_buffering) {
    gst_element_set_state (replace->pipeline, GST_STATE_PLAYING);
  }
}

static void
gst_replace_handle_paused_to_playing (GstReplace *replace)
{

}

static void
gst_replace_handle_playing_to_paused (GstReplace *replace)
{

}

static void
gst_replace_handle_paused_to_ready (GstReplace *replace)
{

}

static void
gst_replace_handle_ready_to_null (GstReplace *replace)
{
  g_main_loop_quit (replace->main_loop);

}


static gboolean
gst_replace_handle_message (GstBus *bus, GstMessage *message,
    gpointer data)
{
  GstReplace *replace = (GstReplace *) data;

  switch (GST_MESSAGE_TYPE(message)) {
    case GST_MESSAGE_EOS:
      gst_replace_handle_eos (replace);
      break;
    case GST_MESSAGE_ERROR:
      {
        GError *error = NULL;
        gchar *debug;

        gst_message_parse_error (message, &error, &debug);
        gst_replace_handle_error (replace, error, debug);
        g_clear_error (&error);
      }
      break;
    case GST_MESSAGE_WARNING:
      {
        GError *error = NULL;
        gchar *debug;

        gst_message_parse_warning (message, &error, &debug);
        gst_replace_handle_warning (replace, error, debug);
        g_clear_error (&error);
      }
      break;
    case GST_MESSAGE_INFO:
      {
        GError *error = NULL;
        gchar *debug;

        gst_message_parse_info (message, &error, &debug);
        gst_replace_handle_info (replace, error, debug);
        g_clear_error (&error);
      }
      break;
    case GST_MESSAGE_TAG:
      {
        GstTagList *tag_list;

        gst_message_parse_tag (message, &tag_list);
        if (verbose) g_print("tag\n");
      }
      break;
    case GST_MESSAGE_STATE_CHANGED:
      {
        GstState oldstate, newstate, pending;

        gst_message_parse_state_changed (message, &oldstate, &newstate,
            &pending);
        if (GST_ELEMENT(message->src) == replace->pipeline) {
          if (verbose) g_print("state change from %s to %s\n",
              gst_element_state_get_name (oldstate),
              gst_element_state_get_name (newstate));
          switch (GST_STATE_TRANSITION(oldstate, newstate)) {
            case GST_STATE_CHANGE_NULL_TO_READY:
              gst_replace_handle_null_to_ready (replace);
              break;
            case GST_STATE_CHANGE_READY_TO_PAUSED:
              gst_replace_handle_ready_to_paused (replace);
              break;
            case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
              gst_replace_handle_paused_to_playing (replace);
              break;
            case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
              gst_replace_handle_playing_to_paused (replace);
              break;
            case GST_STATE_CHANGE_PAUSED_TO_READY:
              gst_replace_handle_paused_to_ready (replace);
              break;
            case GST_STATE_CHANGE_READY_TO_NULL:
              gst_replace_handle_ready_to_null (replace);
              break;
            default:
              if (verbose) g_print("unknown state change from %s to %s\n",
                  gst_element_state_get_name (oldstate),
                  gst_element_state_get_name (newstate));
          }
        }
      }
      break;
    case GST_MESSAGE_BUFFERING:
      {
        int percent;
        gst_message_parse_buffering (message, &percent);
        //g_print("buffering %d\n", percent);
        if (!replace->paused_for_buffering && percent < 100) {
          g_print ("pausing for buffing\n");
          replace->paused_for_buffering = TRUE;
          gst_element_set_state (replace->pipeline, GST_STATE_PAUSED);
        } else if (replace->paused_for_buffering && percent == 100) {
          g_print ("unpausing for buffing\n");
          replace->paused_for_buffering = FALSE;
          gst_element_set_state (replace->pipeline, GST_STATE_PLAYING);
        }
      }
      break;
    case GST_MESSAGE_STATE_DIRTY:
    case GST_MESSAGE_CLOCK_PROVIDE:
    case GST_MESSAGE_CLOCK_LOST:
    case GST_MESSAGE_NEW_CLOCK:
    case GST_MESSAGE_STRUCTURE_CHANGE:
    case GST_MESSAGE_STREAM_STATUS:
      break;
    case GST_MESSAGE_STEP_DONE:
    case GST_MESSAGE_APPLICATION:
    case GST_MESSAGE_ELEMENT:
    case GST_MESSAGE_SEGMENT_START:
    case GST_MESSAGE_SEGMENT_DONE:
    case GST_MESSAGE_DURATION:
    case GST_MESSAGE_LATENCY:
    case GST_MESSAGE_ASYNC_START:
    case GST_MESSAGE_ASYNC_DONE:
    case GST_MESSAGE_REQUEST_STATE:
    case GST_MESSAGE_STEP_START:
    case GST_MESSAGE_QOS:
    default:
      if (verbose) {
        g_print ("message: %s\n", GST_MESSAGE_TYPE_NAME (message));
      }
      break;
  }

  return TRUE;
}



static gboolean
onesecond_timer (gpointer priv)
{
  //GstReplace *replace = (GstReplace *)priv;

  g_print(".\n");

  return TRUE;
}



/* helper functions */

#if 0
gboolean
have_element (const gchar *element_name)
{
  GstPluginFeature *feature;

  feature = gst_default_registry_find_feature (element_name,
      GST_TYPE_ELEMENT_FACTORY);
  if (feature) {
    g_object_unref (feature);
    return TRUE;
  }
  return FALSE;
}
#endif

EOF

}

generate | sed \
  -e "s/GST_BASE_REPLACE/$GST_BASE_REPLACE/g" \
  -e "s/GST_TYPE_BASE_REPLACE/$GST_TYPE_BASE_REPLACE/g" \
  -e "s/GstBaseReplace/$GstBaseReplace/g" \
  -e "s/GST_IS_REPLACE/$GST_IS_REPLACE/g" \
  -e "s/GST_REPLACE/$GST_REPLACE/g" \
  -e "s/GST_TYPE_REPLACE/$GST_TYPE_REPLACE/g" \
  -e "s/GstReplace/$GstReplace/g" \
  -e "s/gst_replace/$gst_replace/g" \
  -e "s/gstreplace/$gstreplace/g" \
  -e "s/replace/$replace/g" >$gstreplace.c

gst-indent $gstreplace.c

gcc -O2 -Wall $(pkg-config --cflags gstreamer-1.0) -c -o $gstreplace.o $gstreplace.c
gcc -o $gstreplace $gstreplace.o $(pkg-config --libs gstreamer-1.0)


