/* Copyright (C) 2005 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 */

#include "MGCanvas.h"

#include "myx_gc_figure.h"

#include <gdkmm.h>
#include <gdk/gdkx.h>

// scroller support
// correct zooming
// font and sys-color support

static bool init_canvas()
{
 // TColorMap colormap;
/*  
  {"ActiveBorder",        0},  // Active window border. 
  {"ActiveCaption",       0},  // Active window caption. 
  {"AppWorkspace",        0},  // Background color of multiple document interface. 
  {"Background",          0},  // Desktop background. 
  {"ButtonFace",          0},  // Face color for three-dimensional display elements. 
  {"ButtonHighlight",     0},  // Dark shadow for three-dimensional display elements (for edges facing away from the light source). 
  {"ButtonShadow",        0},  // Shadow color for three-dimensional display elements. 
  {"ButtonText",          0},  // Text on push buttons. 
  {"CaptionText",         0},  // Text in caption, size box, and scrollbar arrow box. 
  {"GrayText",            0},  // Grayed (disabled) text. This color is set to #000 if the current display driver does not support a solid gray color. 
  {"Highlight",           0},  // Item(s) selected in a control. 
  {"HighlightText",       0},  // Text of item(s) selected in a control. 
  {"Hotlight",            0},  // Hot tracked item.
  {"InactiveBorder",      0},  // Inactive window border. 
  {"InactiveCaption",     0},  // Inactive window caption. 
  {"InactiveCaptionText", 0},  // Color of text in an inactive caption. 
  {"InfoBackground",      0},  // Background color for tooltip controls. 
  {"InfoText",            0},  // Text color for tooltip controls. 
  {"Menu",                0},  // Menu background. 
  {"MenuText",            0},  // Text in menus. 
  {"Scrollbar",           0},  // Scroll bar gray area. 
  {"ThreeDDarkShadow",    0},  // Dark shadow for three-dimensional display elements. 
  {"ThreeDFace",          0},  // Face color for three-dimensional display elements. 
  {"ThreeDHighlight",     0},  // Highlight color for three-dimensional display elements. 
  {"ThreeDLightShadow",   0},  // Light color for three-dimensional display elements (for edges facing the light source). 
  {"ThreeDShadow",        0},  // Dark shadow for three-dimensional display elements. 
  {"Window",              0},  // Window background. 
  {"WindowFrame",         0},  // Window frame.
  {"WindowText",          0}   // Text in windows.
 */
  
  return true;
}


MGCanvas::MGCanvas()
  : Gtk::DrawingArea(), _context(0), _canvas(0)
{
  add_events(Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::BUTTON_MOTION_MASK|
             Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK|Gdk::POINTER_MOTION_MASK);

  set_double_buffered(false);

  _cursors.resize(10);
  _cursors[0]= 0;
  _cursors[1]= 0;
  _cursors[2]= new Gdk::Cursor(Gdk::TOP_SIDE);
  _cursors[3]= new Gdk::Cursor(Gdk::TOP_RIGHT_CORNER);
  _cursors[4]= new Gdk::Cursor(Gdk::RIGHT_SIDE);
  _cursors[5]= new Gdk::Cursor(Gdk::BOTTOM_RIGHT_CORNER);
  _cursors[6]= new Gdk::Cursor(Gdk::BOTTOM_SIDE);
  _cursors[7]= new Gdk::Cursor(Gdk::BOTTOM_LEFT_CORNER);
  _cursors[8]= new Gdk::Cursor(Gdk::LEFT_SIDE);
  _cursors[9]= new Gdk::Cursor(Gdk::TOP_LEFT_CORNER);

  _offsetX= 0.0;
  _offsetY= 0.0;
  _zoom= 1.0;
}


MGCanvas::~MGCanvas()
{ 
  if (_context)
    glXDestroyContext(gdk_display, _context);
  
  for (unsigned int i= 0; i < _cursors.size(); i++)
    delete _cursors[i];
  
  delete _canvas;
}


bool MGCanvas::on_configure_event(GdkEventConfigure* event)
{
  Gtk::DrawingArea::on_configure_event(event);
  
  if (_canvas)
  {
    CGCView *view= _canvas->currentView();
    TGCViewport viewport(0, 0, event->width, event->height);
    
    view->viewport(viewport);
  }
  
  return true;
}


void MGCanvas::on_realize()
{
  XVisualInfo *visinfo;
  int attrib[] = { 
    GLX_RGBA,
      GLX_RED_SIZE, 1,
      GLX_GREEN_SIZE, 1,
      GLX_BLUE_SIZE, 1,
      GLX_DOUBLEBUFFER,
      GLX_DEPTH_SIZE, 1,
      None 
  };
  
  Gtk::DrawingArea::on_realize();
  
  visinfo = glXChooseVisual(gdk_display,
                            gdk_x11_screen_get_screen_number(Gdk::Screen::get_default()->gobj()),
                            attrib);
  if (!visinfo) {
    g_warning("could not get visual for OpenGL");
    return;
  }

  _context= glXCreateContext(gdk_display, visinfo, NULL, True);
  if (!_context) 
  {
    g_warning("Could not initialize GLX context");
    XFree(visinfo);
  }
  XFree(visinfo);
  
  glXMakeCurrent(gdk_display, gdk_x11_drawable_get_xid(get_window()->gobj()), _context);
  
  
  _canvas= new CGenericCanvas(_context, "");
  _canvas->addListener(this);
  
  CGCView *view= _canvas->createView("main");
  _canvas->currentView(view);

  view->viewport(TGCViewport(0, 0, get_allocation().width, get_allocation().height));
  view->color(1.0, 1.0, 1.0, 1.0);

  update_viewport();
}


bool MGCanvas::on_expose_event(GdkEventExpose* event)
{
  if (event->count == 0)
  {
    _canvas->render();
    
    glXSwapBuffers(gdk_display, gdk_x11_drawable_get_xid(get_window()->gobj()));
  }
  return true;
}


bool MGCanvas::on_button_press_event(GdkEventButton* event)
{
  CHitResults *hits;
  
  if (event->state == 0)
    _canvas->clearSelection();

  _clickX= event->x;
  _clickY= event->y;
  
  hits= _canvas->currentView()->getHitTestInfoAt((int)event->x, (int)event->y);
  while (hits->hasNext())
  {
    CFigureInstance *entry= hits->next();

    if (event->state & GDK_SHIFT_MASK)
    { // invert selection
      if (entry->instance->selected())
        _canvas->removeFromSelection(entry->instance);
      else
        _canvas->addToSelection(entry->instance);
    }
    else if (event->state & GDK_CONTROL_MASK)
      _canvas->addToSelection(entry->instance);
  }

  hits->release();

  return true;
}

  
bool MGCanvas::on_button_release_event(GdkEventButton* event)
{  
  return true;
}


bool MGCanvas::on_motion_notify_event(GdkEventMotion* event)
{
  if ((event->state & GDK_BUTTON2_MASK) == GDK_BUTTON2_MASK)
  {
    double dx= event->x - _clickX;
    double dy= event->y - _clickY;
    
    _clickX= event->x;
    _clickY= event->y;
    
    _offsetX += dx;
    _offsetY -= dy;
    
    update_viewport();
  }
  else
  {
    TGCDirection sinfo= _canvas->getSelectionInfo((int)event->x, (int)event->y);
    if (sinfo != _ocursorType)
    {
      switch (sinfo)
      {
      case GC_SI_NONE:
        get_window()->set_cursor();
        break;
      case GC_SI_ON_OBJECT:
        get_window()->set_cursor();
        break;
      default:
        get_window()->set_cursor(*_cursors[(int)sinfo]);
        break;
      }
    }
    _ocursorType= sinfo;
  }
    
  
  return true;
}


bool MGCanvas::on_scroll_event(GdkEventScroll* event)
{
  bool moved= false;
  
  if (event->state == 0)
  {
    switch (event->direction)
    {
    case GDK_SCROLL_UP:
      _offsetY-=10.0*_zoom;
      moved= true;
      break;
    case GDK_SCROLL_DOWN:
      _offsetY+=10.0*_zoom;
      moved= true;
      break;
    case GDK_SCROLL_LEFT:
      _offsetX-=10.0*_zoom;
      moved= true;
      break;
    case GDK_SCROLL_RIGHT:
      _offsetX+=10.0*_zoom;
      moved= true;
      break;
    }
  }
  else if ((event->state & GDK_CONTROL_MASK) == GDK_CONTROL_MASK)
  {
    if (event->direction == GDK_SCROLL_UP)
    {
      _offsetX-=10.0*_zoom;
      moved= true;
    }
    else if (event->direction == GDK_SCROLL_DOWN)
    {
      _offsetX+=10.0*_zoom;
      moved= true;
    }
  }
  else if ((event->state & GDK_SHIFT_MASK) == GDK_SHIFT_MASK)
  {
    double zoom_increment= 0.2;
    double swidth= get_allocation().width;
    double sheight= get_allocation().height;

    //calc stuff and do here

    if (event->direction == GDK_SCROLL_UP)
    {
      _zoom+= zoom_increment;

      moved= true;
    }
    else if (event->direction == GDK_SCROLL_DOWN)
    {
      _zoom-= zoom_increment;

      moved= true;
    }
    
    if (moved)
    {
      _offsetX= _offsetX + (event->x/swidth)*_zoom;
      _offsetY= _offsetY + (event->y/sheight)*_zoom;
    }
  }

  if (moved)
    update_viewport();

  return true;
}


void MGCanvas::onChange(void* AObject, TGCChangeReason Reason)
{
}


void MGCanvas::onError(const char* Message)
{
  g_warning(Message);
}


void MGCanvas::onInvalidate(void)
{
  queue_draw();
}


bool MGCanvas::set_scroll_adjustments(Gtk::Adjustment& hadjustment,
                                      Gtk::Adjustment& vadjustment)
{
  g_message("set adj");
  
  return true;
}


void MGCanvas::update_viewport()
{
  if (_zoom < 0.0)
    _zoom= 0.1;
/*  
  if (_offsetX < 0.0)
    _offsetX= 0.0;
  if (_offsetY < 0.0)
    _offsetY= 0.0;
  */
  _canvas->currentView()->offsetX(_offsetX);
  _canvas->currentView()->offsetY(_offsetY);
  _canvas->currentView()->zoomX(_zoom);
  _canvas->currentView()->zoomY(_zoom);
}
