//<copyright>
// 
// Copyright (c) 1993,94,95
// Institute for Information Processing and Computer Supported New Media (IICM),
// Graz University of Technology, Austria.
// 
//</copyright>

//<file>
//
// Name:        iv3dvw.C
//
// Purpose:     implementation of class HgIv3dViewer
//
// Created:     10 Jul 92   Keith Andrews, IICM (template)
//
// Changed:     18 Feb 95   Michael Pichler
//
//
//</file>


#include "iv3dvw.h"

#include "scenewin.h"
#include "vecutil.h"
#include "stranslate.h"

#include <IV-look/button.h>
#include <IV-look/kit.h>
#include <InterViews/session.h>
#include <InterViews/window.h>
#include <hyperg/hyperg/verbose.h>

#include <string.h>
#include <stdio.h>
#include <iostream.h>


HgIv3dViewer::HgIv3dViewer (HgViewerManager* manager, Session* session)
: Hg3dViewer (manager, session)
{
  state_ = s_ready;
  appwin_ = 0;
  // the application window should be created already here -
  // do not wait until whole document is read
}



HgIv3dViewer::~HgIv3dViewer ()
{
}



void HgIv3dViewer::load (const char* doc, const char* anchors, char* info)
{
  // later possibly change to an hourglass cursor until scene is read
  DEBUGNL ("HgIv3dViewer::load");

  Hg3dViewer::load (doc, anchors, info);

  state_ |= s_load;

} // load



void HgIv3dViewer::setLanguage (HgLanguage::Language hglang)
{
  int lang = (int) hglang;
  DEBUGNL ("HgIv3dViewer::setLanguage (" << lang << ")");

  if (lang >= 0 && lang < HgLanguage::NumLanguages && slanguage != hglang)
  {
    slanguage = hglang;
    scene_->updateLanguage ();
    updateTitle ();
  }
} // setLanguage



// get_pos_look
// extracts camera position and lookat point from string da (dest. anchor) in form
// Position=(px,py,pz) (lx,ly,lz)
// and writes it into pos (px,py,pz) and look (lx,ly,lz)
// return value non zero if field Position was found

static int get_pos_look (const char* dstanch, point3D& pos, point3D& look)
{
  const char* pospos  = strstr (dstanch, "Position=");

  if (pospos)
    sscanf (pospos, "Position=(%f, %f, %f) (%f, %f, %f)",
                     &pos.x, &pos.y, &pos.z,
                     &look.x, &look.y, &look.z);

  return (pospos != 0);
}



// browse
// show current document, opt. go to destination anchor
// if document is not completely read remember destination anchor
// to do display and browse when the document is read

void HgIv3dViewer::browse (             // browse current document
  const char* dest                      //   optional destination anchor
)
{
  DEBUGNL ("HgIv3dViewer::browse. Destination Anchor: <" << dest << ">.");

  state_ |= s_browse;
  browse_str_ = dest;  // store destination anchor

  if (state_ == s_all)
    showScene ();                       // set and display everything
  else if (state_ == s_browse)
    showScene (0);                      // redisplay loaded scene (new dest. anchor)

  // showScene resets state_ to s_ready

} // browse



// readingCompleted
// called by readInput when whole document was read
// check, whether load () and browse () arrived also -
// if so, show the scene

void HgIv3dViewer::readingCompleted ()
{
  DEBUGNL ("HgIv3dViewer::readingCompleted");

  state_ |= s_read;

  if (state_ == s_all)
    showScene ();  // display scene with opt. destination anchors

// TODO: have to do this when errors are reported to SM in other cases
//   error_ = OK;  // jschipf, 19950131
//   manager_->viewerError (this);  // loading completed

  // show Scene sets state_ to s_ready
}


void HgIv3dViewer::updateTitle ()
{
  // set title of scene
  DEBUGNL ("HgIv3dViewer::updateTitle");

  char curlang [16];
  sprintf (curlang, "Title=%s:", HgLanguage::getLanguageString (slanguage));
  RString doctitle = docObj ().field (curlang);
  if (!doctitle.length ())
    doctitle = docObj ().anyTitle ();
  doctitle.SGMLtoISO ();  // convert &auml; etc.
  const char* title = doctitle;
  // const char* colpos = strchr (title, ':');  // usually 0 or 2
  scene_->setTitle ((title [2] == ':') ? title + 3 : title);
}


/*** window operations (begin) ***/


void HgIv3dViewer::iconify ()
{
  DEBUGNL ("HgIv3dViewer::iconify");
  if (appwin_)
    appwin_->iconify ();
}

void HgIv3dViewer::deiconify ()
{
  DEBUGNL ("HgIv3dViewer::deiconify");
  if (appwin_)
    appwin_->deiconify ();
}

void HgIv3dViewer::moveto (float x, float y)
{
  DEBUGNL ("HgIv3dViewer::moveto" << x << ", " << y);
  if (appwin_)
    appwin_->move (x, y);
}

// resize not yet implemented
// would require to wrap yet another MonoGlyph around the window glyph
// that can be told its new size, then we can call appwin_->resize.
// anyway, resize is not used by Harmony

void HgIv3dViewer::map ()
{
  DEBUGNL ("HgIv3dViewer::map");
  if (appwin_)
    appwin_->map ();
//  appwin_->deiconify ();  // stable alternative to map/unmap
}

// note that the InterViews path to avoid unbind is assumed
// (if unbind had to be done on window, it would also be necessary
// for gecontext, which in turn causes troubles on 3D lighting)

void HgIv3dViewer::unmap ()
{
  DEBUGNL ("HgIv3dViewer::unmap");

  if (appwin_)
    appwin_->unmap ();
//  appwin_->iconify ();  // stable alternative to map/unmap
}

void HgIv3dViewer::raise ()
{
  DEBUGNL ("HgIv3dViewer::raise");
  if (appwin_)
    appwin_->raise ();
}

void HgIv3dViewer::lower ()
{
  DEBUGNL ("HgIv3dViewer::lower");
  if (appwin_)
    appwin_->lower ();
}


/*** window operations (end) ***/


// showScene
// this function is called when all data are complete:
// - load () gave the document id and source anchors
// - browse () could give a destination anchor
// - readInput () loaded the document
// so showScene:
// - sets the source anchors
//   (need not be done when browsing the current document)
// - sets the destination anchor
//   (if browse () supplied one)
// - displays the scene document

void HgIv3dViewer::showScene (int setsrcanchors)
{
  DEBUGNL ("HgIv3dViewer::showScene.");

  if (setsrcanchors)
    storeSourceAnchors ();

  // scene_->print (0);

  point3D position, lookat;
  init3D (position, 1, 0, 0);
  init3D (lookat, 0, 0, 0);

  // destination anchor: camera specification (optional)
  const char* dest = browse_str_;
  int camspec = get_pos_look (dest, position, lookat);
  // TODO: extend syntax to allow an optional up vector in destination

/*
  // test!
  camspec = get_pos_look ("Title=en:institute foyer\n"
                          "Title=ge:Instituts-Foyer\n"
                          "Position=(10.16,1.52,20.92) (11.09,1.52,20.56)\n"
                          "OtherField=none\n", position, lookat);
*/
  DEBUG ("HgIv3dViewer::showScene:");
  if (camspec)
  { DEBUGNL ("destination position: " << position << ", lookat: " << lookat);
  }
  else
  { DEBUGNL ("no camera setting included in destination anchor.");
  }

  DEBUGNL ("HgIv3dViewer::showScene: redrawing application window");
  appwin_ = scene_->appwin ();
  // appwin_->map ();  // already done in constructor of SceneWindow
  // SessionManager responsible for remapping to display new scene

  if (camspec)
    scene_->setCamera (position, lookat);

  scene_->reset ();   // redraw 3D output window and reset UI states
  // (not needed first time)

  // the following sequence would redraw only the (unchanged) appwin
  // instead of the window for 3D output atop the application window
  // appwin_->canvas ()->damage_all ();
  // appwin_->repair ();

  DEBUGNL ("HgIv3dViewer::showScene finished.");

  state_ = s_ready;  // ready for next load or browse

} // showScene
