/*-
 * Copyright (c) 2006 Benedikt Meurer <benny@xfce.org>.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 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
 * Library 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_ERRNO_H
#include <errno.h>
#endif
#ifdef HAVE_STDIO_H
#include <stdio.h>
#endif

#include <libxfce4util/libxfce4util.h>

#include "xfce-die-utils.h"



/**
 * xfce_die_g_key_file_set_locale_value:
 * @key_file : the #GKeyFile.
 * @group    : the group name.
 * @key      : the key name.
 * @value    : the new value.
 *
 * Stores @value localized for @key in @group if it
 * is already localized.
 **/
void
xfce_die_g_key_file_set_locale_value (GKeyFile *key_file,
                                      const gchar *group,
                                      const gchar *key,
                                      const gchar *value)
{
  const gchar *const *locale;
  gchar *name;

  g_return_if_fail (key_file != NULL);
  g_return_if_fail (group != NULL);
  g_return_if_fail (key != NULL);
  g_return_if_fail (value != NULL);

  /* try localized first */
  for (locale = g_get_language_names (); *locale != NULL; ++locale)
    {
      name = g_strdup_printf ("%s[%s]", key, *locale);
      if (g_key_file_has_key (key_file, group, name, NULL))
        {
          g_key_file_set_string (key_file, group, name, value);
          g_free (name);
          break;
        }
      g_free (name);
    }

  /* fallback to unlocalized */
  if (G_UNLIKELY (*locale == NULL))
    g_key_file_set_string (key_file, group, key, value);
}



static void
trust_launcher (GFile *gfile)
{
  /* trust the launcher since the user created it */
  guint32 mode = 0111, mask = 0111;
  guint32 old_mode, new_mode;
  GFileInfo *info;

  info = g_file_query_info (gfile,
                            G_FILE_ATTRIBUTE_UNIX_MODE,
                            G_FILE_QUERY_INFO_NONE,
                            NULL,
                            NULL);

  if (info == NULL)
    return;

  old_mode = g_file_info_get_attribute_uint32 (info, G_FILE_ATTRIBUTE_UNIX_MODE);
  new_mode = (old_mode & ~mask) | mode;

  if (old_mode != new_mode)
    {
      g_file_set_attribute_uint32 (gfile,
                                   G_FILE_ATTRIBUTE_UNIX_MODE, new_mode,
                                   G_FILE_QUERY_INFO_NONE,
                                   NULL,
                                   NULL);
    }

  g_object_unref (info);

  if (xfce_g_file_metadata_is_supported (gfile))
    xfce_g_file_set_trusted (gfile, TRUE, NULL, NULL);
}



/**
 * xfce_die_g_key_file_save:
 * @key_file : the #GKeyFile.
 * @create   : whether to create.
 * @trust    : whether to trust the launcher.
 * @base     : file or folder (if @create).
 * @mode     : file mode for .directory or .desktop suffix.
 * @error    : return location for errors or %NULL.
 *
 * Writes changes to the @key_file .desktop or .directory file.
 *
 * Return value: #GFile that was written, or %NULL on error.
 **/
GFile *
xfce_die_g_key_file_save (GKeyFile *key_file,
                          gboolean create,
                          gboolean trust,
                          GFile *base,
                          XfceDieEditorMode mode,
                          GError **error)
{
  GFileType file_type;
  GFile *file;
  gchar *name, *s;
  gchar *filename, *data;
  gsize length;
  gboolean result;
  guint n;
  gboolean desktop_suffix;
  const gchar *suffix;

  g_return_val_if_fail (G_IS_FILE (base), NULL);
  g_return_val_if_fail (key_file != NULL, NULL);
  g_return_val_if_fail (error == NULL || *error == NULL, NULL);

  /* check if we should create a new file */
  if (G_LIKELY (create))
    {
      if (mode == XFCE_DIE_EDITOR_MODE_DIRECTORY)
        suffix = ".directory";
      else
        suffix = ".desktop";

      /* if the filename end with .desktop, then use the base as file */
      name = g_file_get_basename (base);
      desktop_suffix = g_str_has_suffix (name, suffix);
      g_free (name);
      if (desktop_suffix)
        {
          file = g_object_ref (base);
        }
      else
        {
          file_type = g_file_query_file_type (base, G_FILE_QUERY_INFO_NONE, NULL);
          if (file_type == G_FILE_TYPE_REGULAR)
            {
              file = g_object_ref (base);
            }
          else if (file_type == G_FILE_TYPE_DIRECTORY)
            {
              /* determine the desktop entry name */
              name = g_key_file_get_locale_string (key_file, G_KEY_FILE_DESKTOP_GROUP,
                                                   G_KEY_FILE_DESKTOP_KEY_NAME, NULL, NULL);
              if (G_UNLIKELY (name == NULL))
                name = g_strdup ("launcher");

              /* replace invalid file system characters */
              for (s = name; *s != '\0'; ++s)
                if (G_IS_DIR_SEPARATOR (*s) || *s == '.')
                  *s = '_';

              /* create a unique filename */
              filename = g_strconcat (name, suffix, NULL);
              file = g_file_get_child_for_display_name (base, filename, error);
              for (n = 0; file != NULL && g_file_query_exists (file, NULL); n++)
                {
                  /* release the previous name */
                  g_free (filename);
                  g_object_unref (file);

                  /* generate a new file name */
                  filename = g_strdup_printf ("%s%d%s", name, n, suffix);
                  file = g_file_get_child_for_display_name (base, filename, error);
                }

              /* cleanup */
              g_free (filename);
              g_free (name);

              if (G_UNLIKELY (file == NULL))
                return NULL;
            }
          else
            {
              /* base is not a directory, cannot save */
              g_set_error_literal (error, G_FILE_ERROR, g_file_error_from_errno (ENOTDIR),
                                   _("File location is not a regular file or directory"));
              return NULL;
            }
        }
    }
  else
    {
      /* base is the file */
      file = g_object_ref (base);
    }

  /* determine the data for the key file */
  data = g_key_file_to_data (key_file, &length, error);
  if (G_UNLIKELY (data == NULL))
    {
      g_object_unref (file);
      return NULL;
    }

  /* need to recalculate checksum */
  trust = trust || xfce_g_file_is_trusted (file, NULL, NULL);

  result = g_file_replace_contents (file, data, length, NULL, FALSE,
                                    G_FILE_CREATE_NONE,
                                    NULL, NULL, error);

  if (trust)
    trust_launcher (file);

  /* cleanup */
  g_free (data);

  if (result)
    {
      return file;
    }
  else
    {
      g_object_unref (file);
      return NULL;
    }
}
