/***************************************************************************
 *   Copyright (C) 2003 by Julian Rockey                                   *
 *   linux@jrockey.com                                                     *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 ***************************************************************************/

#include "marshaller.h"

#include "pcop.h"
#include "importedmodules.h"

#include <qdatastream.h>

#include <qrect.h>
#include <qfont.h>
#include <qcolor.h>
#include <qpointarray.h>
#include <qdatetime.h>
#include <dcopref.h>

#include <kurl.h>

#if PY_VERSION_HEX < 0x02050000
typedef int Py_ssize_t;
#endif

namespace PythonDCOP {

#include "marshal_funcs.h"

  Marshaller::Marshaller()
  {
    initFuncs();
  }

  Marshaller::~Marshaller()
  {
  }

  bool Marshaller::marsh_private(const PCOPType &type,
                                 PyObject *obj,
                                 QDataStream *str) const
  {

    QString ty = type.type();

    if (ty=="QStringList")
      return marshalList(PCOPType("QString"), obj, str);
    if (ty=="QCStringList")
      return marshalList(PCOPType("QCString"), obj, str);
    if (ty=="QValueList" && type.leftType())
      return marshalList(*type.leftType(), obj, str);
    if (ty=="QMap" && type.leftType() && type.rightType())
      return marshalDict(*type.leftType(), *type.rightType(), obj, str);

    if (!m_marsh_funcs.contains(ty)) return false;
    return m_marsh_funcs[ty](obj,str);
  }

  PyObject *Marshaller::demarsh_private(const PCOPType &type,
                                        QDataStream *str) const
  {
    QString ty = type.type();

    if (ty=="QStringList")
      return demarshalList(PCOPType("QString"), str);
    if (ty=="QCStringList")
      return demarshalList(PCOPType("QCString"), str);
    if (ty=="QValueList" && type.leftType())
      return demarshalList(*type.leftType(), str);
    if (ty=="QMap" && type.leftType() && type.rightType())
      return demarshalDict(*type.leftType(), *type.rightType(), str);

    if (!m_demarsh_funcs.contains(ty)) {
      Py_INCREF(Py_None);
      return Py_None;
    }

    PyObject *result = m_demarsh_funcs[ty](str);
    if (!result) {
      Py_INCREF(Py_None);
      return Py_None;
    }

    return result;
  }

  bool Marshaller::marshalList(const PCOPType &list_type,
                               PyObject *obj,
                               QDataStream *str) const {
    if (!PyList_Check(obj)) return false;

    int count = PyList_Size(obj);

    for(int c=0;c<count;c++)
      if (!list_type.isMarshallable( PyList_GetItem(obj,c) ) )
        return false;

    if (str) {
      (*str) << (Q_INT32)count;
      for(int c=0; c<count; c++)
        list_type.marshal( PyList_GetItem(obj,c), *str );
    }

    return true;
  }

  PyObject *Marshaller::demarshalList(const PCOPType &list_type,
                                      QDataStream *str) const {
    Q_UINT32 count;
    (*str) >> count;

    PyObject *obj = PyList_New(count);
    for(Q_UINT32 c=0;c<count;c++) {
      PyList_SetItem(obj, c, list_type.demarshal(*str));
    }
    return obj;
  }

  bool Marshaller::marshalDict(const PCOPType &key_type,
                               const PCOPType &value_type,
                               PyObject *obj,
                               QDataStream *str) const {
    if (!PyDict_Check(obj)) return false;


    Py_ssize_t c=0;
    PyObject *key, *val;
    while (PyDict_Next(obj, &c, &key, &val)==1)
      if (!key_type.isMarshallable(key) ||
          !value_type.isMarshallable(val))
        return false;

    if (str) {
      Q_INT32 count = (Q_INT32)PyDict_Size(obj);
      (*str) << count;
      c=0;
      while (PyDict_Next(obj, &c, &key, &val)==1) {
        key_type.marshal(key,*str);
        value_type.marshal(val,*str);
      }
    }
    return true;
  }

  PyObject *Marshaller::demarshalDict(const PCOPType &key_type,
                                      const PCOPType &value_type,
                                      QDataStream *str) const {
    PyObject *obj = PyDict_New();
    Q_INT32 count;
    (*str) >> count;
    for(Q_INT32 c=0;c<count;c++) {
      PyObject *key = key_type.demarshal(*str);
      PyObject *value = value_type.demarshal(*str);
      PyDict_SetItem(obj,key,value);
    }
    return obj;
  }


  Marshaller *Marshaller::m_instance = new Marshaller;


}

