#include "unity-webapps-url-db.h"
#include "unity-webapps-dirs.h"
#include "unity-webapps-debug.h"

#include <sqlite3.h>

struct _UnityWebappsUrlDB {
  sqlite3 *db;
};


#define CREATE_URL_TABLE_SQL "CREATE TABLE IF NOT EXISTS urls(url TEXT, package TEXT, appname TEXT, domain TEXT, PRIMARY KEY(url));"

#define INSERT_URL_SQL_TEMPLATE "INSERT OR REPLACE INTO urls(url, package, appname, domain) VALUES (%Q, %Q, %Q, %Q);"

#define LOOKUP_URLS_SQL_TEMPLATE "SELECT package, appname, domain FROM urls WHERE %Q GLOB url;"

#define UNITY_WEBAPPS_URL_DB_DEFAULT_PATH_ENV_VARIABLE "UNITY_WEBAPPS_URL_DB_DEFAULT_PATH"

static sqlite3_stmt *
unity_webapps_url_db_insert_url_prepare_statement (UnityWebappsUrlDB *url_db,
						   const gchar *url,
						   UnityWebappsUrlDBRecord *record)
{
  gchar *statement_sql, *stripped_url, *stripped_package;
  sqlite3_stmt *statement;
  gint rc;
  
  stripped_url = g_strdup(url);
  stripped_url = g_strstrip (stripped_url);
  stripped_package = g_strdup(record->package_name);
  stripped_package = g_strstrip(stripped_package);

  statement_sql = sqlite3_mprintf (INSERT_URL_SQL_TEMPLATE, stripped_url,
				   stripped_package, record->application_name,
				   record->domain);
  
  statement = NULL;
  
  rc = sqlite3_prepare_v2 (url_db->db, statement_sql, -1, &statement, NULL);
  
  if (rc != SQLITE_OK)
    {
      UNITY_WEBAPPS_NOTE (URL_DB, "Failed to compile URL DB insert URL statement: %s",
			  sqlite3_errmsg (url_db->db));
    }
  sqlite3_free (statement_sql);
  
  g_free (stripped_url);
  g_free (stripped_package);
  
  return statement;
}

static sqlite3_stmt *
unity_webapps_url_db_lookup_urls_prepare_statement (UnityWebappsUrlDB *url_db,
					     const gchar *url)
{
  gchar *statement_sql;
  sqlite3_stmt *statement;
  gint rc;
  
  statement_sql = sqlite3_mprintf (LOOKUP_URLS_SQL_TEMPLATE, url);
  
  statement = NULL;
  
  rc = sqlite3_prepare_v2 (url_db->db, statement_sql, -1, &statement, NULL);
  
  if (rc != SQLITE_OK)
    {
      UNITY_WEBAPPS_NOTE (URL_DB, "Failed to compile URL DB lookup URLs statement: %s",
		  sqlite3_errmsg (url_db->db));
    }
  sqlite3_free (statement_sql);
  
  return statement;
}

gboolean
unity_webapps_url_db_lookup_urls (UnityWebappsUrlDB *url_db, const gchar *url,
				  GList **out_records)
{
  GList *records;
  sqlite3_stmt *url_statement;
  int rc;
  gboolean ret = TRUE;
  
  *out_records = records = NULL;
  
  url_statement = unity_webapps_url_db_lookup_urls_prepare_statement (url_db, url);
  
  if (url_statement == NULL)
    {
      return FALSE;
    }
  
  do {
    const gchar *package_name;
    const gchar *app_name;
    const gchar *app_domain;
    rc = sqlite3_step (url_statement);
    
    if (rc != SQLITE_ROW)
      {
	continue;
      }
    
    package_name = (const gchar *)sqlite3_column_text (url_statement, 0);
    app_name = (const gchar *)sqlite3_column_text (url_statement, 1);
    app_domain = (const gchar *)sqlite3_column_text (url_statement, 2);
    records = g_list_append (records, unity_webapps_url_db_record_new (package_name, app_name, app_domain));
  } while (rc == SQLITE_ROW);
  
  if (rc != SQLITE_DONE)
    {
      ret = FALSE;
    }
  
  sqlite3_finalize (url_statement);
  *out_records = records;
  
  return ret;
}

gboolean
unity_webapps_url_db_insert_url (UnityWebappsUrlDB *url_db, const gchar *url,
				 UnityWebappsUrlDBRecord *record)
{
  sqlite3_stmt *url_statement;
  int rc;
  gboolean ret = TRUE;
  
  url_statement = unity_webapps_url_db_insert_url_prepare_statement (url_db, url, record);
  
  if (url_statement == NULL)
    {
      return FALSE;
    }
  
  rc = sqlite3_step (url_statement);
  
  if (rc != SQLITE_DONE)
    {
      g_warning ("Error updating url in url db: %s", sqlite3_errmsg (url_db->db));
      ret = FALSE;
      
      goto out;
    }
  
 out:
  sqlite3_finalize (url_statement);
  return ret;
}

static int
unity_webapps_url_db_create_tables (UnityWebappsUrlDB *url_db)
{
  int rc;
  gchar *error_message;
  
  error_message = NULL;
  
  rc = sqlite3_exec (url_db->db, CREATE_URL_TABLE_SQL, NULL, 0, &error_message);
  
  if (rc != SQLITE_OK)
    {
      UNITY_WEBAPPS_NOTE (URL_DB, "Error creating URL db table: %s\n", error_message);
      sqlite3_free (error_message);
    }
  return rc;
}

UnityWebappsUrlDB *
unity_webapps_url_db_open (gboolean read_only, const gchar *database_path)
{
  UnityWebappsUrlDB *url_db;
  int rc;
  
  url_db = g_malloc0 (sizeof (UnityWebappsUrlDB));
  
  rc = sqlite3_open (database_path, &url_db->db);
  
  if (rc != 0)
    {
      UNITY_WEBAPPS_NOTE (URL_DB, "Failed to open app url database : %s \n", sqlite3_errmsg(url_db->db));
      sqlite3_close (url_db->db);
      g_free (url_db);
      
      return NULL;
    }
  
  rc = unity_webapps_url_db_create_tables (url_db);
  
  if (rc != 0)
    {
      sqlite3_close (url_db->db);
      g_free (url_db);
      return NULL;
    }
  
  return url_db;
}

void
unity_webapps_url_db_free (UnityWebappsUrlDB *url_db)
{
  sqlite3_close (url_db->db);
  g_free (url_db);
}

UnityWebappsUrlDB *
unity_webapps_url_db_open_default (gboolean read_only)
{
  UnityWebappsUrlDB *default_db;
  const gchar *uwa_user_dir;
  const gchar *env_db_path;
  gchar *db_path;
  
  env_db_path = g_getenv (UNITY_WEBAPPS_URL_DB_DEFAULT_PATH_ENV_VARIABLE);
  if (env_db_path != NULL)
    {
      default_db = unity_webapps_url_db_open (read_only, env_db_path);
      return default_db;
    }
  uwa_user_dir = unity_webapps_dirs_get_user_dir ();
  db_path = g_build_filename (uwa_user_dir, "availableapps-v2.db", NULL);

  default_db = unity_webapps_url_db_open (read_only, db_path);
  g_free (db_path);
  
  return default_db;
}

UnityWebappsUrlDBRecord *
unity_webapps_url_db_record_new (const gchar *package_name, 
				 const gchar *application_name,
				 const gchar *application_domain)
{
  UnityWebappsUrlDBRecord *record;
  
  record = g_malloc0 (sizeof (UnityWebappsUrlDBRecord));
  record->package_name = g_strdup (package_name);
  record->application_name = g_strdup (application_name);
  record->domain = g_strdup (application_domain);
  
  return record;
}

void
unity_webapps_url_db_record_free (UnityWebappsUrlDBRecord *record)
{
  g_free (record->package_name);
  g_free (record->application_name);
  g_free (record->domain);
  
  g_free (record);
}

void
unity_webapps_url_db_record_list_free (GList *record_list)
{
  GList *w;
  
  for (w = record_list; w != NULL; w = w->next)
    {
      UnityWebappsUrlDBRecord *record;
      
      record = (UnityWebappsUrlDBRecord *)w->data;
      unity_webapps_url_db_record_free (record);
    }
  
  g_list_free (record_list);
}
