/* Swfdec
 * Copyright (C) 2007 Benjamin Otte <otte@gnome.org>
 *
 * 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., 51 Franklin Street, Fifth Floor, 
 * Boston, MA  02110-1301  USA
 */

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

#include <math.h>
#include <stdlib.h>
#include <string.h>
#include "swfdec_video_movie.h"
#include "swfdec_as_strings.h"
#include "swfdec_debug.h"
#include "swfdec_player_internal.h"
#include "swfdec_resource.h"
#include "swfdec_renderer_internal.h"
#include "swfdec_sandbox.h"
#include "swfdec_utils.h"
#include "swfdec_video_provider.h"
#include "swfdec_video_video_provider.h"
#include "swfdec_image.h"

G_DEFINE_TYPE (SwfdecVideoMovie, swfdec_video_movie, SWFDEC_TYPE_MOVIE)

int g_x = 0, g_y = 0;

static void
swfdec_video_movie_set_position (SwfdecVideoMovie *movie)
{
  SwfdecMovie *mov = SWFDEC_MOVIE(movie);
  SwfdecVideo *org = SWFDEC_VIDEO (mov->graphic);  
  SwfdecPlayer *player = SWFDEC_PLAYER (swfdec_gc_object_get_context (mov));
  double dx, dy, dw, dh;
#if 0 
  dx = SWFDEC_TWIPS_TO_DOUBLE (mov->matrix.x0);
  dy = SWFDEC_TWIPS_TO_DOUBLE (mov->matrix.y0);
  dw = rint (mov->extents.x1 - mov->extents.x0);
  dw = SWFDEC_TWIPS_TO_DOUBLE ((SwfdecTwips) dw);
  dh = rint (mov->extents.y1 - mov->extents.y0);
  dh = SWFDEC_TWIPS_TO_DOUBLE ((SwfdecTwips) dh);
#else
  /* copy from swfdec_sprite_movie_getBounds */
  SwfdecRect rect = mov->extents;
  if (mov->parent)
  	swfdec_movie_rect_local_to_global (mov->parent, &rect);
  swfdec_player_global_to_stage (player, &rect.x0, &rect.y0);
  swfdec_player_global_to_stage (player, &rect.x1, &rect.y1);  
/*
  dx = SWFDEC_TWIPS_TO_DOUBLE(rect.x0);
  dy = SWFDEC_TWIPS_TO_DOUBLE(rect.y0);
  dw = SWFDEC_TWIPS_TO_DOUBLE(rect.x1 - rect.x0);
  dh = SWFDEC_TWIPS_TO_DOUBLE(rect.y1 - rect.y0);
*/
  dx = rect.x0;
  dy = rect.y0;
  dw = rect.x1 - rect.x0;
  dh = rect.y1 - rect.y0;
#if 0
  g_printerr("transforming movie, transform: %g %g  %g %g   %g %g, scale : %g, %g\n",
    mov->matrix.xx, mov->matrix.yy,
    mov->matrix.xy, mov->matrix.yx,
    mov->matrix.x0, mov->matrix.y0,
	mov->xscale, mov->yscale);
#endif
#endif
  swfdec_video_provider_set_position(movie->provider,
	dx + movie->x_,
	dy + movie->y_,
	dw,
	dh);
#if 0
  g_printerr("dw = %f, dh = %f, ow = %d, oh = %d, ww = %f, hh = %f, xs = %f, ys = %f\n",
	dw, dh, org->width, org->height, 
	SWFDEC_TWIPS_TO_DOUBLE(rect.x1 - rect.x0), 
	SWFDEC_TWIPS_TO_DOUBLE(rect.y1 - rect.y0),
	mov->xscale,
	mov->yscale);	
#endif
}

static void
swfdec_video_movie_update_extents (SwfdecMovie *movie,
    SwfdecRect *extents)
{
  SwfdecVideoMovie *mov = SWFDEC_VIDEO_MOVIE (movie);
  SwfdecVideo *org = SWFDEC_VIDEO (movie->graphic);
  SwfdecRect rect = { 0, 0, 
    SWFDEC_TWIPS_SCALE_FACTOR * org->width, 
    SWFDEC_TWIPS_SCALE_FACTOR * org->height };
  
  swfdec_rect_union (extents, extents, &rect);
  /* set position */
  if (mov->provider)
	swfdec_video_movie_set_position(mov);
}

static void
swfdec_video_movie_render (SwfdecMovie *mov, cairo_t *cr, 
    const SwfdecColorTransform *trans)
{
  SwfdecVideoMovie *movie = SWFDEC_VIDEO_MOVIE (mov);

  SwfdecRect rect = mov->original_extents;

  if (movie->provider == NULL || movie->clear)
    return;
  
  if (g_x != movie->x_ || g_y != movie->y_)
  {
	movie->x_ = g_x;
	movie->y_ = g_y;
  }  
  if (movie->provider)		
	swfdec_video_movie_set_position(movie);
  movie->failflag = swfdec_video_provider_get_failflag(movie->provider);
  if (!movie->failflag)
  {
  	cairo_set_source_rgba (cr, 0, 0, 0, 0);
  	cairo_rectangle (cr, 0, 0, rect.x1 - rect.x0, rect.y1 - rect.y0);
  	//g_printerr("swfdec_video_movie_render\n");
  	cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
  	cairo_fill (cr);
  }
  else
  {
	if (!movie->surface)
	{
	  char *p = NULL;
	  char path[128] = "/root/net_app/owb";
	  SwfdecBuffer *buffer = NULL;
	  SwfdecImage *image;
	  GError *error = NULL;
	  g_printerr("load fail image!\n");
	  p = getenv("GNASH_FAIL_IMAGE");
	  if (p == NULL)
	  {
	  	p = getenv("VA_RUNTIME_ROOT");
		if (p != NULL && strlen(p) < sizeof(path) - 20)
		{
			strcpy(path, p);			
		}
		strcat(path, "/Resources/fail.png");
		p = path;
	  }
	  buffer = swfdec_buffer_new_from_file (p, &error);
	  if (!buffer)
		return;
	  image = swfdec_image_new2(buffer);
	  movie->surface = swfdec_image_create_surface (image, NULL);
	  // unref image ?
	  if (movie->surface == NULL)
		return;
	  movie->width = cairo_image_surface_get_width (movie->surface);
	  movie->height = cairo_image_surface_get_height (movie->surface);
	}
	if ((!movie->surface) || movie->width == 0 || movie->height == 0)
  	  return;
	cairo_scale (cr,
    	(mov->original_extents.x1 - mov->original_extents.x0)
    	/ movie->width,
    	(mov->original_extents.y1 - mov->original_extents.y0)
    	/ movie->height);
	cairo_set_source_surface (cr, movie->surface, 0.0, 0.0);
	cairo_paint (cr);
  }
}

static void
swfdec_video_movie_new_image (SwfdecVideoProvider *provider, SwfdecVideoMovie *movie)
{
  movie->clear = FALSE;
  swfdec_movie_invalidate_last (SWFDEC_MOVIE (movie));
}

static void
swfdec_video_movie_dispose (GObject *object)
{
  SwfdecVideoMovie *movie = SWFDEC_VIDEO_MOVIE (object);

  if (movie->provider) {
    g_signal_handlers_disconnect_by_func (movie->provider,
	swfdec_video_movie_new_image, movie);
    g_object_unref (movie->provider);
    movie->provider = NULL;
  }

  if (movie->surface) {
	cairo_surface_destroy (movie->surface);
	movie->surface = NULL;
	movie->width = 0;
	movie->height = 0;	
  }

  G_OBJECT_CLASS (swfdec_video_movie_parent_class)->dispose (object);
}

static void
swfdec_video_movie_set_ratio (SwfdecMovie *movie)
{
  SwfdecVideoMovie *video = SWFDEC_VIDEO_MOVIE (movie);

  if (video->provider)
    swfdec_video_provider_set_ratio (video->provider, movie->original_ratio);
}

static void
swfdec_video_movie_invalidate (SwfdecMovie *movie, const cairo_matrix_t *matrix, gboolean last)
{
  SwfdecVideo *org = SWFDEC_VIDEO (movie->graphic);
  SwfdecRect rect = { 0, 0, 
    SWFDEC_TWIPS_SCALE_FACTOR * org->width, 
    SWFDEC_TWIPS_SCALE_FACTOR * org->height };

  swfdec_rect_transform (&rect, &rect, matrix);
  swfdec_player_invalidate (SWFDEC_PLAYER (swfdec_gc_object_get_context (movie)),
      movie, &rect);
}

static GObject *
swfdec_video_movie_constructor (GType type, guint n_construct_properties,
    GObjectConstructParam *construct_properties)
{
  GObject *object;
  SwfdecMovie *movie;
  SwfdecVideo *video;
  gboolean unuse;

  object = G_OBJECT_CLASS (swfdec_video_movie_parent_class)->constructor (type, 
      n_construct_properties, construct_properties);

  movie = SWFDEC_MOVIE (object);
  unuse = swfdec_sandbox_try_use (movie->resource->sandbox);
  swfdec_video_movie_init_properties (swfdec_gc_object_get_context (movie));
  swfdec_as_object_set_constructor_by_name (swfdec_as_relay_get_as_object (SWFDEC_AS_RELAY (movie)), 
      SWFDEC_AS_STR_Video, NULL);
  if (unuse)
    swfdec_sandbox_unuse (movie->resource->sandbox);

  video = SWFDEC_VIDEO (movie->graphic);

  if (video->n_frames > 0) {
    SwfdecVideoProvider *provider = swfdec_video_video_provider_new (video);
    swfdec_video_movie_set_provider (SWFDEC_VIDEO_MOVIE (movie), provider);
    g_object_unref (provider);
  }

  return object;
}

static void
swfdec_video_movie_class_init (SwfdecVideoMovieClass * g_class)
{
  GObjectClass *object_class = G_OBJECT_CLASS (g_class);
  SwfdecMovieClass *movie_class = SWFDEC_MOVIE_CLASS (g_class);

  object_class->constructor = swfdec_video_movie_constructor;
  object_class->dispose = swfdec_video_movie_dispose;

  movie_class->update_extents = swfdec_video_movie_update_extents;
  movie_class->render = swfdec_video_movie_render;
  movie_class->invalidate = swfdec_video_movie_invalidate;
  movie_class->set_ratio = swfdec_video_movie_set_ratio;
}

static void
swfdec_video_movie_init (SwfdecVideoMovie * video_movie)
{
  video_movie->failflag = FALSE;
  video_movie->x_ = g_x;
  video_movie->y_ = g_y;
  video_movie->surface = NULL;
  video_movie->width = 0;
  video_movie->height = 0;
}

void
swfdec_video_movie_set_provider (SwfdecVideoMovie *movie, 
    SwfdecVideoProvider *provider)
{
  g_return_if_fail (SWFDEC_IS_VIDEO_MOVIE (movie));
  g_return_if_fail (provider == NULL || SWFDEC_IS_VIDEO_PROVIDER (provider));

  if (provider == movie->provider)
    return;

  if (provider) {
    g_object_ref (provider);
    g_signal_connect (provider, "new-image", 
	G_CALLBACK (swfdec_video_movie_new_image), movie);
  }

  if (movie->provider) {
    g_signal_handlers_disconnect_by_func (movie->provider,
	swfdec_video_movie_new_image, movie);
    g_object_unref (movie->provider);
  }

  movie->provider = provider;
  if (movie->provider)
  {
	swfdec_video_movie_set_position(movie);
  }
  swfdec_movie_invalidate_last (SWFDEC_MOVIE (movie));
}

void
swfdec_video_movie_clear (SwfdecVideoMovie *movie)
{
  g_return_if_fail (SWFDEC_IS_VIDEO_MOVIE (movie));

  movie->clear = TRUE;
  swfdec_movie_invalidate_last (SWFDEC_MOVIE (movie));
}

