/* Copyright (C) 2004 MySQL AB

   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.

   This program 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 General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */

#ifndef myx_grt_gc_h
#define myx_grt_gc_h

#include <myx_public_interface.h>
#ifdef __APPLE__
#include <MySQLGRT/myx_grt_public_interface.h>
#include <MySQLGRT/myx_grt_private.h>
#include "myx_grt_gc_public_interface.h"

#include <GenericCanvas/myx_gc_canvas.h>
#include <GenericCanvas/myx_gc_view.h>
#include <GenericCanvas/myx_gc_figure.h>
#include <GenericCanvas/myx_gc_model.h>
#else
#include <myx_grt_public_interface.h>
#include <myx_grt_private.h>
#include <myx_grt_gc_public_interface.h>

#include "myx_gc_canvas.h"
#include "myx_gc_view.h"
#include "myx_gc_figure.h"
#include "myx_gc_model.h"
#endif

#include <string>
using namespace std;

#define DBUG(msg) if (getenv("DEBUG_GRT_GC")) g_message("%s", msg)

#ifdef __cplusplus
extern "C" {
#endif

/*
 * Module Functions
 */

MYX_GRT_VALUE *grt_gc_init(MYX_GRT_VALUE *value, void *data);
MYX_GRT_VALUE *grt_gc_update(MYX_GRT_VALUE *value, void *data);
MYX_GRT_VALUE *grt_gc_value_from_grt(MYX_GRT_VALUE *value, void *data);
MYX_GRT_VALUE *grt_gc_value_to_grt(MYX_GRT_VALUE *value, void *data);
MYX_GRT_VALUE *grt_gc_delete(MYX_GRT_VALUE *value, void *data);

MYX_GRT_VALUE* grt_gc_addFigureInstance(MYX_GRT_VALUE *value, void *data);
MYX_GRT_VALUE* grt_gc_addLayer(MYX_GRT_VALUE *value, void *data);
MYX_GRT_VALUE* grt_gc_addLayoutsFromFile(MYX_GRT_VALUE *value, void *data);
MYX_GRT_VALUE* grt_gc_addStylesFromFile(MYX_GRT_VALUE *value, void *data);
MYX_GRT_VALUE* grt_gc_addToSelection(MYX_GRT_VALUE *value, void *data);
MYX_GRT_VALUE* grt_gc_beginUpdate(MYX_GRT_VALUE *value, void *data);
MYX_GRT_VALUE* grt_gc_checkError(MYX_GRT_VALUE *value, void *data);
MYX_GRT_VALUE* grt_gc_clearContent(MYX_GRT_VALUE *value, void *data);
MYX_GRT_VALUE* grt_gc_clearLayouts(MYX_GRT_VALUE *value, void *data);
MYX_GRT_VALUE* grt_gc_clearSelection(MYX_GRT_VALUE *value, void *data);
MYX_GRT_VALUE* grt_gc_clearStyles(MYX_GRT_VALUE *value, void *data);
MYX_GRT_VALUE* grt_gc_containsPoint(MYX_GRT_VALUE *value, void *data);
MYX_GRT_VALUE* grt_gc_createFigure(MYX_GRT_VALUE *value, void *data);
MYX_GRT_VALUE* grt_gc_createFigureInstance(MYX_GRT_VALUE *value, void *data);
MYX_GRT_VALUE* grt_gc_createLayer(MYX_GRT_VALUE *value, void *data);
MYX_GRT_VALUE* grt_gc_createView(MYX_GRT_VALUE *value, void *data);
MYX_GRT_VALUE* grt_gc_endUpdate(MYX_GRT_VALUE *value, void *data);
MYX_GRT_VALUE* grt_gc_getCurrentView(MYX_GRT_VALUE *value, void *data);
MYX_GRT_VALUE* grt_gc_grtFigureDelete(MYX_GRT_VALUE *value, void *data);
MYX_GRT_VALUE* grt_gc_grtFigureUpdate(MYX_GRT_VALUE *value, void *data);
MYX_GRT_VALUE* grt_gc_grtGetFigureCreator(MYX_GRT_VALUE *value, void *data);
MYX_GRT_VALUE* grt_gc_grtGetFigureElement(MYX_GRT_VALUE *value, void *data);
MYX_GRT_VALUE* grt_gc_grtToFigure(MYX_GRT_VALUE *value, void *data);
MYX_GRT_VALUE* grt_gc_layerByName(MYX_GRT_VALUE *value, void *data);
MYX_GRT_VALUE* grt_gc_refresh(MYX_GRT_VALUE *value, void *data);
MYX_GRT_VALUE* grt_gc_release(MYX_GRT_VALUE *value, void *data);
MYX_GRT_VALUE* grt_gc_removeFigureInstance(MYX_GRT_VALUE *value, void *data);
MYX_GRT_VALUE* grt_gc_removeFromSelection(MYX_GRT_VALUE *value, void *data);
MYX_GRT_VALUE* grt_gc_removeLayer(MYX_GRT_VALUE *value, void *data);
MYX_GRT_VALUE* grt_gc_removeView(MYX_GRT_VALUE *value, void *data);
MYX_GRT_VALUE* grt_gc_setCurrentView(MYX_GRT_VALUE *value, void *data);
MYX_GRT_VALUE* grt_gc_showSelection(MYX_GRT_VALUE *value, void *data);
MYX_GRT_VALUE* grt_gc_viewByName(MYX_GRT_VALUE *value, void *data);

/*
 * Structs and Enums
 */

static MYX_GRT_BUILTIN_FUNCTION functions_grt_gc_bridge[]= {
  // Mandatory bridge functions.
  {"_initDict::", grt_gc_init},
  {"_update::",   grt_gc_update},
  {"_setValue::", grt_gc_value_from_grt},
  {"_getValue::", grt_gc_value_to_grt},
  {"_delValue::", grt_gc_delete},

  // Special support functions. For parameter description see function implementations.
  {"addFigureInstance::",    grt_gc_addFigureInstance}, 
  {"addLayer::",             grt_gc_addLayer}, 
  {"addLayoutsFromFile::",   grt_gc_addLayoutsFromFile}, 
  {"addStylesFromFile::",    grt_gc_addStylesFromFile}, 
  {"addToSelection::",       grt_gc_addToSelection}, 
  {"beginUpdate::",          grt_gc_beginUpdate}, 
  {"checkError::",           grt_gc_checkError}, 
  {"clearContent::",         grt_gc_clearContent}, 
  {"clearLayouts::",         grt_gc_clearLayouts}, 
  {"clearSelection::",       grt_gc_clearSelection}, 
  {"clearStyles::",          grt_gc_clearStyles}, 
  {"containsPoint::",        grt_gc_containsPoint}, 
  {"createFigure::",         grt_gc_createFigure}, 
  {"createFigureInstance::", grt_gc_createFigureInstance}, 
  {"createLayer::",          grt_gc_createLayer}, 
  {"createView::",           grt_gc_createView}, 
  {"endUpdate::",            grt_gc_endUpdate}, 
  {"getCurrentView::",       grt_gc_getCurrentView}, 
  {"grtFigureDelete::",      grt_gc_grtFigureDelete}, 
  {"grtFigureUpdate::",      grt_gc_grtFigureUpdate}, 
  {"grtGetFigureCreator::",  grt_gc_grtGetFigureCreator}, 
  {"grtGetFigureElement::",  grt_gc_grtGetFigureElement}, 
  {"grtToFigure::",          grt_gc_grtToFigure}, 
  {"layerByName::",          grt_gc_layerByName}, 
  {"refresh::",              grt_gc_refresh}, 
  {"release::",              grt_gc_release}, 
  {"removeFigureInstance::", grt_gc_removeFigureInstance}, 
  {"removeFromSelection::",  grt_gc_removeFromSelection}, 
  {"removeLayer::",          grt_gc_removeLayer}, 
  {"removeView::",           grt_gc_removeView}, 
  {"setCurrentView::",       grt_gc_setCurrentView}, 
  {"showSelection::",        grt_gc_showSelection}, 
  {"viewByName::",           grt_gc_viewByName}
};

static MYX_GRT_BUILTIN_MODULE grt_module_grt_gc= {
  "GenericCanvas",
  NULL,
  sizeof(functions_grt_gc_bridge) / sizeof(MYX_GRT_BUILTIN_FUNCTION),
  functions_grt_gc_bridge
};

#ifdef __cplusplus
}
#endif

//----------------------------------------------------------------------------------------------------------------------

/** Mapper for id <-> object lookups. */
typedef hash_map<string, CGCBase*> CIdGcMapper;
typedef hash_map<CGCBase*, string> CGcIdMapper;

/** Mapper to find GRT values associated with a GC object. */
typedef map<CGCBase*, MYX_GRT_VALUE*> CGcGrtMapper;

class CGrtToGcBridge;

class CGcObjectListener: public CGCListener
{
  friend class CGrtToGcBridge;
protected:
  CGrtToGcBridge* bridge;
public:
  virtual void __cdecl onChange(CGCBase* sender, CGCBase* origin, TGCChangeReason reason);
  virtual void __cdecl onDestroy(CGCBase* sender);
  virtual void __cdecl onError(CGCBase* sender, CGCBase* origin, const char* message);
};

static string emptyString("");

/**
 * The GRT-to-GC bridge is a helper class to connect the runtime with one or more generic canvases.
 */
class CGrtToGcBridge
{
  friend class CGcObjectListener;
private:
  MYX_GRT* FRuntime;
  MYX_GRT_MODULE* FModule;
  CGcGrtMapper FGcToGrtMapper;         // Back mapping from GC to GRT. This maps GRT values that represent GC objects 
                                       // in the GRT.
  CGcGrtMapper FCreatorMapper;         // Back mapping from GC to GRT. This maps GRT values which have been converted
                                       // to GC objects (see grtToFigure and grtFigureUpdate).
  CGcIdMapper FGcToIdMapper;           // Mapping a GC object to an id.
  int FUpdateCount;
  CGcObjectListener FListener;         // A listener to events happening in the generic canvas.
  string FLastError;
protected:
  void addIdMapping(const string& id, CGCBase* object);
  void convertDict(MYX_GRT_VALUE* dict, CFigure* figure);
  void deleteFigures(MYX_GRT_VALUE* value);
  void fillDictElement(CFigureElement* element, MYX_GRT_VALUE* source, wstring path);
  void fillListElement(CFigureElement* element, MYX_GRT_VALUE* source, wstring path);
  MYX_GRT_VALUE* generateError(string message, string details);
  MYX_GRT_VALUE* generateResult(MYX_GRT_VALUE* value);
  CGenericCanvas* getCanvasFromParameter(MYX_GRT_VALUE* parameter);
  double getFloatFromParameter(MYX_GRT_VALUE* parameter, unsigned int index);
  MYX_GRT_VALUE* getValueFromParameter(MYX_GRT_VALUE* parameter, unsigned int index);
  int getIntFromParameter(MYX_GRT_VALUE* parameter, unsigned int index);
  CGCBase* getObjectFromParameter(MYX_GRT_VALUE* parameter, unsigned int index);
  MYX_GRT_VALUE* getOrCreateDict(CGCBase* object, const char* structName);
  const char* getStringFromParameter(MYX_GRT_VALUE* parameter, unsigned int index);
  CGCBase* getGcObjectFromId(const string& id);
  MYX_GRT_VALUE* getGrtValue(CGCBase* object);
  string& getId(CGCBase* object);
  void removeIdMapping(CGCBase* object);
  void updateFigure(CGenericCanvas* canvas, CFigure* oldFigure, MYX_GRT_VALUE* source, const char* layoutClass); 
public:
  CGrtToGcBridge(MYX_GRT* runtime);
  virtual ~CGrtToGcBridge(void);

  void addMapping(MYX_GRT_VALUE* value, CGCBase* object);
  bool deleteObject(MYX_GRT_VALUE* value);
  void freeNotification(CGCBase* object);
  bool initObject(MYX_GRT_VALUE* value);
  void module(MYX_GRT_MODULE* module);
  MYX_GRT_MODULE* module(void) { return FModule; };
  void notification(MYX_GRT_VALUE* value, MYX_GRT_VALUE_CALLBACK_REASON reason);
  void onError(CGCBase* object, string message);
  bool removeMapping(CGCBase* object);
  bool updateObject(MYX_GRT_VALUE* value);
  bool updateValue(MYX_GRT_VALUE* value);
  bool writeValue(MYX_GRT_VALUE* value);

  // Special bridge functions.
  MYX_GRT_VALUE* addFigureInstance(MYX_GRT_VALUE *value);
  MYX_GRT_VALUE* addLayer(MYX_GRT_VALUE *value);
  MYX_GRT_VALUE* addLayoutsFromFile(MYX_GRT_VALUE *value);
  MYX_GRT_VALUE* addStylesFromFile(MYX_GRT_VALUE *value);
  MYX_GRT_VALUE* addToSelection(MYX_GRT_VALUE *value);
  MYX_GRT_VALUE* beginUpdate(MYX_GRT_VALUE *value);
  MYX_GRT_VALUE* checkError(MYX_GRT_VALUE *value);
  MYX_GRT_VALUE* clearContent(MYX_GRT_VALUE *value);
  MYX_GRT_VALUE* clearLayouts(MYX_GRT_VALUE *value);
  MYX_GRT_VALUE* clearSelection(MYX_GRT_VALUE *value);
  MYX_GRT_VALUE* clearStyles(MYX_GRT_VALUE *value);
  MYX_GRT_VALUE* containsPoint(MYX_GRT_VALUE *value);
  MYX_GRT_VALUE* createFigure(MYX_GRT_VALUE *value);
  MYX_GRT_VALUE* createFigureInstance(MYX_GRT_VALUE *value);
  MYX_GRT_VALUE* createLayer(MYX_GRT_VALUE *value);
  MYX_GRT_VALUE* createView(MYX_GRT_VALUE *value);
  MYX_GRT_VALUE* endUpdate(MYX_GRT_VALUE *value);
  MYX_GRT_VALUE* getCurrentView(MYX_GRT_VALUE *value);
  MYX_GRT_VALUE* grtFigureDelete(MYX_GRT_VALUE *value);
  MYX_GRT_VALUE* grtFigureUpdate(MYX_GRT_VALUE *value);
  MYX_GRT_VALUE* grtGetFigureCreator(MYX_GRT_VALUE *value);
  MYX_GRT_VALUE* grtGetFigureElement(MYX_GRT_VALUE *value);
  MYX_GRT_VALUE* grtToFigure(MYX_GRT_VALUE *value);
  MYX_GRT_VALUE* layerByName(MYX_GRT_VALUE *value);
  MYX_GRT_VALUE* refresh(MYX_GRT_VALUE *value);
  MYX_GRT_VALUE* release(MYX_GRT_VALUE *value);
  MYX_GRT_VALUE* removeFigureInstance(MYX_GRT_VALUE *value);
  MYX_GRT_VALUE* removeFromSelection(MYX_GRT_VALUE *value);
  MYX_GRT_VALUE* removeLayer(MYX_GRT_VALUE *value);
  MYX_GRT_VALUE* removeView(MYX_GRT_VALUE *value);
  MYX_GRT_VALUE* setCurrentView(MYX_GRT_VALUE *value);
  MYX_GRT_VALUE* showSelection(MYX_GRT_VALUE *value);
  MYX_GRT_VALUE* viewByName(MYX_GRT_VALUE *value);
};

//----------------------------------------------------------------------------------------------------------------------

#endif
