/* OGMRip - A library for DVD ripping and encoding
 * Copyright (C) 2004-2012 Olivier Rolland <billl@users.sourceforge.net>
 *
 * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 */

/**
 * SECTION:ogmrip-edl
 * @title: Edit Decision List
 * @short_description: Functions for manipulating EDL
 * @include: ogmrip-edl.h
 */

#include "ogmrip-edl.h"

#include <stdio.h>
#include <locale.h>

struct _OGMRipEdl
{
  guint ref;
  gboolean dirty;
  gchar *filename;
  GSList *list;
};

typedef struct
{
  OGMRipEdlAction action;
  gdouble start;
  gdouble end;
} OGMRipEdlElement;

/**
 * ogmrip_edl_new:
 * @filename: The output file
 *
 * Creates a new #OGMRipEdl.
 *
 * Returns: The new #OGMRipEdl
 */
OGMRipEdl *
ogmrip_edl_new (const gchar *filename)
{
  OGMRipEdl *edl;

  g_return_val_if_fail (filename && *filename, NULL);

  edl = g_new0 (OGMRipEdl, 1);
  edl->filename = g_strdup (filename);
  edl->ref = 1;

  return edl;
}

/**
 * ogmrip_edl_ref:
 * @edl: A #OGMRipEdl
 *
 * Increments the reference count of the #OGMRipEdl.
 */
void
ogmrip_edl_ref (OGMRipEdl *edl)
{
  g_return_if_fail (edl != NULL);

  edl->ref ++;
}

/**
 * ogmrip_edl_unref:
 * @edl: A #OGMRipEdl
 *
 * Decrements the reference count of the #OGMRipEdl and frees if the result is 0.
 */
void
ogmrip_edl_unref (OGMRipEdl *edl)
{
  g_return_if_fail (edl != NULL);

  if (edl->ref > 0)
  {
    edl->ref --;
    if (edl->ref == 0)
    {
      g_free (edl->filename);
      g_slist_foreach (edl->list, (GFunc) g_free, NULL);
      g_slist_free (edl->list);
      g_free (edl);
    }
  }
}

static gint
ogmrip_edl_element_compare (OGMRipEdlElement *elt1, OGMRipEdlElement *elt2)
{
  if (elt1->start < elt2->start)
    return -1;

  if (elt1->start > elt2->start)
    return 1;

  return 0;
}

/**
 * ogmrip_edl_add:
 * @edl: An #OGMRipEdl
 * @action: An #OGMRipEdlAction
 * @start: The start in seconds
 * @end: The end in seconds
 *
 * Adds the given action to the EDL.
 */
void
ogmrip_edl_add (OGMRipEdl *edl, OGMRipEdlAction action, gdouble start, gdouble end)
{
  OGMRipEdlElement *element;

  g_return_if_fail (edl != NULL);
  g_return_if_fail (start < end);

  edl->dirty = TRUE;

  element = g_new0 (OGMRipEdlElement, 1);
  element->action = action;
  element->start = start;
  element->end = end;

  edl->list = g_slist_insert_sorted (edl->list, element, (GCompareFunc) ogmrip_edl_element_compare);
}

/**
 * ogmrip_edl_foreach:
 * @edl: An #OGMRipEdl
 * @func: An #OGMRipEdlFunc
 * @data: The user data
 *
 * Invokes @func on each EDL entry.
 */
void
ogmrip_edl_foreach (OGMRipEdl *edl, OGMRipEdlFunc func, gpointer data)
{
  GSList *link;
  OGMRipEdlElement *elt;

  g_return_if_fail (edl != NULL);
  g_return_if_fail (func != NULL);

  for (link = edl->list; link; link = link->next)
  {
    elt = link->data;
    (* func) (elt->action, elt->start, elt->end, data);
  }
}

static void
ogmrip_edl_element_dump (OGMRipEdlElement *elt, FILE *stream)
{
  fprintf (stream, "%.0lf %.0lf %d\n", elt->start, elt->end, elt->action);
}

/**
 * ogmrip_edl_dump:
 * @edl: An #OGMRipEdl
 *
 * Writes the EDL in the given file.
 *
 * Returns: %TRUE if the EDL has been dumped
 */
gboolean
ogmrip_edl_dump (OGMRipEdl *edl)
{
  FILE *stream;
  gchar *lc;

  g_return_val_if_fail (edl != NULL, FALSE);

  if (edl->dirty)
  {
    stream = fopen (edl->filename, "w");
    if (!stream)
      return FALSE;

    lc = setlocale (LC_NUMERIC, NULL);
    setlocale (LC_NUMERIC, "C");

    g_slist_foreach (edl->list, (GFunc) ogmrip_edl_element_dump, stream);

    setlocale (LC_NUMERIC, lc);

    fclose (stream);

    edl->dirty = FALSE;
  }

  return TRUE;
}

/**
 * ogmrip_edl_get_filename:
 * @edl: An #OGMRipEdl
 *
 * Gets the filename of the EDL.
 *
 * Returns: The filename
 */
const gchar *
ogmrip_edl_get_filename (OGMRipEdl *edl)
{
  g_return_val_if_fail (edl != NULL, NULL);

  return edl->filename;
}
/*
gdouble
ogmrip_edl_get_mute_length (OGMRipEdl *edl)
{
  GSList *link;
  OGMRipEdlElement *element;
  gdouble length = 0.0;

  g_return_val_if_fail (edl != NULL, -1.0);

  for (link = edl->list; link; link = link->next)
  {
    element = link->data;
    if (element->action == OGMRIP_EDL_ACTION_MUTE)
      length += element->end - element->start;
  }

  return length;
}

gdouble
ogmrip_edl_get_skip_length (OGMRipEdl *edl)
{
  GSList *link;
  OGMRipEdlElement *element;
  gdouble length = 0.0;

  g_return_val_if_fail (edl != NULL, -1.0);

  for (link = edl->list; link; link = link->next)
  {
    element = link->data;
    if (element->action == OGMRIP_EDL_ACTION_SKIP)
      length += element->end - element->start;
  }

  return length;
}
*/

