/*
 GNU Maverik - a system for managing display and interaction in 
               Virtual Environment applications.
 Copyright (C) 1999 Advanced Interfaces Group

 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


 The authors can be contacted via:
 www   - http://aig.cs.man.ac.uk
 email - maverik@aig.cs.man.ac.uk
 mail  - Advanced Interfaces Group, Room 2.94, Computer Science Building, 
         University of Manchester, Manchester, M13 9PL, UK
*/


#include "mavlib_windows.h"
#include <stdlib.h>
#include <stdio.h>

MAV_callback *mav_callback_keyboard;
MAV_callback *mav_callback_sysKeyboard;



/* Wrapper routines to set and execute the keyboard callbacks */

void mav_callbackKeyboardSet(MAV_window *w, MAV_class *c, MAV_callbackKeyboardFn fn)
{
  mav_callbackSet(mav_callback_keyboard, w, c, (MAV_callbackFn) fn);
}

int mav_callbackKeyboardExec(MAV_window *w, MAV_object *o, MAV_keyboardEvent *ke)
{
  return (mav_callbackExec(mav_callback_keyboard, w, o, (void *) ke, NULL));
}

void mav_callbackSysKeyboardSet(MAV_window *w, MAV_class *c, MAV_callbackKeyboardFn fn)
{
  mav_callbackSet(mav_callback_sysKeyboard, w, c, (MAV_callbackFn) fn);
}

int mav_callbackSysKeyboardExec(MAV_window *w, MAV_object *o, MAV_keyboardEvent *ke)
{
  return (mav_callbackExec(mav_callback_sysKeyboard, w, o, (void *) ke, NULL));
}



/* Routines to implement functionality of reserved keystrokes */

void mavlib_sf1(void)
{
  if (mav_win_current->vmp) {
    mav_win_current->vmp->offset*=0.9;
    fprintf(stderr, "Offset %f\n", mav_win_current->vmp->offset);
  }
}

void mavlib_sf2(void)
{
  if (mav_win_current->vmp) {
    mav_win_current->vmp->offset*=0.99;
    fprintf(stderr, "Offset %f\n", mav_win_current->vmp->offset);
  }
}

void mavlib_sf3(void)
{
  if (mav_win_current->vmp) {
    mav_win_current->vmp->offset*=1.01;
    fprintf(stderr, "Offset %f\n", mav_win_current->vmp->offset);
  }
}

void mavlib_sf4(void)
{
  if (mav_win_current->vmp) {
    mav_win_current->vmp->offset*=1.1;
    fprintf(stderr, "Offset %f\n", mav_win_current->vmp->offset);
  }
}

void mavlib_sf5(void)
{
  MAV_viewModifierFn fn;

  if (mav_opt_stereo) {
    fn= mav_win_left->mod;
    mav_win_left->mod= mav_win_right->mod;
    mav_win_right->mod= fn;
    fprintf (stderr, "Windows swapped\n");
  }
}

float mavlib_offsetbackup=0.0;

void mavlib_sf6(void)
{
  if (mav_win_current->vmp) {
    if (mav_win_current->vmp->offset==0.0)
    {
      mav_win_current->vmp->offset=mavlib_offsetbackup;
    }
    else
    {
      mavlib_offsetbackup=mav_win_current->vmp->offset;
      mav_win_current->vmp->offset=0.0;
    }
    
    fprintf(stderr, "Offset %f\n", mav_win_current->vmp->offset);
  }
}

void mavlib_sf7(void)
{
  mav_viewParamsPrint("current view parameters:\n", *mav_win_current->vp);
}

int mavlib_filledorwire=1;

void mavlib_sf8(void)
{
  mavlib_filledorwire=!mavlib_filledorwire;
  mav_windowPolygonModeSet(mav_win_all, mavlib_filledorwire);
}

int mavlib_multiSample=1;

void mavlib_sf9(void)
{
  if (mav_opt_multiSample)
  {
    mavlib_multiSample=!mavlib_multiSample;
    mav_gfxMultiSampleSet(mavlib_multiSample);
    fprintf(stderr, "multisample %i\n", mavlib_multiSample);
  }
  else
  {
    if (mav_opt_output==MAV_VERBOSE) fprintf(stderr, "multisample option not selected\n");
  }
}

int mavlib_drawMouse=0;

void mavlib_sf10(void)
{
  mavlib_drawMouse=!mavlib_drawMouse;

  if (mavlib_drawMouse)
  {
    fprintf(stderr, "Drawing mouse\n");
    mav_frameFn2Add(mav_mouseDraw);
    mav_needFrameDraw++;
  }
  else
  {
    fprintf(stderr, "Not drawing mouse\n");
    mav_frameFn2Rmv(mav_mouseDraw);
    mav_needFrameDraw--;
    mav_drawingMouse=MAV_FALSE;
  }
}

int mavlib_snapcnt=0;

void mavlib_sf11(void)
{
  char fn[100];
  sprintf(fn, "snap%i.ppm", mavlib_snapcnt);
  mav_windowDump(mav_win_mouse, fn);
  mavlib_snapcnt++;
}

void mavlib_sf12(void)
{
  int i, rb, gb, bb, db, doub, ar, ag, ab;

  fprintf(stderr, "\n\n");
  mav_moduleDump();
  if (mav_win_current->vmp) {
    fprintf(stderr, "Shift-F1 decrease stereo offset by 10%%\n");
    fprintf(stderr, "Shift-F2 decrease stereo offset by 1%%\n");
    fprintf(stderr, "Shift-F3 increase stereo offset by 1%%\n");
    fprintf(stderr, "Shift-F4 increase stereo offset by 10%%\n");
    fprintf(stderr, "Shift-F5 swap windows\n");
    fprintf(stderr, "Shift-F6 toggle stereo offset between value and 0\n");
  }
  fprintf(stderr, "Shift-F7 print viewing parameters\n");
  fprintf(stderr, "Shift-F8 toggle wireframe/filled\n");
  fprintf(stderr, "Shift-F9 toggle multisample (where applicable)\n");
  fprintf(stderr, "Shift-F10 toggle drawing mouse at world coordinates\n");
  fprintf(stderr, "Shift-F11 dump the window the mouse is in as snap[n].ppm\n");
  fprintf(stderr, "Shift-F12 info\n");
  fprintf(stderr, "Shift-Esc quit\n");
  
  for (i=0; i<15; i++) if (mav_ctrlF_desc[i]) fprintf(stderr, "%s\n", mav_ctrlF_desc[i]);

  fprintf(stderr, "\n");
  if (mav_win_current->vmp) fprintf(stderr, "Current stereo offset: %f\n", mav_win_current->vmp->offset);
  fprintf(stderr, "Frame rate: %f fps (%f secs per frame)\n", mav_fps_avg, 1.0/mav_fps_avg);

  mav_gfxVisualInfoGet(&rb, &gb, &bb, &db, &doub, &ar, &ag, &ab);
  fprintf(stderr, "RGB bits: %i %i %i depth bits: %i double buffered: %i\n", rb, gb, bb, db, doub);
  if (mav_opt_accumBuf) fprintf(stderr, "Accumulation RGB bits: %i %i %i\n", ar, ag, ab);
}



/* Routine to deal with this event */

int mavlib_dealWithKeyboardEvent(int *info)
{
  MAV_keyboardEvent ke;
  int i, rv= MAV_FALSE;

  /* Make up event data structure */

  ke.win= mavlib_getWindow(info[0]);
  ke.x= info[1];
  ke.y= info[2];
  ke.root_x= info[3];
  ke.root_y= info[4];

  switch (info[5]) {
  case 0:
    ke.movement= MAV_PRESSED;
    break;
  case 1:
    ke.movement= MAV_RELEASED;
    break;
  }

  ke.key= info[6];

  for (i=0; i<MAV_MODIFIER_MAX; i++) {
    if (info[i+7]) 
    {
      ke.modifiers[i]= MAV_PRESSED;
    }
    else
    {
      ke.modifiers[i]= MAV_RELEASED;
    }
  }

  /* Check for reserved keystrokes */

  if (ke.movement==MAV_PRESSED && ke.modifiers[MAV_MODIFIER_SHIFT]==MAV_PRESSED) {
    if (ke.key==MAV_KEY_F1) {mavlib_sf1(); return -100;}
    if (ke.key==MAV_KEY_F2) {mavlib_sf2(); return -100;}
    if (ke.key==MAV_KEY_F3) {mavlib_sf3(); return -100;}
    if (ke.key==MAV_KEY_F4) {mavlib_sf4(); return -100;}
    if (ke.key==MAV_KEY_F5) {mavlib_sf5(); return -100;}
    if (ke.key==MAV_KEY_F6) {mavlib_sf6(); return -100;}
    if (ke.key==MAV_KEY_F7) {mavlib_sf7(); return -100;}
    if (ke.key==MAV_KEY_F8) {mavlib_sf8(); return -100;}
    if (ke.key==MAV_KEY_F9) {mavlib_sf9(); return -100;}
    if (ke.key==MAV_KEY_F10) {mavlib_sf10(); return -100;}
    if (ke.key==MAV_KEY_F11) {mavlib_sf11(); return -100;}
    if (ke.key==MAV_KEY_F12) {mavlib_sf12(); return -100;}
    if (ke.key==27) exit(1);
  }

  if (ke.movement==MAV_PRESSED && ke.modifiers[MAV_MODIFIER_CTRL]==MAV_PRESSED) {
    for (i=1; i<=12; i++) {
      if (ke.key==MAV_KEY_F1+i-1 && mav_ctrlF[i]) {
	(*mav_ctrlF[i])();
	return -100;
      }
    }
  }

  /* Check if system callback is defined - used for keyboard navigation */

  if (mav_callbackQuery(mav_callback_sysKeyboard, ke.win, mav_object_world))
  {
    rv= mav_callbackSysKeyboardExec(ke.win, mav_object_world, &ke);
    if (rv) return rv;
  }

  /* See what we hit */

  ke.line= mav_lineFrom2DPoint(ke.win, ke.x, ke.y);
  ke.intersects= mav_SMSIntersectLineAll(ke.win, ke.line, &ke.objint, &ke.obj);

  /* Check if any callbacks are defined for the world object */

  if (mav_callbackQuery(mav_callback_keyboard, ke.win, mav_object_world))
  {
    rv= mav_callbackKeyboardExec(ke.win, mav_object_world, &ke);
  }
  else
  {
    /* If we intersected, check for any class callbacks before specific class ones */

    if (ke.intersects) 
    {
      if (mav_callbackQuery(mav_callback_keyboard, ke.win, mav_object_any))
      {
	rv= mav_callbackKeyboardExec(ke.win, mav_object_any, &ke);
      }
      else
      {
	if (mav_callbackQuery(mav_callback_keyboard, ke.win, ke.obj))
	{
	  rv= mav_callbackKeyboardExec(ke.win, ke.obj, &ke);
	}
      }
    }
    else
    {
      /*  If no intersection check for none class */

      if (mav_callbackQuery(mav_callback_keyboard, ke.win, mav_object_none))
      {
	rv= mav_callbackKeyboardExec(ke.win, mav_object_none, &ke);
      }
    }
  }

  return rv;
}



/* Routine to query the status (pressed or released) of a key */

int mav_keyboardGet(int key)
{
  return (mav_gfxWindowKeyGet(key));
}
