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

//<file>
//
// Name:        about.C
//
// Purpose:     implementation of about dialog
//
// Created:     25 Apr 94   Michael Pichler
//
// Changed:     29 Jun 94   Michael Pichler
//
//
//</file>



#include "about.h"
#include "glyphutil.h"
#include "wtranslate.h"
#include "xpmraster.h"

#include "harletters.xbm"
// harmony letters are compiled-in
// logos are too big, so read them from TIFF-file

#include <InterViews/background.h>
#include <InterViews/bitmap.h>
#include <InterViews/color.h>
#include <InterViews/display.h>
#include <InterViews/event.h>
#include <InterViews/font.h>
#include <InterViews/handler.h>
#include <InterViews/image.h>
#include <InterViews/label.h>
#include <InterViews/layout.h>
#include <InterViews/patch.h>
#include <InterViews/session.h>
#include <InterViews/stencil.h>
#include <InterViews/style.h>
#include <InterViews/tiff.h>
#include <InterViews/window.h>
#include <IV-look/kit.h>

#include <OS/string.h>

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


// static members

ManagedWindow* About::aboutwin_ = 0;
float About::hleft_ = -1;
float About::hbottom_ = -1;
Glyph* About::crglyph_ = 0;
Patch* About::winpatch_ = 0;
Glyph* About::credits_ = 0;
PolyGlyph* About::crbox_ = 0;
PolyGlyph* About::bigbox_ = 0;
int About::crindex_ = 0;
int About::card_ = 0;
const Font* About::bigfont_ = 0;
const Font* About::smallfont_ = 0;


// default fonts

static const char* def_large_font = "-*-helvetica-medium-r-*-*-17-*-*-*-*-*-iso8859-*";
static const char* def_small_font = "-*-helvetica-medium-r-*-*-12-*-*-*-*-*-iso8859-*";


/*** AboutDeleteHandler ***/

class AboutDeleteHandler: public Handler
{
  public:
    boolean event (Event&);
};


boolean AboutDeleteHandler::event (Event&)
{
  About::unmap ();
  return 1;
}


/*** CloseOnKeypress ***/
// Inputhandler that closes About window on keypress and mouse click
// when deleting the window on press, the mouse up event
// for that window causes a seg'fault

class CloseOnKeypress: public InputHandler
{
  public:
    CloseOnKeypress (Glyph* body, Style* style)
    : InputHandler (body, style)  { }

    void keystroke (const Event&);
    void release (const Event&);
};


void CloseOnKeypress::keystroke (const Event& e)
{
  char key;  // do not unmap on shift etc.
  if (e.mapkey (&key, 1))
    About::unmap ();
}


void CloseOnKeypress::release (const Event&)
{
  About::unmap ();
}


/*** ShowOtherGlyph ***/

class ShowOtherGlyph: public InputHandler
{
  public:
    ShowOtherGlyph (Glyph* body, Style* style)
    : InputHandler (body, style)  { }

    void release (const Event&);
    void double_click (const Event&);
};


void ShowOtherGlyph::release (const Event& e)
{
  if (!e.shift_is_down () && !e.control_is_down ())
    About::unmap ();
}


void ShowOtherGlyph::double_click (const Event& e)
{
  if (e.shift_is_down () || e.control_is_down ())
    About::toggleCard ();
}



// newpath
// adds up a path name, creates a new string that has to be deleted after use

static char* newpath (const String& iconpath, Style* style,
                      const char* attrname, const char* deffile)
{
  String filename;
  if (!style->find_attribute (attrname, filename))
    filename = deffile;

  int iplen = iconpath.length ();
  int fnlen = filename.length ();

  char* path = new char [iplen + fnlen + 2];
  char* p = path;  // after iconpath

  if (iplen)
  { strncpy (path, iconpath.string (), iplen);
    p += iplen;
    // append '/' if not yet there, not done when no iconpath
    if (p [-1] != '/')
      *p++ = '/';
  }

  strncpy (p, filename.string (), fnlen);
  p [fnlen] = '\0';

//cerr << "icon path and file name: " << path << " [" << iplen + fnlen + 2 << "]" << endl;

  return path;
}



// getBigFont, getSmallFont
// create big/small font for "About" style (first time)

const Font* About::getBigFont ()
{
  if (!bigfont_)
    lookupFonts ();

  return bigfont_;
}


const Font* About::getSmallFont ()
{
  if (!smallfont_)
    lookupFonts ();

  return smallfont_;
}


void About::lookupFonts ()  // lookup fonts first time
{
  if (bigfont_ && smallfont_)
    return;

  WidgetKit& kit = *WidgetKit::instance ();
  kit.begin_style ("About");
  Style* style = kit.style ();
  String valstr;

  if (!style->find_attribute ("infofontbig", valstr) || !(bigfont_ = Font::lookup (valstr)))
    if (!(bigfont_ = Font::lookup (def_large_font)))
      bigfont_ = kit.font ();
  Resource::ref (bigfont_);


  if (!style->find_attribute ("infofontsmall", valstr) || !(smallfont_ = Font::lookup (valstr)))
    if (!(smallfont_ = Font::lookup (def_small_font)))
      smallfont_ = kit.font ();
  Resource::ref (smallfont_);

  kit.end_style ();  // "About"
}



// map

void About::map (
  HgLanguage::Language lang,
  const char* description,
  const char* version,
  const char* wintitle,
  int biglogo
)
{
  if (aboutwin_)  // do not map twice
    return;

  if (!bigfont_)  // look up fonts (first time)
    lookupFonts ();

  WidgetKit& kit = *WidgetKit::instance ();
  const LayoutKit& layout = *LayoutKit::instance ();

  kit.begin_style ("About");
  Style* style = kit.style ();

  Color* black = new Color ((float) 0.0, (float) 0.0, (float) 0.0);
  Color* white = new Color ((float) 1.0, (float) 1.0, (float) 1.0);
  // this nice colour is not part of the Harmony colour map:
  Color* greyblue = new Color ((float) 0.92, (float) 0.91, (float) 0.96);  // (235, 232, 245)
  Color* darkblue = new Color ((float) 0, (float) 0.02, (float) 0.73);  // (0, 5, 186)

  CopyString iconpath;  // ordinary String class behaves just like char*
  // iconpath only needed for big logo (other icons compiled-in)
  if (!style->find_attribute ("iconpath", iconpath))
  {
    // default iconpath: $HARMONY_HOME/icons
    const char* harmonyhome = getenv ("HARMONY_HOME");
    if (harmonyhome)  // should always be set
    {
      int len = strlen (harmonyhome) + 10;
      char* buf = new char [len];
      sprintf (buf, "%s/icons", harmonyhome);
      iconpath = buf;
      delete[] buf;
    }
  }
  // cerr << "icon path: " << iconpath.string () << endl;

  Glyph* aboutlogo = nil;
  char* fullpath;
  if (biglogo)
  {
    fullpath = newpath (iconpath, style, "aboutlogo", "aboutlogo.tif");
    aboutlogo = new Image (TIFFRaster::load (fullpath));
    delete fullpath;
  }
  else
    aboutlogo = layout.vspace (5);

  Glyph* harmony_letters = new Stencil (
    new Bitmap (harletters_bits, harletters_width, harletters_height),
    darkblue
  );

  Glyph* harmony_logo = nil;
  if (!biglogo)
  {
    fullpath = newpath (iconpath, style, "harmonylogo", "harmonylogo.tif");
    Glyph* har_tiff = new Image (TIFFRaster::load (fullpath));
    delete fullpath;

    fullpath = newpath (iconpath, style, "harmonymask", "harmonymask.xbm");
    Bitmap* harmony_mask = Bitmap::open (fullpath);  // bit set for background
    if (!harmony_mask)
      cerr << "About: Cannot open " << fullpath << endl;
    delete fullpath;
    if (harmony_mask)
      harmony_logo = layout.overlay (har_tiff, new Stencil (harmony_mask, greyblue));
    else
      harmony_logo = har_tiff;
  }

  fullpath = newpath (iconpath, style, "hyperglogo", "hyperg.tif");
  Glyph* hyperg_tiff = new Image (TIFFRaster::load (fullpath));
  delete fullpath;

  fullpath = newpath (iconpath, style, "hypergmask", "hyperg_mask.xbm");
  Bitmap* hyperg_mask = Bitmap::open (fullpath);  // bit set for background
  if (!hyperg_mask)
    cerr << "About: Cannot open " << fullpath << endl;
  delete fullpath;

  Glyph* hyperg_logo;  // logo with mask stencil
  if (hyperg_mask)
    hyperg_logo = layout.overlay (hyperg_tiff, new Stencil (hyperg_mask, greyblue));
  else
    hyperg_logo = hyperg_tiff;

  Glyph* vspace = layout.vspace (8.0);

  Glyph* hglue = layout.hglue (10, fil, 0);
  Glyph* vglue = layout.vglue ();

  Glyph* descrversion = layout.vbox (
    layout.hmargin (
      multiLineLabel (description, bigfont_, black),
      5, fil, 0, 5, fil, 0
    ),
    vspace,
    layout.hmargin (
      multiLineLabel (version, smallfont_, black),
      0, fil, 0, 0, fil, 0
    )
  );

  PolyGlyph* upperpart = layout.vbox (
    aboutlogo,
    vspace,
    layout.hmargin (
      harmony_letters,
      10, fil, 0, 10, fil, 0
    ),
    layout.vspace (12),
    descrversion,
    vspace
  );

  crbox_ = upperpart;
  if (biglogo)
  { crglyph_ = aboutlogo;
    crindex_ = 0;
  }
  else
  { crglyph_ = descrversion;
    crindex_ = 4;
  }
  Resource::ref (crglyph_);
  // for credits

  Glyph* lowerpart = layout.hbox (
    hglue,
    layout.vcenter (
      new ShowOtherGlyph (
        hyperg_logo,
        style
      ),
      0.5
    ),
    hglue,
    layout.vcenter (
      layout.vbox (
	vglue,
	new Label (WTranslate::str (WTranslate::COPYRIGHT94IICM, lang), smallfont_, black),
	vglue,
	new Label (WTranslate::str (WTranslate::TUGRAZ, lang), smallfont_, black),
	vglue,
	new Label (WTranslate::str (WTranslate::ALLRIGHTSRESERVED, lang), smallfont_, black),
	vglue
      ),
      0.5
    ),
    hglue,
    layout.vcenter (
      harmony_logo,
      0.5
    ),
    hglue
  );

  bigbox_ = layout.vbox (
    new Background (
      upperpart,
      white
    ),
    new Background (
      layout.vmargin (
        lowerpart,
        5, 0, 0, 5, 0, 0
      ),
      greyblue
    )
  );

  winpatch_ = new Patch (
    new CloseOnKeypress (
      new TransparentTarget (bigbox_),
      style
    )
  );
  aboutwin_ = new ApplicationWindow (winpatch_);
//aboutwin_ = new TransientWindow (winpatch_);  // mgais, 19950113

  aboutwin_->wm_delete (new AboutDeleteHandler ());

  Style* namestyle = new Style (style);
  if (!wintitle)
    wintitle = WTranslate::str (WTranslate::ABOUTHARMONY, lang);
  namestyle->attribute ("name", wintitle);
  // same iconName
  aboutwin_->style (namestyle);

//    setIconWindow(hyperWindow_,style);

  if (hleft_ >= 0)  // open at previous position
    aboutwin_->place (hleft_, hbottom_);

  aboutwin_->map ();

  // jschipf, 19940620
  aboutwin_->repair ();
  aboutwin_->display ()->flush ();

  kit.end_style ();  // "About"

} // map


void About::unmap ()
{
  if (aboutwin_)
  {
    hleft_ = aboutwin_->left ();
    hbottom_ = aboutwin_->bottom ();
    Resource::unref (crglyph_);
    crglyph_ = 0;
    delete aboutwin_;
    aboutwin_ = 0;
    card_ = 0;
//    current_ = -1;
  }
} // unmap


void About::credits (Glyph* credits)
{
  if (credits != credits_)
  {
    Resource::ref (credits);
    Resource::unref (credits_);
    credits_ = credits;
  }
}


void About::toggleCard ()
{
  if (card_)  // hide credits
  {
    crbox_->replace (crindex_, crglyph_);
    bigbox_->modified (0);
    card_ = 0;
  }
  else  // show credits
  {
    if (!credits_)
      return;

    crbox_->replace (crindex_, credits_);
    bigbox_->modified (0);
    card_ = 1;
  }

  winpatch_->reallocate ();
  aboutwin_->resize ();
  winpatch_->redraw ();
}
