// Please see the README file or the LEGAL NOTES-section in the manual before modifying, compiling or using 'xmrm'
//   Idea: Manfred Kopp
//   Programming: Gerhard Waldhör, Andreas Artmann

#include <forms.h>
#include <tiffio.h>
#include <stdlib.h>
#include <unistd.h>
#include <malloc.h> //****************
#include "xmrm.h"
#include "io.h"
#include "const.h"
#include "init.h"
#include "morphvec.h"
#include "areas.h"
#include "wavemorph.h"
#include "wave.h"

#include "xmrm-icon_111x35.xpm"
#include "xmrm-logo_158x50.xpm"
#include "drop_65x60.xpm"
#include "drop_shadow_65x60.xpm"
#include "tu_logo_120x60.xpm"
#include "tu_logo_shadow_120x60.xpm"

#define INTERVAL 1500

extern void Load_Project(const char *);
extern void Add_Extension(char *, const char *);
extern void AtActivate_MRM(FL_FORM *, void *);
extern void AtDeactivate_MRM(FL_FORM *, void *);
extern void Hide_Oneliner(int, void *);
extern void Hide_or_show_VEC_MENU_Win(int);

Pixmap xpm_drop, xpm_drop_shadow;
Pixmap xpm_tulogo, xpm_tulogo_shadow;
unsigned w_drop, h_drop;
unsigned w_tulogo, h_tulogo;

int max_x=0,max_y=0;

WindowClass *s_win, *d_win, *m_win, *a_win;
MorphVecClass *s_vec, *d_vec;// , *i_vec;
PictureClass *s_pic, *d_pic, *result_pic;
MyImageClass *MyImage, *cinema[MAX_PIC];
AreaClass *area;

GC gc;
Display *disp;
VisualInfoClass vis;
ControlClass control;

FD_MRM *fd_MRM;
FD_MORPH *fd_MORPH;  
FD_AREAS *fd_AREAS;
FD_RESULT *fd_RESULT;
FD_WAIT *fd_WAIT;
FD_CREDITS *fd_CREDITS;
FD_SLID_CONTR *fd_SLID_CONTR;
FD_VEC_MENU *fd_VEC_MENU;

// SLID_CONTR_pre_handler
int SLID_CONTR_pre_handler(FL_OBJECT *ob, int event, FL_Coord mx, FL_Coord my, int key, void *xev)
{
  char *s1, *s2, *s3;

  if ( ((event == FL_PUSH) || (event == FL_MOUSE)) && (key >= 2) )
  {
    if (ob == fd_SLID_CONTR->SL_Param_a)
    {
      s1="\n\nThe value 'a' influences every pixel according to the weight function:\n";
      s2="";
      s3="weight = [ (length_of_vector ^ p) / (A+distance_to_vector) ] ^ b";
    }
    else if (ob == fd_SLID_CONTR->SL_Param_b)
    {
      s1="\n\nThe value 'b' influences every pixel according to the weight function:\n";
      s2="";
      s3="weight = [ (length_of_vector ^ p) / (a+distance_to_vector) ] ^ B";
    }
    else if (ob == fd_SLID_CONTR->SL_Param_p)
    {
      s1="\n\nThe value 'p' influences every pixel according to the weight function:\n";
      s2="";
      s3="weight = [ (length_of_vector ^ P) / (a+distance_to_vector) ] ^ b";
    }

    fl_show_message(s1,s2,s3);

    return FL_PREEMPT;
  }
  return 0;
}

// SLID_CONTR_post_handler
int SLID_CONTR_post_handler(FL_OBJECT *ob, int event, FL_Coord mx, FL_Coord my, int key, void *xev)
{
  char *s=NULL;
  if (ob == fd_SLID_CONTR->SL_Param_a)
    s="Press right button for detailed information...";
  else if (ob == fd_SLID_CONTR->SL_Param_b)
    s="Press right button for detailed information...";
  else if (ob == fd_SLID_CONTR->SL_Param_p)
    s="Press right button for detailed information...";

  if (event == FL_ENTER && s)
    fl_set_object_label(fd_SLID_CONTR->Infoline,s);
//  else if (event != FL_MOTION)
  if (event == FL_LEAVE)
    fl_set_object_label(fd_SLID_CONTR->Infoline,NULL);

  return 0;
}

// CREDITS_post_handler
int CREDITS_post_handler(FL_OBJECT *ob, int event, FL_Coord mx, FL_Coord my, int key, void *xev)
{
  char s[] = "Starts NETSCAPE !";

  if (ob == fd_CREDITS->BT_Drop)
  {
    if (event == FL_ENTER)
    {
      fl_set_pixmapbutton_pixmap(ob, xpm_drop_shadow, 0);
      fl_redraw_object(ob);
    }
    if (event == FL_LEAVE)
    {
      fl_set_pixmapbutton_pixmap(ob, xpm_drop, 0);
      fl_redraw_object(ob);
    }
  }
  else if (ob == fd_CREDITS->BT_TU_Logo)
  {
    if (event == FL_ENTER)
    {
      fl_set_pixmapbutton_pixmap(ob, xpm_tulogo_shadow, 0);
      fl_redraw_object(ob);
    }
    if (event == FL_LEAVE)
    {
      fl_set_pixmapbutton_pixmap(ob, xpm_tulogo, 0);
      fl_redraw_object(ob);
    }
  }
  
  switch (event)
  {
    case FL_ENTER:
      fl_show_oneliner(s, ob->form->x + ob->x, ob->form->y + ob->y + ob->h + 1);
      break;
    
    case FL_LEAVE:
      fl_hide_oneliner();
      break;

    default:
      ;
  }

  return 0;
}

// MRM_post_handler
int MRM_post_handler(FL_OBJECT *ob, int event, FL_Coord mx, FL_Coord my, int key, void *xev)
{
  char *s=NULL;
 
  if (ob == fd_MRM->CB_Simple_Morph)
    s="Morph Source Image into Destination Image according to your settings !";
  else if (ob == fd_MRM->BT_Drop)
  {
    s = "Click this pixmap to start Netscape and visit the Institute of Computer Graphics !";
    if (event == FL_ENTER)
    {
      fl_show_oneliner("Starts NETSCAPE !", ob->form->x + ob->x, ob->form->y + ob->y + ob->h + 1);
      fl_set_pixmapbutton_pixmap(ob, xpm_drop_shadow, 0);
      fl_redraw_object(ob);
    }
    if (event == FL_LEAVE)
    {
      fl_hide_oneliner();
      fl_set_pixmapbutton_pixmap(ob, xpm_drop, 0);
      fl_redraw_object(ob);
    }
  }
  else if (ob == fd_MRM->CB_Warp)
    s="Only warp the Source Image according to the Vectors set in the Source and Destination field !";
  else if (ob == fd_MRM->CB_Animate_Detail)
    s="Interpolate wavelet-coeffs between 0.5-source_warp and (-0.5)-destination_warp !";
  else if (ob == fd_MRM->BT_Swap_Vecs)
    s="Swap Images and Vectors";
  else if (ob == fd_MRM->BT_About)
    s="Honour us by taking a look..";
  else if (ob == fd_MRM->CB_Advanced_Mode)
    s="Advanced Mode";
  else if (ob == fd_MRM->CB_Border_Vecs)
    s="Border Vectors are set internally (not visible)";
  else if (ob == fd_MRM->CT_Level_Select)
    s="Select Wavelet-Level";
  else if (ob == fd_MRM->SL_Level_Adjust)
    s="Modify Wavelet-Level";
  else if (ob == fd_MRM->BT_Level[0])
    s="Let wavelet level #1 be fixed";
  else if (ob == fd_MRM->BT_Level[1])
    s="Let wavelet level #2 be fixed";
  else if (ob == fd_MRM->BT_Level[2])
    s="Let wavelet level #3 be fixed";
  else if (ob == fd_MRM->BT_Level[3])
    s="Let wavelet level #4 be fixed";
  else if (ob == fd_MRM->BT_Level[4])
    s="Let wavelet level #5 be fixed";
  else if (ob == fd_MRM->BT_Level[5])
    s="Let wavelet level #6 be fixed";
  else if (ob == fd_MRM->BT_Level[6])
    s="Let wavelet level #7 be fixed";
  else if (ob == fd_MRM->BT_Level[7])
    s="Let wavelet level #8 be fixed";
  else if (ob == fd_MRM->BT_Level[8])
    s="Let wavelet level #9 be fixed";
  else if (ob == fd_MRM->BT_Level[9])
    s="Let wavelet level #10 be fixed";
  else if (ob == fd_MRM->BT_Calculate)
    s="Let's GO !";
  else if (ob == fd_MRM->CT_Frames)
    s="Number of Frames to calculate";
  else if (ob == fd_MRM->CB_Animation)
    s="Animation Sequence Mode";
  else if (ob == fd_MRM->CB_Single_Frame)
    s="Show/Calculate Single Frame Mode";
  else if (ob == fd_MRM->CB_Anim_Cycle)
    s="SRC->DST->SRC->STOP";
  else if (ob == fd_MRM->SL_fps)
    s="Set frame-rate";
  else if (ob == fd_MRM->BT_Animate)
    s="Start the Animation";
  else if (ob == fd_MRM->CT_Frame_Nr)
    s="Select Frame Number - Hit Calculate if not in animation";
/*AAA  else if (ob == fd_MRM->BT_MPEG_Info)
    s="PRESS for MPEG-encoding Info";
  else if (ob == fd_MRM->CB_MPEG_Cycle)
    s="Make MPEG-Cycle";*/
    
  if (event == FL_ENTER && s)
    fl_set_object_label(fd_MRM->Infoline,s);
//  else if (event != FL_MOTION)
  if (event == FL_LEAVE)
    fl_set_object_label(fd_MRM->Infoline,NULL);

  return 0;
}

// VEC_MENU_pre_handler
int VEC_MENU_pre_handler(FL_OBJECT *ob, int event, FL_Coord mx, FL_Coord my, int key, void *xev)
{
  switch( event)
  {
    case FL_PUSH:
      if ( key >=2 )
      {
        Hide_or_show_VEC_MENU_Win(1);
        return FL_PREEMPT;
      }
      break;
  }
  
  return 0;
}

// VEC_MENU_post_handler
int VEC_MENU_post_handler(FL_OBJECT *ob, int event, FL_Coord mx, FL_Coord my, int key, void *xev)
{
  char s[] = "Right Button to Hide!";
  int timeoutID;
  static int first_time = 1;
  
  switch (event)
  {
    case FL_ENTER:
      if ( first_time )
      {
       first_time = 0;
       fl_show_oneliner(s, ob->form->x + ob->x, ob->form->y + ob->y + ob->h / 2);
       timeoutID = fl_add_timeout(INTERVAL, Hide_Oneliner, 0);
      }
      break;

    default:
      ;
  }

  return 0;
}

// -----------------------------------------------------------------------------
//                                M A I N :
// -----------------------------------------------------------------------------
int main(int argc, char *argv[])
{
  FL_OBJECT *obj;
  int c;
  char *argv_filename_project = NULL;
  char *temp;

//  memory_warnings(NULL, NULL);//(void *)Warn_Mem());

  opterr = 0; // suppress Error-messages from getopt
  control.debug = 0;
  
  /* Init control: */
  //control.ControlClass(); // call constructor
  temp = control.URL_manual;

  while( (c=getopt(argc, argv, "hdm:p:")) != -1)
    switch (c)
    {
      case 'd':
        printf("* XMRM DEBUG MODE *\n");
        control.debug = 1;
        break;
      case 'm':
        control.URL_manual = optarg;
        break;
      case 'p':
        argv_filename_project = optarg;
        break;
      case 'h':
        fprintf(stderr,"\nusage: %s: [-hd] [-p project_file[.prj]] [-m manual_location] [xforms]\n\n",argv[0]);
        fprintf(stderr,"  -h: usage information\n");
        fprintf(stderr,"  -d: print debug information\n");
        fprintf(stderr,"  -p: load Project at start-up\n");
        fprintf(stderr,"  -m: specify the location of the manual - URL of Online-manual is default\n");
        fprintf(stderr,"  xforms: These options will be passed to fl_initialize() of the XForms library.\n");
        fprintf(stderr,"          You shouldn't need these options.\n\n");
        return 0;
      case '?':
        break;
    }

  if ( !control.URL_manual )
    control.URL_manual = temp;

//  (void) mcheck(NULL);

  /* Set global borderwidth */
  fl_set_border_width(BW);
  
  /* Initializing display: */
  disp = fl_initialize(&argc,argv,"XMRM",0,0);

  /* Create forms: */
  fd_MRM = create_form_MRM();
  fd_MORPH = create_form_MORPH();
  fd_AREAS = create_form_AREAS();
  fd_RESULT = create_form_RESULT();
  fd_WAIT = create_form_WAIT();
  fd_CREDITS = create_form_CREDITS();
  fd_SLID_CONTR = create_form_SLID_CONTR();
  fd_VEC_MENU = create_form_VEC_MENU();

  // DO NET SET PIXMAPS HERE --> SEE BELOW, IF SET HERE -> ERROR !!! (WE DON´T KNOW WHY)

  /* Getting visual information: */
  vis.GetVisualInfo();

  /* Allocate memory for objects: */
  s_vec = new MorphVecClass;
  d_vec = new MorphVecClass;
//  i_vec = new MorphVecClass;
  
  s_win = new WindowClass;  
  d_win = new WindowClass;  
  m_win = new WindowClass;    
  a_win = new WindowClass;      
  
  s_pic = new PictureClass;
  d_pic = new PictureClass;
  result_pic = new PictureClass;    
    
  MyImage = new MyImageClass;
  
  for (int i=0; i<MAX_PIC; i++)
    cinema[i] = new MyImageClass;

  area = new AreaClass;

  Wave_Init(control.debug);
    
  /* Set cursor colors: */
  fl_set_cursor_color(XC_hand2,FL_BLACK,FL_RED);
  fl_set_cursor_color(XC_arrow,FL_BLACK,FL_GREEN);
  fl_set_cursor_color(XC_pirate,FL_RED,FL_BLACK);    

  /* Set post- and prehandlers for MRM: */
  fl_set_object_posthandler(fd_MRM->CB_Simple_Morph,MRM_post_handler);
  fl_set_object_posthandler(fd_MRM->CB_Warp,MRM_post_handler);
  fl_set_object_posthandler(fd_MRM->CB_Animate_Detail,MRM_post_handler);
  fl_set_object_posthandler(fd_MRM->BT_Swap_Vecs,MRM_post_handler);
  fl_set_object_posthandler(fd_MRM->BT_About,MRM_post_handler);
  fl_set_object_posthandler(fd_MRM->CB_Advanced_Mode,MRM_post_handler);
  fl_set_object_posthandler(fd_MRM->CB_Border_Vecs,MRM_post_handler);
  fl_set_object_posthandler(fd_MRM->BT_Calculate,MRM_post_handler);
  fl_set_object_posthandler(fd_MRM->CT_Frames,MRM_post_handler);
  fl_set_object_posthandler(fd_MRM->CB_Animation,MRM_post_handler);
  fl_set_object_posthandler(fd_MRM->CB_Single_Frame,MRM_post_handler);
  fl_set_object_posthandler(fd_MRM->CB_Anim_Cycle,MRM_post_handler);
  fl_set_object_posthandler(fd_MRM->SL_fps,MRM_post_handler);
  fl_set_object_posthandler(fd_MRM->BT_Animate,MRM_post_handler);
  fl_set_object_posthandler(fd_MRM->CT_Frame_Nr,MRM_post_handler);
  fl_set_object_posthandler(fd_MRM->BT_Drop,MRM_post_handler);

  for (int i=0; i<MAX_LEVELS; i++)
    fl_set_object_posthandler(fd_MRM->BT_Level[i],MRM_post_handler);

  fl_set_object_posthandler(fd_MRM->CT_Level_Select,MRM_post_handler);
  fl_set_object_posthandler(fd_MRM->SL_Level_Adjust,MRM_post_handler);

  /* Set post- and prehandlers for SLID_CONTR: */
  fl_set_object_prehandler(fd_SLID_CONTR->SL_Param_a,SLID_CONTR_pre_handler);
  fl_set_object_posthandler(fd_SLID_CONTR->SL_Param_a,SLID_CONTR_post_handler);

  fl_set_object_prehandler(fd_SLID_CONTR->SL_Param_b,SLID_CONTR_pre_handler);
  fl_set_object_posthandler(fd_SLID_CONTR->SL_Param_b,SLID_CONTR_post_handler);

  fl_set_object_prehandler(fd_SLID_CONTR->SL_Param_p,SLID_CONTR_pre_handler);
  fl_set_object_posthandler(fd_SLID_CONTR->SL_Param_p,SLID_CONTR_post_handler);
  
  fl_set_object_posthandler(fd_CREDITS->BT_Drop, CREDITS_post_handler);
  fl_set_object_posthandler(fd_CREDITS->BT_TU_Logo, CREDITS_post_handler);  

  fl_set_object_prehandler(fd_VEC_MENU->vec_menu, VEC_MENU_pre_handler);
  fl_set_object_prehandler(fd_VEC_MENU->BT_SetVec, VEC_MENU_pre_handler);
  fl_set_object_prehandler(fd_VEC_MENU->BT_EditVec, VEC_MENU_pre_handler);
  fl_set_object_prehandler(fd_VEC_MENU->BT_SetLines, VEC_MENU_pre_handler);
  fl_set_object_prehandler(fd_VEC_MENU->BT_DeleteVec, VEC_MENU_pre_handler);
  fl_set_object_posthandler(fd_VEC_MENU->vec_menu, VEC_MENU_post_handler);

  // Set goodies font
  fl_set_goodies_font(FL_BOLD_STYLE,FL_NORMAL_SIZE);
  
  // Set At(De)Activate callbacks for MRM
  fl_set_form_atactivate(fd_MRM->MRM, AtActivate_MRM, 0);
  fl_set_form_atdeactivate(fd_MRM->MRM, AtDeactivate_MRM, 0);

  /* Initialize sliders & buttons: */
  fl_call_object_callback(fd_MRM->CB_Simple_Morph);
  fl_call_object_callback(fd_MRM->CB_Advanced_Mode);
  fl_call_object_callback(fd_MRM->CB_High_Quality);
  fl_call_object_callback(fd_MRM->SL_Level_Adjust);
  fl_call_object_callback(fd_MRM->CT_Frames);
  fl_call_object_callback(fd_MRM->CT_Frame_Nr);
  fl_call_object_callback(fd_MRM->CB_Save_Calculation);
  fl_call_object_callback(fd_MRM->CB_Save_Animation);
  fl_call_object_callback(fd_MRM->CB_Single_Frame);
  fl_call_object_callback(fd_MRM->CB_Animation);
  fl_call_object_callback(fd_MRM->CB_Anim_Cycle);
  fl_call_object_callback(fd_MRM->SL_fps);

  for (int i=0; i<MAX_LEVELS; i++)
    fl_hide_object(fd_MRM->BT_Level[i]);

  fl_call_object_callback(fd_SLID_CONTR->SL_Param_a);
  fl_call_object_callback(fd_SLID_CONTR->SL_Param_b);
  fl_call_object_callback(fd_SLID_CONTR->SL_Param_p);

  // redirect TIFF-Error- and Warnig-Handler
  (void) TIFFSetErrorHandler(NULL);
  (void) TIFFSetWarningHandler(NULL);
  
  // Set the icons
  xpm_drop_shadow = fl_create_from_pixmapdata(fl_default_window(), &(*drop_shadow_65x60), &w_drop, &h_drop, NULL, 0, 0, 0);
  xpm_drop = fl_create_from_pixmapdata(fl_default_window(), &(*drop_65x60), &w_drop, &h_drop, NULL, 0, 0, 0);
  xpm_tulogo = fl_create_from_pixmapdata(fl_default_window(), &(*tu_logo_120x60), &w_drop, &h_drop, NULL, 0, 0, 0);
  xpm_tulogo_shadow = fl_create_from_pixmapdata(fl_default_window(), &(*tu_logo_shadow_120x60), &w_drop, &h_drop, NULL, 0, 0, 0);

  Pixmap p_icon;
  unsigned w_icon, h_icon;
  
  p_icon = fl_create_from_pixmapdata(fl_default_window(), &(*xmrm_logo_very_small), &w_icon, &h_icon, NULL, 0, 0, 0);
  fl_set_form_icon(fd_MRM->MRM, p_icon, 0);
  fl_set_form_icon(fd_MORPH->MORPH, p_icon, 0);
  fl_set_form_icon(fd_AREAS->AREAS, p_icon, 0);
  fl_set_form_icon(fd_RESULT->RESULT, p_icon, 0);
  fl_set_form_icon(fd_WAIT->WAIT, p_icon, 0);
  fl_set_form_icon(fd_CREDITS->CREDITS, p_icon, 0);
  fl_set_form_icon(fd_SLID_CONTR->SLID_CONTR, p_icon, 0);
  fl_set_form_icon(fd_VEC_MENU->VEC_MENU, p_icon, 0);

  fl_set_pixmapbutton_data(fd_MRM->BT_Drop, drop_65x60);
  fl_set_pixmapbutton_data(fd_CREDITS->XPM_xmrm_logo, xmrm_logo_small);
  fl_set_pixmapbutton_data(fd_CREDITS->BT_TU_Logo, tu_logo_120x60);
  fl_set_pixmapbutton_data(fd_CREDITS->BT_Drop, drop_65x60);

  /* Show forms: */
  fl_set_form_position(fd_MRM->MRM,0,0);
  fl_show_form(fd_MRM->MRM,FL_PLACE_GEOMETRY,FL_FULLBORDER,PROGRAM_ID);
  gc = fl_state[fl_get_vclass()].gc[0];

  if ( argv_filename_project )
  {
    // user didn´t supply absolute path...
    if ( *argv_filename_project != '/' )
    {
      (void) getcwd(control.filename_project, BUFSIZ);
      strcat(control.filename_project, "/");
      strcat(control.filename_project, argv_filename_project);
    }
    // user DID supply absolut path
    else
      strcpy( control.filename_project, argv_filename_project );

    // add extension if necessary
    Add_Extension(control.filename_project, ".prj");
    Load_Project( control.filename_project );
  }

  fl_do_forms();

  return 0;
}
