/*
 * AT-SPI - Assistive Technology Service Provider Interface
 * (Gnome Accessibility Project; http://developer.gnome.org/projects/gap)
 *
 * Copyright 2013 SUSE LLC.
 * Copyright 2001, 2002 Sun Microsystems Inc.,
 * Copyright 2001, 2002 Ximian, Inc.
 *
 * 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 Library General Public
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 */

#include <atk/atk.h>
#include <droute/droute.h>

#include "spi-dbus.h"
#include "object.h"
#include "introspection.h"

static dbus_bool_t
impl_get_ColumnSpan (DBusMessageIter * iter, void *user_data)
{
  AtkTableCell *cell = (AtkTableCell *) user_data;
  g_return_val_if_fail (ATK_IS_TABLE_CELL (user_data), FALSE);
  return droute_return_v_int32 (iter, atk_table_cell_get_column_span (cell));
}

static DBusMessage *
message_from_object_array (DBusMessage *message, GPtrArray *array)
{
  DBusMessage *reply;
  DBusMessageIter iter, iter_array;
  gint len;
  gint i;

  reply = dbus_message_new_method_return (message);
  if (!reply)
    return NULL;

  dbus_message_iter_init_append (reply, &iter);

  if (!dbus_message_iter_open_container
      (&iter, DBUS_TYPE_ARRAY, "(so)", &iter_array))
    return reply; /* TODO: handle out of memory */
  len = (array? array->len: 0);
  for (i = 0; i < len; i++)
  {
    spi_object_append_reference (&iter_array, g_ptr_array_index (array, i));
  }
  dbus_message_iter_close_container (&iter, &iter_array);
  g_ptr_array_unref (array);
  return message;
}

static DBusMessage *
impl_GetColumnHeaderCells (DBusConnection * bus, DBusMessage * message,
                        void *user_data)
{
  AtkTableCell *cell = user_data;
  GPtrArray *array;

  g_return_val_if_fail (ATK_IS_TABLE_CELL (user_data),
                        droute_not_yet_handled_error (message));

  array = atk_table_cell_get_column_header_cells (cell);
  return message_from_object_array (message, array);
}

static dbus_bool_t
impl_get_RowSpan (DBusMessageIter * iter, void *user_data)
{
  AtkTableCell *cell = (AtkTableCell *) user_data;
  g_return_val_if_fail (ATK_IS_TABLE_CELL (user_data), FALSE);
  return droute_return_v_int32 (iter, atk_table_cell_get_row_span (cell));
}

static DBusMessage *
impl_GetRowHeaderCells (DBusConnection * bus, DBusMessage * message,
                        void *user_data)
{
  AtkTableCell *cell = user_data;
  GPtrArray *array;

  g_return_val_if_fail (ATK_IS_TABLE_CELL (user_data),
                        droute_not_yet_handled_error (message));

  array = atk_table_cell_get_row_header_cells (cell);
  return message_from_object_array (message, array);
}

static dbus_bool_t
impl_get_Position (DBusMessageIter * iter, void *user_data)
{
  AtkTableCell *cell = (AtkTableCell *) user_data;
  gint row = -1, column = -1;
  dbus_int32_t d_row, d_column;
  DBusMessageIter iter_struct, iter_variant;

  g_return_val_if_fail (ATK_IS_TABLE_CELL (user_data), FALSE);
  if (!atk_table_cell_get_position (cell, &row, &column))
    return FALSE;

  d_row = row;
  d_column = column;
  dbus_message_iter_open_container (iter, DBUS_TYPE_STRUCT, "(ii)", &iter_variant);
  dbus_message_iter_open_container (&iter_struct, DBUS_TYPE_STRUCT, NULL, &iter_struct);
  dbus_message_iter_append_basic (&iter_struct, DBUS_TYPE_INT32, &row);
  dbus_message_iter_append_basic (&iter_struct, DBUS_TYPE_INT32, &column);
  dbus_message_iter_close_container (&iter_variant, &iter_struct);
  dbus_message_iter_close_container (iter, &iter_variant);
  return TRUE;
}

static dbus_bool_t
impl_get_Table (DBusMessageIter * iter, void *user_data)
{
  AtkTableCell *cell = (AtkTableCell *) user_data;
  AtkObject *table;

  g_return_val_if_fail (ATK_IS_TABLE_CELL (user_data), FALSE);

  table = atk_table_cell_get_table (cell);
  if (!table)
    return FALSE;
  spi_object_append_reference (iter, table);
  return TRUE;
}

static DBusMessage *
impl_GetRowColumnSpan (DBusConnection * bus, DBusMessage * message,
                          void *user_data)
{
  AtkTableCell *cell = (AtkTableCell *) user_data;
  gint row, column, row_span, column_span;
  dbus_int32_t d_row, d_column, d_row_span, d_column_span;
  DBusMessage *reply;

  g_return_val_if_fail (ATK_IS_TABLE (user_data),
                        droute_not_yet_handled_error (message));
  atk_table_cell_get_row_column_span (cell, &row, &column, &row_span,
                                         &column_span);
  d_row = row;
  d_column = column;
  d_row_span = row_span;
  d_column_span = column_span;
  reply = dbus_message_new_method_return (message);
  if (reply)
    {
      dbus_message_append_args (reply, DBUS_TYPE_INT32, &d_row, DBUS_TYPE_INT32,
                                &d_column, DBUS_TYPE_INT32, &d_row_span,
                                DBUS_TYPE_INT32, &d_column_span,
                                DBUS_TYPE_INVALID);
    }
  return reply;
}

static DRouteMethod methods[] = {
  {impl_GetRowHeaderCells, "GetRowHeaderCells"},
  {impl_GetColumnHeaderCells, "GetColumnHeaderCells"},
  {impl_GetRowColumnSpan, "GetRowColumnSpan"},
  {NULL, NULL}
};

static DRouteProperty properties[] = {
  {impl_get_ColumnSpan, NULL, "ColumnSpan"},
  {impl_get_Position, NULL, "Position"},
  {impl_get_RowSpan, NULL, "RowSpan"},
  {impl_get_Table, NULL, "Table"},
  {NULL, NULL, NULL}
};

void
spi_initialize_table_cell (DRoutePath * path)
{
  droute_path_add_interface (path,
                             ATSPI_DBUS_INTERFACE_TABLE_CELL,
                             spi_org_a11y_atspi_TableCell,
                             methods, properties);
};
