/*
* File name: mdispgtkapp.cpp
* Location: See Matrox Example Launcher in the MIL Control Center
* 
*/
//
// Copyright (C) Matrox Electronic Systems Ltd., 1992-2020.
// All Rights Reserved
#include <mil.h>
#include <gtk/gtk.h>
#include <X11/Xlib.h>
#include <stdlib.h>
#include "mainframe.h"
#include "mdispgtkapp.h"

static gint MessageBox(GtkWindow *parent, gchar *text,GtkMessageType messagetype,GtkButtonsType buttonstype)
   {
   GtkWidget *dialog;
   gint result;
   dialog = gtk_message_dialog_new (GTK_WINDOW(parent),
                                    GTK_DIALOG_DESTROY_WITH_PARENT,
                                    messagetype,
                                    buttonstype,
                                    "%s",
                                    text);
   gtk_window_set_title(GTK_WINDOW(dialog),"MIL Error");
   result=gtk_dialog_run (GTK_DIALOG (dialog));
   gtk_widget_destroy (dialog);
   return result;
   }

static gboolean RunDialog(gpointer user_data)
   {
   DialogData *data = (DialogData *) user_data;
   g_return_val_if_fail(data, FALSE);
   
   g_mutex_lock (&data->mutex);
   data->Result = MessageBox(data->Parent, data->Text, data->MessageType, data->ButtonsType);
   data->Done = TRUE;
   g_cond_signal (&data->cond);
   g_mutex_unlock (&data->mutex);

   return FALSE;
   }
MdispGtkApp::MdispGtkApp(GtkApplication *gtkApp)
   {
   m_GtkApp = gtkApp;
   m_MainFrame = NULL;
   m_MainThread  = g_thread_self();
   m_isCurrentlyHookedOnErrors = false;
   InitInstance();
   

   }

MdispGtkApp::~MdispGtkApp()
   {
   ExitInstance();
   
   if(m_MainFrame)
      delete m_MainFrame;
   
   m_MainFrame = NULL;
   }

void MdispGtkApp::InitWindow()
   {
   m_MainFrame = new MainFrame(m_GtkApp);   
   g_object_set_data(G_OBJECT(m_MainFrame->MainWindow()),"App",(void *)this);   
   }

bool MdispGtkApp::InitInstance()
   {
   // Allocate an application and system [CALL TO MIL]
   MappAllocDefault(M_DEFAULT, &m_MilApplication, &m_MilSystem, M_NULL, M_NULL, M_NULL);

   // Hook MIL error on function DisplayError() [CALL TO MIL]
   MappHookFunction(M_DEFAULT, M_ERROR_CURRENT,DisplayErrorExt,this);

   m_isCurrentlyHookedOnErrors = true;
   
   // Disable MIL error message to be displayed as the usual way [CALL TO MIL]
   MappControl(M_DEFAULT, M_ERROR,M_PRINT_DISABLE);
 
   // Inquire number of digitizers available on the system [CALL TO MIL]
   MsysInquire(m_MilSystem,M_DIGITIZER_NUM,&m_numberOfDigitizer);
   
   // Digitizer is available
   if (m_numberOfDigitizer)  
      {
      // Allocate a digitizer [CALL TO MIL]
      MdigAlloc(m_MilSystem,M_DEFAULT,MIL_TEXT("M_DEFAULT"),M_DEFAULT,&m_MilDigitizer);
      
      // Inquire digitizer informations [CALL TO MIL]
      MdigInquire(m_MilDigitizer,M_SIZE_X,&m_digitizerSizeX);
      MdigInquire(m_MilDigitizer,M_SIZE_Y,&m_digitizerSizeY);    
      MdigInquire(m_MilDigitizer,M_SIZE_BAND,&m_digitizerNbBands);
      }

   // Initialize the state of the grab
   m_isGrabStarted = false;
   return true;
   }

bool MdispGtkApp::ExitInstance()
   {
   /////////////////////////////////////////////////////////////////////////
   // MIL: Write your code that will be executed on application exit
   /////////////////////////////////////////////////////////////////////////  
       
   //Free the digitizer [CALL TO MIL]
   if(m_MilDigitizer)    
      MdigFree (m_MilDigitizer);  
   
   //Free the system [CALL TO MIL]
   if(m_MilSystem)
      MsysFree (m_MilSystem);
   
   
   if(m_MilApplication)  
      {
      // Enable MIL error message to be displayed as the usual way [CALL TO MIL]
      MappControl(M_DEFAULT, M_ERROR,M_PRINT_ENABLE);
      
      // Unhook MIL error on function DisplayError() [CALL TO MIL]
      if(m_isCurrentlyHookedOnErrors)
         {
         //MappHookFunction(M_DEFAULT, M_ERROR_CURRENT+M_UNHOOK,DisplayErrorExt,pMdispGtkView);
         m_isCurrentlyHookedOnErrors = false;
         }
      
      // Free the application [CALL TO MIL]
      MappFree(m_MilApplication);
      }
   
   /////////////////////////////////////////////////////////////////////////
   // MIL: Write your code that will be executed on application exit
   /////////////////////////////////////////////////////////////////////////
   return true;
   }

long MFTYPE MdispGtkApp::DisplayErrorExt(long HookType, MIL_ID EventId, void* UserDataPtr)
   {
   MdispGtkApp* UserData = (MdispGtkApp *) UserDataPtr;
   //If user clicks NO on error message, unhook to errors.
   if(UserData->DisplayError(HookType,EventId, UserDataPtr) == GTK_RESPONSE_NO)
      {
      MappHookFunction(M_DEFAULT, M_ERROR_CURRENT+M_UNHOOK,DisplayErrorExt,UserDataPtr);
      UserData->HookedOnErrors(false);
      }

   return M_NULL;
}

long MFTYPE MdispGtkApp::DisplayError(MIL_INT HookType, MIL_ID EventId, void* UserDataPtr)
   {
   char  ErrorMessageFunction[M_ERROR_MESSAGE_SIZE] = "";
   char  ErrorMessage[M_ERROR_MESSAGE_SIZE]         = "";
   char  ErrorSubMessage1[M_ERROR_MESSAGE_SIZE]     = "";
   char  ErrorSubMessage2[M_ERROR_MESSAGE_SIZE]     = "";
   char  ErrorSubMessage3[M_ERROR_MESSAGE_SIZE]     = "";
   long  NbSubCode;
   GString  *GErrorMessage;
   gint result = GTK_RESPONSE_YES;

   GErrorMessage=g_string_new(NULL);
   
   //Retrieve error message [CALL TO MIL]
   MappGetHookInfo(M_DEFAULT, EventId,M_MESSAGE+M_CURRENT_FCT,ErrorMessageFunction);
   MappGetHookInfo(M_DEFAULT, EventId,M_MESSAGE+M_CURRENT,ErrorMessage);
   MappGetHookInfo(M_DEFAULT, EventId,M_CURRENT_SUB_NB,&NbSubCode);

   if (NbSubCode > 2)
      MappGetHookInfo(M_DEFAULT, EventId,M_MESSAGE+M_CURRENT_SUB_3,ErrorSubMessage3);
   if (NbSubCode > 1)
      MappGetHookInfo(M_DEFAULT, EventId,M_MESSAGE+M_CURRENT_SUB_2,ErrorSubMessage2);
   if (NbSubCode > 0)
      MappGetHookInfo(M_DEFAULT, EventId,M_MESSAGE+M_CURRENT_SUB_1,ErrorSubMessage1);

   GErrorMessage = g_string_append(GErrorMessage,ErrorMessageFunction);
   GErrorMessage = g_string_append(GErrorMessage ,"\n");
   GErrorMessage = g_string_append(GErrorMessage ,ErrorMessage);

   if(NbSubCode > 0)
      {
      GErrorMessage = g_string_append(GErrorMessage , "\n");
      GErrorMessage = g_string_append(GErrorMessage , ErrorSubMessage1);
      }
   
   if(NbSubCode > 1)
      {
      GErrorMessage = g_string_append(GErrorMessage , "\n");
      GErrorMessage = g_string_append(GErrorMessage , ErrorSubMessage2);
      }
   
   if(NbSubCode > 2)
      {
      GErrorMessage = g_string_append(GErrorMessage , "\n");
      GErrorMessage = g_string_append(GErrorMessage , ErrorSubMessage3);
      }
   
   GErrorMessage = g_string_append(GErrorMessage , "\n\n");
   GErrorMessage = g_string_append(GErrorMessage , "Do you want to continue error print?");
   
   if ( m_MainThread == g_thread_self())
      {
      if (m_MainFrame && GTK_IS_WINDOW(m_MainFrame->MainWindow()))
         result = MessageBox(GTK_WINDOW(m_MainFrame->MainWindow()), GErrorMessage->str, GTK_MESSAGE_QUESTION, GTK_BUTTONS_YES_NO);
      else
         result = MessageBox(NULL, GErrorMessage->str, GTK_MESSAGE_QUESTION, GTK_BUTTONS_YES_NO);
      }
   else
      {
      DialogData *data;
      
      data = g_new0 (DialogData, 1);
      data->Parent = GTK_WINDOW(m_MainFrame->MainWindow());
      data->MessageType = GTK_MESSAGE_QUESTION;
      data->ButtonsType = GTK_BUTTONS_YES_NO;
      data->Text = GErrorMessage->str;
      data->Done = FALSE;

      g_mutex_init (&data->mutex);
      g_cond_init (&data->cond);
      g_mutex_lock (&data->mutex);

      g_main_context_invoke (NULL, RunDialog, data);

      while (!data->Done)
         g_cond_wait (&data->cond, &data->mutex);

      result = data->Result;
      g_mutex_unlock (&data->mutex);
      g_mutex_clear (&data->mutex);
      g_cond_clear (&data->cond);

      g_free (data);
      }
   
   g_string_free(GErrorMessage,TRUE);
   
   return result;
   }