/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
/*
 * unity-webapps-script-loader.c
 * Copyright (C) Canonical LTD 2012
 * 
 * Author: Alex Launi <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 <gio/gio.h>

#include "unity-webapps-application-manifest.h"

#include "unity-webapps-script-loader.h"
#include "../context-daemon/util/unity-webapps-dirs.h"

struct _UnityWebappsScriptLoaderPrivate {
	GHashTable *found_requires_by_name;
};

G_DEFINE_TYPE (UnityWebappsScriptLoader, unity_webapps_script_loader, G_TYPE_OBJECT);

#define UNITY_WEBAPPS_SCRIPT_LOADER_GET_PRIVATE(object) (G_TYPE_INSTANCE_GET_PRIVATE ((object), UNITY_WEBAPPS_TYPE_SCRIPT_LOADER, UnityWebappsScriptLoaderPrivate))


static void
unity_webapps_script_loader_finalize (GObject *object)
{
  UnityWebappsScriptLoader *loader;
  
  loader = (UnityWebappsScriptLoader *)object;
  
  g_hash_table_destroy (loader->priv->found_requires_by_name);
}


static void
unity_webapps_script_loader_class_init (UnityWebappsScriptLoaderClass *klass)
{
  GObjectClass *object_class = G_OBJECT_CLASS (klass);
  
  object_class->finalize = unity_webapps_script_loader_finalize;
  
  g_type_class_add_private (object_class, sizeof (UnityWebappsScriptLoaderPrivate));
}

static gchar *
unity_webapps_script_loader_find_require_path_in_data_dir (UnityWebappsScriptLoader *loader, const gchar *data_dir, const gchar *require)
{
  gchar *require_file;
  gboolean exists;
  
  require_file = g_build_filename (data_dir, "unity-webapps/userscripts/common", require, NULL);
  exists = g_file_test (require_file, G_FILE_TEST_EXISTS);
  
  if (exists)
	{
	  return require_file;
	}
  else
	{
	  g_free (require_file);
	}
  
  return NULL;  
}

static const gchar *
unity_webapps_script_loader_find_require_path (UnityWebappsScriptLoader *loader, const gchar *require)
{
  const gchar * const *system_dirs;
  const gchar *user_dir;
  gchar *require_path;
  gint i, len;
  
  require_path = g_hash_table_lookup (loader->priv->found_requires_by_name, require);
  
  if (require_path != NULL)
	{
	  return require_path;
	}
  
  user_dir = unity_webapps_dirs_get_user_dir ();
  require_path = 
	unity_webapps_script_loader_find_require_path_in_data_dir (loader, user_dir, require);
  
  if (require_path != NULL)
	{
	  g_hash_table_insert (loader->priv->found_requires_by_name, g_strdup (require), require_path);
	  return require_path;
	}
  
  system_dirs = g_get_system_data_dirs ();
  len = g_strv_length ((gchar **)system_dirs);
  for (i = 0; i < len; i++)
	{
	  const gchar *system_data_dir;
	  
	  system_data_dir = system_dirs[i];
	  require_path = unity_webapps_script_loader_find_require_path_in_data_dir (loader, system_data_dir, require);
	  
	  if (require_path != NULL)
		{
		  g_hash_table_insert (loader->priv->found_requires_by_name, g_strdup (require), require_path);
		  return require_path;
		}
	}
  return NULL;
}

static gchar *
unity_webapps_script_loader_get_require_contents (UnityWebappsScriptLoader *self,
												  const gchar *require)
{
  const gchar *require_path;
  gchar *contents;
  GError *error;
  
  require_path = unity_webapps_script_loader_find_require_path (self, require);
  
  if (require_path == NULL)
	{
	  return NULL;
	}

  error = NULL;
  g_file_get_contents (require_path, &contents, NULL, &error);

  if (error != NULL)
	{
	  g_warning ("Failed to load required script file: %s \n", error->message);
	  g_error_free (error);
	  
	  return NULL;
	}
  return contents;  
}

static gchar *
unity_webapps_script_loader_get_combined_requirements (UnityWebappsScriptLoader *self,
													   UnityWebappsApplicationManifest *manifest)
{
  GString *combined_requirements;
  const gchar **require_files;
  gchar *ret;
  gint i, len;
  
  require_files = unity_webapps_application_manifest_get_requires (manifest);
  if (require_files == NULL)
	{
	  return NULL;
	}
  combined_requirements = g_string_new ("");
  

  len = g_strv_length ((gchar **)require_files);
  for (i = 0; i < len; i++)
	{
	  const gchar *require_file;
	  gchar *contents;
	  
	  require_file = require_files[i];
	  contents = unity_webapps_script_loader_get_require_contents (self, require_file);

	  if (contents == NULL)
		{
		  g_string_free (combined_requirements, TRUE);
		  return NULL;
		}
	  g_string_append_printf (combined_requirements, "\n// imported script: %s\n", require_file);
	  combined_requirements = g_string_append (combined_requirements, contents);
	  
	  g_free (contents);
	}

  ret = combined_requirements->str;
  g_string_free (combined_requirements, FALSE);

  return ret;
}

static gchar *
unity_webapps_script_loader_get_userscript_content (UnityWebappsScriptLoader *loader, UnityWebappsApplicationManifest *manifest,
													const gchar *script)
{
  const gchar *base_path;
  gchar *userscript_path, *contents;
  GError *error;
  
  base_path = unity_webapps_application_manifest_get_base_path (manifest);
  userscript_path = g_build_filename (base_path, script, NULL);
  
  error = NULL;
  contents = NULL;

  g_file_get_contents (userscript_path, &contents, NULL, &error);
  
  if (error != NULL)
	{
	  g_warning ("Failed to load userscript contents: %s \n", error->message);
	  g_error_free (error);

	}
  
  g_free (userscript_path);
  return contents;
}

static gchar *
unity_webapps_script_loader_get_combined_userscripts (UnityWebappsScriptLoader *loader, UnityWebappsApplicationManifest *manifest)
{
  GString *combined_scripts;
  const gchar **scripts;
  gchar *ret;
  gint i, len;
  
  scripts = unity_webapps_application_manifest_get_scripts (manifest);
  
  if (scripts == NULL)
	{
	  return NULL;
	}
  
  combined_scripts = g_string_new ("");
  len = g_strv_length ((gchar **)scripts);
  for (i = 0; i < len; i++)
	{
	  const gchar *script;
	  gchar *contents;
	  
	  script = scripts[i];
	  contents = unity_webapps_script_loader_get_userscript_content (loader, manifest, script);
	  
	  if (contents == NULL)
		{
		  g_string_free (combined_scripts, TRUE);
		  return NULL;
		}
	  combined_scripts = g_string_append (combined_scripts, contents);
	  
	  g_free (contents);
	}
  ret = combined_scripts->str;
  g_string_free (combined_scripts, FALSE);
  
  return ret;
}


static void
unity_webapps_script_loader_init (UnityWebappsScriptLoader *self)
{
  self->priv = UNITY_WEBAPPS_SCRIPT_LOADER_GET_PRIVATE (self);
  self->priv->found_requires_by_name = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
}

UnityWebappsScriptLoader *
unity_webapps_script_loader_new ()
{
  return g_object_new (UNITY_WEBAPPS_TYPE_SCRIPT_LOADER, NULL);
}

gchar *
unity_webapps_script_loader_get_userscript_contents (UnityWebappsScriptLoader *loader, UnityWebappsLocalAvailableApplication *application)
{
  UnityWebappsApplicationManifest *manifest;
  gchar *user_scripts;
  gchar *requirements;
  gchar *contents;
  
  manifest = unity_webapps_local_available_application_get_manifest (application);
  
  requirements = unity_webapps_script_loader_get_combined_requirements (loader, manifest);
  user_scripts = unity_webapps_script_loader_get_combined_userscripts (loader, manifest);
  
  contents = g_strconcat (requirements ? requirements : "" , user_scripts, NULL);

  g_free (requirements);
  g_free (user_scripts);
  
  return contents;
}
