/*
    Copyright (C) 1998 by Jorrit Tyberghein
    Written by Brandon Ehle

    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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

#ifndef __CS_CSPYTHON_H__
#define __CS_CSPYTHON_H__

#include <Python.h>

#include "ivaria/script.h"
#include "iutil/eventh.h"
#include "iutil/comp.h"
#include "csutil/csinput.h"  
#include <csutil/hash.h>


class csPyValue : public iScriptValue
{
public:
  csPyValue();
  csPyValue(PyObject* value);
  csPyValue(long value);
  csPyValue(double value);
  csPyValue(bool value);
  csPyValue(const char* value);
  csPyValue(iScriptObject* value);
  virtual ~csPyValue();
  PyObject* val;

  /// Returns a bitmask indicating which types this value can be coerced into.
  virtual unsigned GetTypes () const; // {unsigned u; return u;}

  /// Returns this value as an int.
  virtual int GetInt () const; //{int i; return i;}
  
  /// Returns this value as a long.
  virtual long GetLong () const;

  /// Returns this value as a float.
  virtual float GetFloat () const; //{float f; return f;}

  /// Returns this value as a double.
  virtual double GetDouble () const; //{double d; return d;}

  /// Returns this value as a string.
  virtual const char* GetString () const; //{const char* c; return c;}

  /// Returns this value as a bool.
  virtual bool GetBool () const; //{return false;}

  /// Returns this value as a script object.
  virtual csPtr<iScriptObject> GetObject () const;// {csRef<iScriptObject> s; return s;}
  
  virtual void* GetLiteral() const;
  
  virtual void SetLiteral(void* value);
  
  SCF_DECLARE_IBASE;
};

class csPyModule : public iScriptObject
{
public:
  csPyModule();
  csPyModule(PyObject *mod);
  virtual ~csPyModule();
  
  PyObject* module;
  
  virtual void* GetLiteral() {return (void*)module;}
  //not implemented:
  virtual csPtr<iScriptValue> Call (const char *name, const csRefArray<iScriptValue> &args = csRefArray<iScriptValue> ()) {iScriptValue* i; return i;};

  virtual bool Set (const char *name, csRef<iScriptValue> value) {return false;}

  virtual csPtr<iScriptValue> Get (const char *name) {iScriptValue* i; return i;}
  
  virtual bool SetPointer (iBase *) {return false;}
  virtual bool IsType (const char *) const {return false;}
  virtual iBase* GetPointer () const {iBase* b; return b;}
  
  //////////////
  //BELOW IS USELESS
  //////////////
#if 1  
  virtual bool Call (const char *name, const char *format, ...)
    CS_GNUC_PRINTF(3, 4) {return false;}
  virtual bool Call (const char *name, int &ret, const char *fmt, ...)
    CS_GNUC_PRINTF(4, 5) {return false;}
  virtual bool Call (const char *name, float &ret, const char *fmt, ...)
    CS_GNUC_PRINTF(4, 5) {return false;}
  virtual bool Call (const char *name, double &ret, const char *fmt, ...)
    CS_GNUC_PRINTF(4, 5) {return false;}
  virtual bool Call (const char *name, csRef<iString>&, const char *fmt, ...)
    CS_GNUC_PRINTF(4, 5) {return false;}
  virtual bool Call (const char *name, csRef<iScriptObject>&,
    const char *fmt, ...) CS_GNUC_PRINTF(4, 5) {return false;}
  virtual bool Set (const char *name, int data) {return false;}
  virtual bool Set (const char *name, float data) {return false;}
  virtual bool Set (const char *name, double data) {return false;}
  virtual bool Set (const char *name, char const *data) {return false;}
  virtual bool Set (const char *name, iScriptObject *data) {return false;}
  virtual bool SetTruth (const char *name, bool isTrue) {return false;}
  virtual bool Get (const char *name, int &data) const {return false;}
  virtual bool Get (const char *name, float &data) const {return false;}
  virtual bool Get (const char *name, double &data) const {return false;}
  virtual bool Get (const char *name, csRef<iString>&) const {return false;}
  virtual bool Get (const char *name, csRef<iScriptObject>&) const {return false;}
  virtual bool GetTruth (const char *name, bool &isTrue) const {return false;}
#endif //commented out lines
  SCF_DECLARE_IBASE;
};

  

class csPyObject : public iScriptObject
{
public:
  csPyObject();
  virtual ~csPyObject();
  PyObject* object;
  SCF_DECLARE_IBASE;
};

class csPython : public iScript
{
  //This function is to store the __main__ module in LoadedModules.
  //This is not done through LoadModule, because LoadModule adds
  //a module to __main__. This was previously done through RunText,
  //but that did not allow the loaded module to be tracked.
  virtual bool LoadMain();
  
public:
  csPython(iBase *iParent);
  virtual ~csPython();

  static csPython* shared_instance;
  iObjectRegistry* object_reg;
  int Mode;
  bool use_debugger;

  csHash<csPyModule*,csString> LoadedModules;
  PyObject* main_mod;

  virtual bool Initialize(iObjectRegistry* object_reg);
  virtual bool HandleEvent(iEvent&);
  virtual bool RunText(const char *Text);
  virtual bool LoadModule(const char *Text);
  virtual bool Store (const char *name, csRef<iScriptValue> value); //{return false;}
  virtual csPtr<iScriptValue> Retrieve (const char *name); //{iScriptValue * i; return i;}

  virtual csPtr<iScriptObject> GetModule(const char *name) {iScriptObject*n; return n; }

  /*
    @@@ New functions not yet implemented
  */
  virtual csPtr<iScriptValue> Call(const char *name, const csRefArray<iScriptValue> &args = csRefArray<iScriptValue> ());
  
  virtual csPtr<iScriptValue> RValue (int value);
  virtual csPtr<iScriptValue> RValue (long value);
  virtual csPtr<iScriptValue> RValue (float value);
  virtual csPtr<iScriptValue> RValue (double value);
  virtual csPtr<iScriptValue> RValue (const char *value);
  virtual csPtr<iScriptValue> RValue (bool value);
  virtual csPtr<iScriptValue> RValue (csRef<iScriptObject> value);
  
  virtual csPtr<iScriptObject> New (const char *type,
    const csRefArray<iScriptValue> &args = csRefArray<iScriptValue> ());

#if 1  
  //////////////
  //BELOW IS USELESS / DEPRECATED
  //////////////
  virtual bool Store(const char* name, void* data, void* tag);
  virtual bool Call(const char *name, const char *fmt, ...);
    //{ return false; }
  virtual bool Call(const char *name, int &ret, const char *fmt, ...)
    { return false; }
  virtual bool Call(const char *name, float &ret, const char *fmt, ...)
    { return false; }
  virtual bool Call(const char *name, double &ret, const char *fmt, ...)
    { return false; }
  virtual bool Call(const char *name, csRef<iString> &ref,
    const char *fmt, ...)
    { return false; }
  virtual bool Call(const char *name, csRef<iScriptObject> &ref,
    const char *fmt, ...)
    { return false; }
  virtual csPtr<iScriptObject> NewObject(const char *type,
    const char *fmt, ...)
    { return 0; }
  virtual bool Store(const char *name, int data)
    { return false; }
  virtual bool Store(const char *name, float data)
    { return false; }
  virtual bool Store(const char *name, double data)
    { return false; }
  virtual bool Store(const char *name, char const *data)
    { return false; }
  virtual bool Store(const char *name, iScriptObject *data)
    { return false; }
  virtual bool SetTruth(const char *name, bool data)
    { return false; }
  virtual bool Retrieve(const char *name, int &data) const
    { return false; }
  virtual bool Retrieve(const char *name, float &data) const
    { return false; }
  virtual bool Retrieve(const char *name, double &data) const
    { return false; }
  virtual bool Retrieve(const char *name, csRef<iString> &data) const
    { return false; }
  virtual bool Retrieve(const char *name, csRef<iScriptObject> &data) const
    { return false; }
  virtual bool GetTruth(const char *name, bool &data) const
    { return false; }

#endif //commented out lines
  virtual bool Remove(const char *name)
    { return false; }
  void ShowError();
  void Print(bool Error, const char *msg);

  SCF_DECLARE_IBASE;

  // Implement iComponent interface.
  struct eiComponent : public iComponent
  {
    SCF_DECLARE_EMBEDDED_IBASE(csPython);
    virtual bool Initialize (iObjectRegistry* p)
    { return scfParent->Initialize(p); }
  } scfiComponent;

  // Implement iEventHandler interface.
  struct eiEventHandler : public iEventHandler
  {
    SCF_DECLARE_EMBEDDED_IBASE(csPython);
    virtual bool HandleEvent (iEvent& e) { return scfParent->HandleEvent(e); }
    CS_EVENTHANDLER_NAMES("crystalspace.cspython")
    CS_EVENTHANDLER_NIL_CONSTRAINTS
  } scfiEventHandler;
};

#endif // __CS_CSPYTHON_H__
