/* -copyright-
#-# 
#-# Copyright (C) 1999-2001  Robin Hogan, 2021-2026 Willem Vermin
#-# 
#-# 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 <gtk/gtk.h>
#include <math.h>
#include "ui_xml.h"
#include "ui.h"
#include "debug.h"
#include "main.h"
#include "toon.h"
#include "xpenguins.h"
#include "utils.h"

#include "xpenguins.xpm"
#include "button_angel.xpm"
#include "button_splat.xpm"

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#ifdef __cplusplus
#define MODULE_EXPORT extern "C" G_MODULE_EXPORT
#else
#define MODULE_EXPORT G_MODULE_EXPORT
#endif


int ThemeFound;

static char **allthemenames;  /* all theme names */
static int    nthemes;        /* number of themes known: as many buttons will show up, to a max of NTYPES */
static int    human_action = 1;   /* is it a human who is playing with the buttons? */

#define NTYPES 16 
static GtkBuilder      *builder;
static GtkWidget       *hauptfenster;
static GtkStyleContext *hauptfenstersc;
static char             buf[100];
static GtkWidget       *id_lift;
static GtkWidget       *id_liftvalue;
static GtkWidget       *id_penguin;
static GtkWidget       *id_penguinvalue;
static GtkWidget       *id_logo1;
static GtkWidget       *id_logo2;
static GtkWidget       *id_logo3;
static GtkWidget       *id_angel_picture;
static GtkWidget       *id_splat_picture;
static GtkWidget       *id_speed;
static GtkWidget       *id_speedvalue;
static GtkWidget       *id_angels;
static GtkWidget       *id_blood;
static GtkWidget       *id_types[NTYPES];
static GtkWidget       *id_icons[NTYPES];

static void   handle_css(void);
static void   init_buttons(void);
static void   init_ids(void);
static void   init_pixmaps(void);
static FILE  *openflagsfile(char *mode);
static float  speedfactor_to_scale(float speed);
static float  scale_to_speedfactor(float scale);
static float  npenguins_to_scale(float n);
static float  scale_to_npenguins(float scale);
static void   ab(float Max, float Min, float *a, float *b);


// Sometimes it is good to have a logarithmic scale, such that
//
//  V = a*M*10**s + b 
//
//  where:       V = parameter (e.g. SpeedFactor)
//               M = desired maximum of V (e.g. 4.0)
//               s = value of the gtkscale (0 .. 1.0)
//  Furthermore: m = desired minimum of V (e.g. 0.2)
//
//  Then:
//     a = (M - m)/(9*M)
//     b = m - a*M
//
// The placement of a is a logical choice, the placement of b is 
// more or less random. I need a constant next to a, because I want
// to define minimum V AND maximum V. 
//
// Given V, compute s:
//
//   s = log10((V-b)/(a*M))
// 

void ab(float Max, float Min, float *a, float *b)
{
   *a = (Max - Min)/(9.0*Max);
   *b = Min - (*a)*Max;
}

const float MaxSpeedFactor = 4.0;
const float MinSpeedFactor = 0.2;

const float MaxNPenguins = 200;
const float MinNPenguins = 1.0;

void handle_css()
{
}

MODULE_EXPORT void buttoncb(GtkWidget *w, char *data)
{
   if(!human_action)
      return;
   int active = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w));
   P("buttoncb: %d %d\n",*data,active); 
   if (active || !active)
   {
      char *backup_theme = strdup(ThemeNames[0]);
      // add/remove theme
      P("add/remove theme %s\n",data);
      xpenguins_free_list(ThemeNames);
      ThemeNames = NULL;
      int i;
      int imax;
      if (nthemes > NTYPES)
	 imax = NTYPES;
      else
	 imax = nthemes;

      int n = 0;
      for (i=0; i<imax; i++)
      {
	 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(id_types[i])))
	 {
	    n++;
	    P("add theme n: %d i: %d theme: %s\n",n,i,allthemenames[i]);
	    ThemeNames = (char **)realloc(ThemeNames,n*sizeof(char*));
	    if(ThemeNames == NULL)
	    {
	       fprintf(stderr,"Realloc error in %s:%d\n",__FILE__,__LINE__);
	       exit(1);
	    }
	    ThemeNames[n-1] = strdup(allthemenames[i]);
	 }
      }
      if (n == 0)
      {
	 n = 1;
	 ThemeNames = (char **)realloc(ThemeNames,n*sizeof(char*));
	 if(ThemeNames == NULL)
	 {
	    fprintf(stderr,"Realloc error in %s:%d\n",__FILE__,__LINE__);
	    exit(1);
	 }
	 ThemeNames[0] = strdup(backup_theme);
      }
      ThemeNames = (char **)realloc(ThemeNames,(n+1)*sizeof(char*));
      if(ThemeNames == NULL)
      {
	 fprintf(stderr,"Realloc error in %s:%d\n",__FILE__,__LINE__);
	 exit(1);
      }
      ThemeNames[n] = NULL;
      free(backup_theme);
      main_init();
      npenguins = default_penguin_number();
      xpenguins_set_number(npenguins);
      set_buttons();

      if(0)
      {
	 GtkWidget *m = gtk_message_dialog_new(GTK_WINDOW(hauptfenster),
	       //GTK_DIALOG_DESTROY_WITH_PARENT,
	       GTK_DIALOG_MODAL,
	       //0,
	       GTK_MESSAGE_INFO,
	       GTK_BUTTONS_OK,
	       "And the winner is %s!\n",
	       data
	       );
	 g_signal_connect(m,"response",G_CALLBACK(gtk_widget_destroy),NULL);
	 gtk_widget_show_all(m);
      }
   }
}

void show_dialog(int type, const char *format, const char *text)
{
   GtkMessageType message_type;
   if (type == 1)
      message_type = GTK_MESSAGE_ERROR;
   else
      message_type = GTK_MESSAGE_INFO;

   GtkWidget *m = gtk_message_dialog_new(GTK_WINDOW(hauptfenster),
	 GTK_DIALOG_MODAL,
	 message_type,
	 GTK_BUTTONS_OK,
	 format,
	 text
	 );
   g_signal_connect(m,"response",G_CALLBACK(gtk_main_quit),NULL);
   gtk_widget_show_all(m);
}

void init_buttons()
{
   allthemenames = get_themes(&nthemes);
   int i;
   for (i=0; i<NTYPES; i++)
      gtk_widget_hide(id_types[i]);

   int imax;
   if (nthemes > NTYPES)
      imax = NTYPES;
   else
      imax = nthemes;

   for (i=0; i<imax; i++)
   {
      char *location = xpenguins_theme_directory(allthemenames[i]);
      if (! location)
	 continue;
      P("theme: %s: %s\n",allthemenames[i],location);
      char **info = xpenguins_theme_info(allthemenames[i]);

      P("icon: %s\n",info[PENGUIN_ICON]);
      gtk_image_set_from_file(GTK_IMAGE(id_icons[i]),info[PENGUIN_ICON]);
      gtk_widget_show_all(id_types[i]);

      g_signal_connect(id_types[i],"toggled",G_CALLBACK(buttoncb),allthemenames[i]);

      char text[1024];
      snprintf(text, 1000, 
	    "Theme:\t\t%s\n"      
	    "Date:\t\t%s\n"       
	    "Artist(s):\t\t%s\n"  
	    "Copyright:\t%s\n"  
	    "License:\t\t%s\n"    
	    "Maintainer:\t%s\n" 
	    "Location:\t\t%s\n"   
	    "Icon:\t\t%s\n"       
	    "Comment:\t%s",  

	    xpenguins_remove_underscores(allthemenames[i]),
	    info[PENGUIN_DATE],
	    info[PENGUIN_ARTIST],
	    info[PENGUIN_COPYRIGHT],
	    info[PENGUIN_LICENSE],
	    info[PENGUIN_MAINTAINER],
	    location,
	    info[PENGUIN_ICON],
	    info[PENGUIN_COMMENT]);                      

      gtk_widget_set_tooltip_text(GTK_WIDGET(id_types[i]),text);
   }
   //gtk_widget_set_tooltip_text(GTK_WIDGET(id_types[1]),"Hallo\nhello");
}

void init_ids()
{
   id_lift          = GTK_WIDGET(gtk_builder_get_object(builder, "id-lift"));
   id_liftvalue     = GTK_WIDGET(gtk_builder_get_object(builder, "id-liftvalue"));
   id_penguin       = GTK_WIDGET(gtk_builder_get_object(builder, "id-penguin"));
   id_penguinvalue  = GTK_WIDGET(gtk_builder_get_object(builder, "id-penguinvalue"));
   id_logo1         = GTK_WIDGET(gtk_builder_get_object(builder, "id-logo1"));
   id_logo2         = GTK_WIDGET(gtk_builder_get_object(builder, "id-logo2"));
   id_logo3         = GTK_WIDGET(gtk_builder_get_object(builder, "id-logo3"));
   id_angel_picture = GTK_WIDGET(gtk_builder_get_object(builder, "id-angel-picture"));
   id_splat_picture = GTK_WIDGET(gtk_builder_get_object(builder, "id-splat-picture"));
   id_speed         = GTK_WIDGET(gtk_builder_get_object(builder, "id-speed"));
   id_speedvalue    = GTK_WIDGET(gtk_builder_get_object(builder, "id-speedvalue"));
   id_angels        = GTK_WIDGET(gtk_builder_get_object(builder, "id-angels"));
   id_blood         = GTK_WIDGET(gtk_builder_get_object(builder, "id-blood"));

   int i;
   for (i=0; i<NTYPES; i++)
   {
      char buf[100];
      sprintf(buf,"id-type%d",i);
      id_types[i] = GTK_WIDGET(gtk_builder_get_object(builder, buf));
      sprintf(buf,"id-icon%d",i);
      id_icons[i] = GTK_WIDGET(gtk_builder_get_object(builder,buf));
   }
}

void init_pixmaps()
{
   GdkPixbuf *pixbuf, *pixbuf1;
   pixbuf  = gdk_pixbuf_new_from_xpm_data ((const char **)xpenguins);
   pixbuf1 = gdk_pixbuf_scale_simple(pixbuf,64,64,GDK_INTERP_BILINEAR);
   gtk_image_set_from_pixbuf(GTK_IMAGE(id_logo1),pixbuf1);
   gtk_image_set_from_pixbuf(GTK_IMAGE(id_logo2),pixbuf1);
   gtk_image_set_from_pixbuf(GTK_IMAGE(id_logo3),pixbuf1);

   g_object_unref(pixbuf);
   g_object_unref(pixbuf1);

   pixbuf  = gdk_pixbuf_new_from_xpm_data ((const char **)button_angel);
   pixbuf1 = gdk_pixbuf_scale_simple(pixbuf,52,32,GDK_INTERP_BILINEAR);
   gtk_image_set_from_pixbuf(GTK_IMAGE(id_angel_picture),pixbuf1);

   g_object_unref(pixbuf);
   g_object_unref(pixbuf1);

   pixbuf  = gdk_pixbuf_new_from_xpm_data ((const char **)button_splat);
   pixbuf1 = gdk_pixbuf_scale_simple(pixbuf,52,17,GDK_INTERP_BILINEAR);
   gtk_image_set_from_pixbuf(GTK_IMAGE(id_splat_picture),pixbuf1);

   g_object_unref(pixbuf);
   g_object_unref(pixbuf1);

}

void set_buttons()
{

   int h = human_action;
   human_action = 0;
   gtk_range_set_value(GTK_RANGE(id_lift), toon_lift);
   sprintf(buf,"%d",toon_lift);
   gtk_label_set_text(GTK_LABEL(id_liftvalue),buf);

   gtk_range_set_value(GTK_RANGE(id_penguin), npenguins_to_scale(npenguins));
   sprintf(buf,"%d",npenguins);
   gtk_label_set_text(GTK_LABEL(id_penguinvalue),buf);

   gtk_range_set_value(GTK_RANGE(id_speed),speedfactor_to_scale(SpeedFactor));
   sprintf(buf,"%d",(int)(100*SpeedFactor));
   gtk_label_set_text(GTK_LABEL(id_speedvalue),buf);

   gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(id_angels), xpenguins_angels);

   gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(id_blood), xpenguins_blood);

   char **t;
   for (t = ThemeNames; *t; t++)
   {
      P("set_buttons theme: %s\n",*t);
      char **s;
      int k = 0;
      for (s = allthemenames; *s; s++,k++)
      {
	 if (!strcmp(*t,*s))
	    break;
      }
      P("set_buttons: found: %d '%s'\n",k,*s);
      gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(id_types[k]),True);
   }

   human_action = h;

   FlagsChanged = 1;
}

MODULE_EXPORT void button_lift(GtkWidget *w)
{
   if (!human_action)
      return;
   int value = gtk_range_get_value(GTK_RANGE(w));
   apply_lift(value);
   sprintf(buf,"%d",value);
   gtk_label_set_text(GTK_LABEL(id_liftvalue),buf);
}

MODULE_EXPORT void button_penguins(GtkWidget *w)
{
   if (!human_action)
      return;
   float value = gtk_range_get_value(GTK_RANGE(w));
   P("penguins: %f\n",value);
   xpenguins_set_number(scale_to_npenguins(value));
   // see toon_draw: ToonDraw()
   // after removing penguins, often remains stay in the window
   ConditionalClear = 1;
   npenguins = scale_to_npenguins(value);
   FlagsChanged = 1;

   sprintf(buf,"%d",npenguins);
   gtk_label_set_text(GTK_LABEL(id_penguinvalue),buf);
}

MODULE_EXPORT void button_speed(GtkWidget *w)
{
   if (!human_action)
      return;
   float value = gtk_range_get_value(GTK_RANGE(w));
   SpeedFactor = scale_to_speedfactor(value);
   P("speed: %f %f\n",value,SpeedFactor);
   FlagsChanged = 1;

   sprintf(buf,"%d",(int)(100*SpeedFactor));
   gtk_label_set_text(GTK_LABEL(id_speedvalue),buf);
}


MODULE_EXPORT void button_defaults()
{
   ClearScreen();
   if (!human_action)
      return;
   apply_lift(0);

   xpenguins_angels = 1;
   xpenguins_blood  = 1;

   set_default_delay();

   SpeedFactor = 1;

   npenguins = default_penguin_number();
   xpenguins_set_number(npenguins);

   set_buttons();
}

MODULE_EXPORT void button_iconify()
{
   if (!human_action)
      return;
   gtk_window_iconify(GTK_WINDOW(hauptfenster));
}

MODULE_EXPORT void button_angels(GtkWidget *w)
{
   if (!human_action)
      return;
   int value = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w));
   P("angels: %d\n",value);
   xpenguins_angels = value;
   FlagsChanged = 1;
}

MODULE_EXPORT void button_blood(GtkWidget *w)
{
   if (!human_action)
      return;
   int value = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w));
   P("blood: %d\n",value);
   xpenguins_blood = value;
   FlagsChanged = 1;
}

FILE *openflagsfile(char *mode)
{
   char *h = getenv("HOME");
   if (h == NULL)
      return NULL;
   char *flagsfile = (char*)malloc((strlen(h)+strlen(FLAGSFILE)+2)*sizeof(char));
   flagsfile[0] = 0;
   strcat(flagsfile,h);
   strcat(flagsfile,"/");
   strcat(flagsfile,FLAGSFILE);
   FILE *f = fopen(flagsfile,mode);
   P("openflagsfile %s %s\n",flagsfile,mode);
   free(flagsfile);
   return f;
}

void ReadFlags()
{
   ThemeFound = 0;
   FILE *f = openflagsfile(_("r"));
   if (f == NULL)
   {
      I("Cannot read $HOME/%s\n",FLAGSFILE);
      return;
   }
   int lineno     = 1;
   while(1)
   {
      char *line = NULL;
      size_t n = 0;
      int m = getline(&line,&n,f);
      if (m<0)
	 break;
      P("ReadFlags: %d [%s]\n",lineno,line);
      char *flag = (char*)malloc((strlen(line)+1)*sizeof(char));
      m = sscanf(line, "%s", flag);
      if (m == EOF || m == 0)
	 continue;
      char *rest = line + strlen(flag);

      char *p;
      p = rest;
      while (*p == ' ' || *p == '\t' || *p == '\n')
	 p++;
      rest = p;
      p = &line[strlen(line)-1];
      while (*p == ' ' || *p == '\t' || *p == '\n')
	 p--;
      *(p+1) = 0;

      P("ReadFlags: %s [%s]\n",flag,rest);
      if (!strcmp(flag,"--lift"))
      {
	 toon_lift = atoi(rest);
	 P("toon_lift: %d\n",toon_lift);
      }
      else if(!strcmp(flag,"--no-angels"))
      {
	 xpenguins_angels = atoi(rest);
	 P("xpenguins_angels: %d\n",xpenguins_angels);
      }
      else if(!strcmp(flag,"--no-blood"))
      {
	 xpenguins_blood = atoi(rest);
	 P("xpenguins_blood: %d\n",xpenguins_blood);
      }
      else if(!strcmp(flag,"--penguins"))
      {
	 npenguins = atoi(rest);
	 P("npenguins: %d\n",npenguins);
      }
      else if(!strcmp(flag,"--delay"))
      {
	 time_move = atoi(rest);
	 P("delay: %d\n",time_move);
      }
      else if(!strcmp(flag,"--speed"))
      {
	 SpeedFactor = 0.01*atoi(rest);
	 P("speed: %d\n",time_move);
      }
      else if (!strcmp(flag,"--theme"))
      {
	 P("theme: '%s'\n",rest);
	 P("ThemeNames:\n"); //xpenguins_print_list(ThemeNames);
	 if(!ThemeFound)
	 {
	    xpenguins_free_list(ThemeNames);
	    ThemeNames = NULL;
	 }
	 ThemeFound = 1;
	 int n = 0;
	 if(ThemeNames)
	 {
	    char **t;
	    for(t=ThemeNames; *t; t++)
	       n++;
	 }
	 ThemeNames = (char**)realloc(ThemeNames,(n+2)*sizeof(char*));
	 ThemeNames[n] = strdup(rest);
	 ThemeNames[n+1] = NULL;
	 P("ThemeNames:%d\n",n); // xpenguins_print_list(ThemeNames);
      }
      lineno++;
      free(line);
      free(flag);
   }
   fclose(f);
}

void WriteFlags()
{
   FILE *f = openflagsfile(_("w"));
   if (f == NULL)
   {
      I("Cannot write $HOME/%s\n",FLAGSFILE);
      return;
   }
   fprintf(f,"--lift %d\n",toon_lift);
   fprintf(f,"--no-angels %d\n",xpenguins_angels);
   fprintf(f,"--no-blood %d\n",xpenguins_blood);
   fprintf(f,"--penguins %d\n",npenguins);
   fprintf(f,"--delay %d\n",time_move);
   fprintf(f,"--speed %d\n",(int)(100*SpeedFactor));
   char **t;
   for (t=ThemeNames; *t; t++)
      fprintf(f,"--theme %s\n",*t);
   fclose(f);
}

float speedfactor_to_scale(float speed)
{
   float a,b;
   ab(MaxSpeedFactor, MinSpeedFactor,&a,&b);
   return mylog10f((speed-b)/(a*MaxSpeedFactor));
}

float scale_to_speedfactor(float scale)
{
   float a,b;
   ab(MaxSpeedFactor, MinSpeedFactor,&a,&b);
   return a * MaxSpeedFactor*myexp10f(scale) + b; 
}

float npenguins_to_scale(float n)
{
   float a,b;
   ab(MaxNPenguins, MinNPenguins, &a, &b);
   return mylog10f((n-b)/(a*MaxNPenguins));
}

float scale_to_npenguins(float scale)
{
   float a,b;
   ab(MaxNPenguins, MinNPenguins, &a, &b);
   return a * MaxNPenguins*myexp10f(scale) + b; 
}

void iconify()
{
   gtk_window_iconify(GTK_WINDOW(hauptfenster));
}

void ui()
{

   builder = gtk_builder_new_from_string (xpenguins_xml, -1);
   gtk_builder_connect_signals (builder, builder);
   hauptfenster  = GTK_WIDGET(gtk_builder_get_object(builder, "hauptfenster"));

   hauptfenstersc  = gtk_widget_get_style_context(hauptfenster);

   handle_css();
   char wtitle[100];
   wtitle[0] = 0;
   strcat(wtitle,"XpenguinS");
#ifdef HAVE_CONFIG_H
   strcat(wtitle,"-");
   strncat(wtitle,VERSION,99 - strlen(wtitle));
#endif
   gtk_window_set_title(GTK_WINDOW(hauptfenster),wtitle);
   gtk_window_set_resizable(GTK_WINDOW(hauptfenster),False);
   gtk_widget_show_all (hauptfenster);
   g_signal_connect (GTK_WINDOW(hauptfenster), "delete-event", G_CALLBACK (gtk_main_quit), NULL);
   g_signal_connect (GTK_WINDOW(hauptfenster), "destroy", G_CALLBACK (gtk_main_quit), NULL);

   init_ids();
   init_buttons();

   init_pixmaps();
   set_buttons();
}

