/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
/*
 * test.c
 * Copyright (C) Canonical LTD 2011
 * 
 * Author: Robert Carr <racarr@canonical.com>
 * 
 unity-webapps 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 3 of the License, or
 * (at your option) any later version.
 * 
 * unity-webapps 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 program.  If not, see <http://www.gnu.org/licenses/>.";
 */

#include "uwa-test.h"
#include "uwa-trace.h"

#include <stdio.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>

#include <glib/gstdio.h>

struct _UwaTest {
  gchar *name;
  
  UwaTrace *context_trace;
  UwaTrace *service_trace;
  UwaTrace *client_trace;
	
  gboolean echo;
};

UwaTest *
uwa_test_new (const gchar *test_name, gboolean do_not_trace, gboolean echo)
{
  UwaTest *test;
  
  test = g_malloc0 (sizeof (UwaTest));
  
  test->name = g_strdup (test_name);
  
  if (do_not_trace == FALSE)
	{
	  test->context_trace = uwa_trace_new_for_test_name (test_name, "Context");
	  
	  if (test->context_trace == NULL)
		{
		  g_error ("Failed to load trace file (Context Channel)");
		  return NULL;
		}
	  
	  test->service_trace = uwa_trace_new_for_test_name (test_name, "Service");
	  
	  if (test->service_trace == NULL)
		{
		  g_error ("Failed to load trace file (Service Channel)");
		  return NULL;
		}
	  
	  test->client_trace = uwa_trace_new_for_test_name (test_name, "Client");
	  
	  if (test->client_trace == NULL)
		{
		  g_error ("Failed to load trace file (Client Channel)");
		  return NULL;
		}
	}
  else
	{
	  test->context_trace = NULL;
	  test->service_trace = NULL;
	  test->client_trace = NULL;
	}
  
  test->echo = echo;
  
  return test;
}

void
uwa_test_free (UwaTest *test)
{
  uwa_trace_free (test->context_trace);
  uwa_trace_free (test->service_trace);
  uwa_trace_free (test->client_trace);
  g_free (test->name);
  g_free (test);
}

static gboolean
kill_existing_service ()
{
  gchar *argv[] = {"../../tools/unity-webapps-tool", "shutdown", NULL};
  GError *error;
  
  error = NULL;
  
  g_spawn_sync (NULL, argv, NULL, G_SPAWN_SEARCH_PATH |
				G_SPAWN_STDOUT_TO_DEV_NULL |
				G_SPAWN_STDERR_TO_DEV_NULL,
				NULL,
				NULL,
				NULL,
				NULL,
				NULL,
				&error);
  
  if (error != NULL)
	{
	  g_error ("Error running unity-webapps-tool to shutdown: %s", error->message);
	  
	  g_error_free (error);
	  
	  return FALSE;
	}
  
  return TRUE;
}

#define SERVICE_MESSAGE_PREFIX "** Message: [SERVICE]"

static gboolean
service_out_watch (GIOChannel *channel,
				   GIOCondition condition,
				   gpointer user_data)
{
  UwaTest *test;
  gchar *out_line;
  gsize size;
  
  test = (UwaTest *) user_data;
  
  if (condition == G_IO_HUP)
	{
	  g_io_channel_unref (channel);
	  
	  return FALSE;
	}
  
  g_io_channel_read_line (channel, &out_line, &size, NULL, NULL);

  if (test->echo)
	{
	  g_printf("%s", out_line);
	}

  if (test->service_trace && g_str_has_prefix (out_line, SERVICE_MESSAGE_PREFIX))
	{
	  if (uwa_trace_process_line (test->service_trace, out_line) == FALSE)
		{
		  g_error ("Failed to process line against trace (service channel)");
		}
	  
	}
  else if (test->context_trace)
	{
	  if (uwa_trace_process_line (test->context_trace, out_line) == FALSE)
		{
		  g_error ("Failed to process line against trace (context channel)");
		}
  
	}

  g_free (out_line);
  
  return TRUE;
}

static gboolean
spawn_new_service (UwaTest *test)
{
  GIOChannel *out_ch;
  gchar *argv[] = {"../../src/webapps-service/unity-webapps-service", NULL};
  gint child_stderr;
  GError *error;
  
  error = NULL;
  
  g_spawn_async_with_pipes (NULL, argv, NULL, 0, NULL, NULL, NULL, NULL,
						    NULL, &child_stderr, &error);

  if (error != NULL)
	{
	  g_error ("Error spawning service: %s", error->message);
	  
	  g_error_free (error);
	  
	  return FALSE;
	}
  
  out_ch = g_io_channel_unix_new (child_stderr);
  
  g_io_add_watch (out_ch, G_IO_IN | G_IO_HUP, (GIOFunc)service_out_watch, test);
  
  return TRUE;
}

gboolean
uwa_test_prepare_environment (UwaTest *test)
{
  g_setenv("UNITY_WEBAPPS_DEBUG_FLAGS", "all", TRUE);
  g_setenv("UNITY_WEBAPPS_TESTS_DISABLE_INDEX_UPDATER", "yes", TRUE);
  g_setenv("UNITY_WEBAPPS_RUNNING_TRACED_TESTS", "yes", TRUE);
  g_setenv("UNITY_WEBAPPS_USE_DBUS_CONTROLLABLE_WINDOW_TRACKING", "yes", TRUE);

  if (kill_existing_service() == FALSE)
	{
	  printf("Couldnt kill \n");
	  return FALSE;
	}
  
  if (spawn_new_service(test) == FALSE)
	{
	  return FALSE;
	}
  
  return TRUE;
}

static gboolean
client_out_watch (GIOChannel *channel,
				  GIOCondition condition,
				  gpointer user_data)
{
  UwaTest *test;
  gchar *out_line;
  gsize size;
  
  test = (UwaTest *)user_data;
  
  if (condition == G_IO_HUP)
	{
	  g_io_channel_unref (channel);
	  
	  return FALSE;
	}
  
  g_io_channel_read_line (channel, &out_line, &size, NULL, NULL);
  
  if (test->echo)
	{
	  g_printf("(Client) %s", out_line);
	}
  
  if (test->client_trace)
	{
	  if (uwa_trace_process_line (test->client_trace, out_line) == FALSE)
		{
		  g_error ("Failed to process line against trace (client channel)");
		}
	}
  
  g_free (out_line);
  
  return TRUE;
}

static gboolean
spawn_new_test (UwaTest *test)
{
  GIOChannel *out_ch;
  gchar *argv[] = {NULL, NULL};
  gint child_stderr;
  GError *error;
	
  error = NULL;
	
  argv[0] = test->name;
	
  g_spawn_async_with_pipes (NULL, argv, NULL, 0, NULL, NULL,
							NULL, NULL,
							NULL, &child_stderr, &error);
	
  if (error != NULL)
	{
	  g_error ("Error spawning test: %s", error->message);
		
	  g_error_free (error);
		
	  return FALSE;
	}
  
  out_ch = g_io_channel_unix_new (child_stderr);
  
  g_io_add_watch (out_ch, G_IO_IN | G_IO_HUP, (GIOFunc)client_out_watch, test);
	
  return TRUE;
}

gboolean
uwa_test_run (UwaTest *test)
{
  spawn_new_test (test); 
  
  return TRUE;
}


gboolean
uwa_test_passed (UwaTest *test, gboolean print_next)
{
  if (test->context_trace &&  (uwa_trace_passed (test->context_trace, print_next) == FALSE))
	{
	  return FALSE;
	}
  else if (test->service_trace && (uwa_trace_passed (test->service_trace, print_next) == FALSE))
	{
	  return FALSE;
	}
  else if (test->client_trace && (uwa_trace_passed (test->client_trace, print_next) == FALSE))
	{
	  return FALSE;
	}
  
  return TRUE;
}
