/************************************************************
**
** Application: UnitConv
**
** Title:       c.gases
**
*************************************************************/

/*
*
* Copyright (c) 2015, Chris Johnson
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*   * Redistributions of source code must retain the above copyright
*     notice, this list of conditions and the following disclaimer.
*   * Redistributions in binary form must reproduce the above
*     copyright notice, this list of conditions and the following
*     disclaimer in the documentation and/or other materials provided
*     with the distribution.
*   * Neither the name of the copyright holder nor the names of their
*     contributors may be used to endorse or promote products derived
*     from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDER BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/

/* Include files */
/* from standard clib */
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>

/* from oslib */
#include "OSLib:button.h"
#include "OSLib:displayfield.h"
#include "OSLib:menu.h"
#include "OSLib:os.h"
#include "OSLib:popup.h"
#include "OSLib:wimp.h"
#include "OSLib:window.h"
#include "OSLib:writablefield.h"

/* from oslib support */
#include "OSLibSupport:event.h"

/* from CJLib */
#include "CJLib:tbox.h"
#include "CJLib:message.h"
#include "CJLib:etc.h"

/* from app  */
#include "iconbar.h"
#include "cjoslib.h"
#include "gases.h"
#include "msglink.h"
#include "main.h"

/************************************************************/

/* Local defines */

        // Gases window
#define GASES_TEMPLATE          ((toolbox_id)"Gases")
#define GASES_DIAM_MENUTEMPLATE  ((toolbox_id)"DiameterM")
#define GASES_XSEC_MENUTEMPLATE  ((toolbox_id)"XsectionM")

#define GASES_TEMP              ((toolbox_c)0x0A)
#define GASES_PRESS             ((toolbox_c)0x0B)
#define GASES_DIAM              ((toolbox_c)0x0C)
#define GASES_MASS              ((toolbox_c)0x0D)
#define GASES_MFP               ((toolbox_c)0x10)
#define GASES_RMS               ((toolbox_c)0x11)
#define GASES_AVE               ((toolbox_c)0x12)
#define GASES_MOSTPROB          ((toolbox_c)0x13)
#define GASES_COLFREQ           ((toolbox_c)0x14)
#define GASES_TOTCOLL           ((toolbox_c)0x15)
#define GASES_PRESSLABEL        ((toolbox_c)0x11A)
#define GASES_SIZELABEL         ((toolbox_c)0x11B)
#define GASES_POPUP_PRESSURE    ((toolbox_c)0x0E)
#define GASES_POPUP_SIZE        ((toolbox_c)0x0F)
#define uevent_GASES_CALC       0x040
#define uevent_GASES_USEATM     0x041
#define uevent_GASES_USEN       0x042
#define uevent_GASES_USETORR    0x043
#define uevent_GASES_USEDIAMPM  0x044
#define uevent_GASES_USEDIAMNM  0x045
#define uevent_GASES_USEDIAMM   0x046
#define uevent_GASES_USEXSECTPM 0x047
#define uevent_GASES_USEXSECTNM 0x048
#define uevent_GASES_USEXSECTM  0x049

//////#define PI              3.141592654
#define BOLTZMANN_K     1.38066E-23
#define RMS_FACTOR      157.9351133
#define MEAN_FACTOR     145.5084203
#define PROB_FACTOR     128.95348
#define ROOT_2          1.414213562

#define PRESS_FROM_ATM  101325
#define PRESS_FROM_TORR 133.3223684

#define MFP_FACTOR      9.762740485E-24 // BOLTZMANN_K/ROOT_2

#define TXBUF_SIZE 16

/************************************************************/
/* global variables */

static toolbox_o Gases_winid;
static wimp_w    Gases_winhandle;
static toolbox_position Gases_win_pos;
static toolbox_o Gases_PressureMenuID;
static toolbox_o Gases_SizeMenuID;
static toolbox_o Gases_DiameterMenuID;
static toolbox_o Gases_XsectionMenuID;
static osbool Gases_size_diameter;
static unsigned int Gases_pres_flag;
static unsigned int Gases_xsect_flag;


// the functions



/************************************************************/

static void Gases_Calculate ( void )
{
  char  txbuf [TXBUF_SIZE] ;
  int used ;
  double temperature,
         pressure,
         mass,
         cross_section ;

  double root_T_over_m,
         c_bar,
         rms,
         most_prob,
         mfp,
         temp,
         temp2 ;



  /* get the text from the writables */
  /* first the temperature */
  used = writablefield_get_value ( 0, Gases_winid, GASES_TEMP, txbuf, TXBUF_SIZE ) ;
  if ( used == 1 )
  {
    Msg_Warn ( NOTEMP );
    /* no entry for temp */
    return ;
  }
  else
  {
    temperature = atof ( txbuf ) ;
    if ( temperature <= 0 )
    {
      Msg_Warn ( INVALTEMP );
      return ;
    }
  }

  /* now the pressure */
  used = writablefield_get_value ( 0, Gases_winid, GASES_PRESS, txbuf, TXBUF_SIZE ) ;
  if ( used == 1 )
  {
    pressure = 0 ;
  }
  else
  {
    pressure = atof ( txbuf ) ;
  }

  /* now the diameter/cross-section */
  used = writablefield_get_value ( 0, Gases_winid, GASES_DIAM, txbuf, TXBUF_SIZE ) ;
  if ( used == 1 )
  {
    cross_section = 0 ;
  }
  else
  {
    cross_section = atof ( txbuf ) ;
  }

  /* now the relative molar mass */
  used = writablefield_get_value ( 0, Gases_winid, GASES_MASS, txbuf, TXBUF_SIZE ) ;
  if ( used == 1 )
  {
    mass = 0 ;
  }
  else
  {
    mass = atof ( txbuf ) ;
  }


  /* now do the calculations */
  /* use the mass to find the molecular speeds */
  if ( mass > 0 )
  {
    root_T_over_m = sqrt ( temperature / mass ) ;
    c_bar = root_T_over_m * MEAN_FACTOR ;
    rms = root_T_over_m * RMS_FACTOR ;
    most_prob = root_T_over_m * PROB_FACTOR ;
    /* now fill in the result fields */
    sprintf ( txbuf, "%.4g", rms ) ;
    displayfield_set_value ( 0, Gases_winid, GASES_RMS, txbuf ) ;
    sprintf ( txbuf, "%.4g", c_bar ) ;
    displayfield_set_value ( 0, Gases_winid, GASES_AVE,txbuf ) ;
    sprintf ( txbuf, "%.4g", most_prob ) ;
    displayfield_set_value ( 0, Gases_winid, GASES_MOSTPROB, txbuf ) ;
  }
  else
  {
    /* blank appropriate fields as can't do calculation */
    displayfield_set_value ( 0, Gases_winid, GASES_RMS, "" ) ;
    displayfield_set_value ( 0, Gases_winid, GASES_AVE, "" ) ;
    displayfield_set_value ( 0, Gases_winid, GASES_MOSTPROB, "" ) ;
    c_bar = 0 ;
  }

  if ( ( pressure > 0 ) && ( cross_section > 0 ) )
  {
    /* Convert pressure to N/m2 */
    switch ( Gases_pres_flag )
    {
      case PRES_ATM:
        pressure *= PRESS_FROM_ATM ;
        break ;

      case PRES_TORR:
        pressure *= PRESS_FROM_TORR ;
        break ;
    }
    /* Convert size as diameter to cross-section */
    if ( Gases_size_diameter )
    {
      cross_section = PI * cross_section * cross_section ;
    }
    /* Convert cross-section units to metre */
    switch ( Gases_xsect_flag )
    {
      case XSECT_PM:
        cross_section *= 1e-24 ;
        break ;

      case XSECT_NM:
        cross_section *= 1e-18 ;
        break ;
    }
    /* calculate mean free path */
    mfp = MFP_FACTOR * temperature / cross_section / pressure ;
    sprintf ( txbuf, "%.4g", mfp ) ;
    displayfield_set_value ( 0, Gases_winid, GASES_MFP, txbuf ) ;
    if ( c_bar > 0 )
    {
      temp = pressure / BOLTZMANN_K / temperature ;
      temp2 = ROOT_2 * cross_section * c_bar * temp ;
      sprintf ( txbuf, "%.4g", temp2 ) ;
      displayfield_set_value ( 0, Gases_winid, GASES_COLFREQ, txbuf ) ;
      temp2 = temp2 * temp / 2 ;
      sprintf ( txbuf, "%.4g", temp2 ) ;
      displayfield_set_value ( 0, Gases_winid, GASES_TOTCOLL, txbuf ) ;
    }
    else
    {
      displayfield_set_value ( 0, Gases_winid, GASES_COLFREQ, "" ) ;
      displayfield_set_value ( 0, Gases_winid, GASES_TOTCOLL, "" ) ;
    }

  }
  else
  {
    /* blank the results fields */
    displayfield_set_value ( 0, Gases_winid, GASES_MFP, "" ) ;
    displayfield_set_value ( 0, Gases_winid, GASES_COLFREQ, "" ) ;
    displayfield_set_value ( 0, Gases_winid, GASES_TOTCOLL, "" ) ;
  }


  return ;
}






/************************************************************/

static void Gases_SetPressure ( bits event )
{
  switch ( event )
  {
  case uevent_GASES_USEATM:
    Gases_pres_flag = PRES_ATM ;
    button_set_value ( 0,
                       Gases_winid,
                       GASES_PRESSLABEL,
                       "Pressure/atm" ) ;
    break ;

  case uevent_GASES_USEN:
    Gases_pres_flag = PRES_N ;
    button_set_value ( 0,
                       Gases_winid,
                       GASES_PRESSLABEL,
                       "Pressure/N m-" ) ;
    break ;

  case uevent_GASES_USETORR:
    Gases_pres_flag = PRES_TORR ;
    button_set_value ( 0,
                       Gases_winid,
                       GASES_PRESSLABEL,
                       "Pressure/torr" ) ;
    break ;
  }
  return ;
}






/************************************************************/

static osbool Gases_PressureMenuHandler ( bits event_code,
                                          toolbox_action *action,
                                          toolbox_block *id_block,
                                          void *handle )
{
  switch (event_code)
  {
    case uevent_GASES_USEATM:
    case uevent_GASES_USEN:
    case uevent_GASES_USETORR:
      Gases_SetPressure ( event_code ) ;
      break ;

    case action_MENU_DIALOGUE_COMPLETED:
      event_deregister_toolbox_handler ( Gases_PressureMenuID,
                                       action_ANY,
                                       Gases_PressureMenuHandler,
                                       NULL );
      break;
  }

  return (TRUE);

  /* for compiler */
  IGNORE (handle);
  IGNORE (id_block);
  IGNORE (action);
}





/************************************************************/

static void Gases_SetSizeDiameter ( bits event )
{

  switch ( event )
  {
  case uevent_GASES_USEDIAMPM:
    Gases_xsect_flag = XSECT_PM ;
    button_set_value ( 0,
                       Gases_winid,
                       GASES_SIZELABEL,
                       "Molecular diameter/pm" ) ;
    break ;

  case uevent_GASES_USEDIAMNM:
    Gases_xsect_flag = XSECT_NM ;
    button_set_value ( 0,
                       Gases_winid,
                       GASES_SIZELABEL,
                       "Molecular diameter/nm" ) ;
    break ;

  case uevent_GASES_USEDIAMM:
    Gases_xsect_flag = XSECT_M ;
    button_set_value ( 0,
                       Gases_winid,
                       GASES_SIZELABEL,
                       "Molecular diameter/m" ) ;
    break ;


  }
  return ;
}





/************************************************************/

static osbool Gases_DiameterMenuHandler ( bits event_code,
                                          toolbox_action *action,
                                          toolbox_block *id_block,
                                          void *handle )
{
  switch (event_code)
  {
    case uevent_GASES_USEDIAMPM:
    case uevent_GASES_USEDIAMNM:
    case uevent_GASES_USEDIAMM:
      Gases_size_diameter = TRUE ;
      Gases_SetSizeDiameter ( event_code ) ;
      break;
  }

  return (TRUE);

  /* for compiler */
  IGNORE (handle);
  IGNORE (id_block);
  IGNORE (action);
}




/************************************************************/

static void Gases_SetSizeXsection ( bits event )
{

  switch ( event )
  {
    case uevent_GASES_USEXSECTPM:
      Gases_xsect_flag = XSECT_PM ;
      button_set_value ( 0,
                         Gases_winid,
                         GASES_SIZELABEL,
                         "Molecular xsection/(pm)" ) ;
      break ;

    case uevent_GASES_USEXSECTNM:
      Gases_xsect_flag = XSECT_NM ;
      button_set_value ( 0,
                         Gases_winid,
                         GASES_SIZELABEL,
                         "Molecular xsection/(nm)" ) ;
      break ;

    case uevent_GASES_USEXSECTM:
      Gases_xsect_flag = XSECT_M ;
      button_set_value ( 0,
                         Gases_winid,
                         GASES_SIZELABEL,
                         "Molecular xsection/m" ) ;
      break ;

  }
  return ;
}




/************************************************************/

static osbool Gases_XsectionMenuHandler ( bits event_code,
                                          toolbox_action *action,
                                          toolbox_block *id_block,
                                          void *handle )
{
  switch (event_code)
  {
    case uevent_GASES_USEXSECTPM:
    case uevent_GASES_USEXSECTNM:
    case uevent_GASES_USEXSECTM:
      Gases_size_diameter = FALSE ;
      Gases_SetSizeXsection ( event_code ) ;
      break;
  }

  return (TRUE);

  /* for compiler */
  IGNORE (handle);
  IGNORE (id_block);
  IGNORE (action);
}




/************************************************************/

static osbool Gases_SizeMenuHandler ( bits event_code,
                                          toolbox_action *action,
                                          toolbox_block *id_block,
                                          void *handle )
{
  switch (event_code)
  {
    case action_MENU_DIALOGUE_COMPLETED:
      event_deregister_toolbox_handler ( Gases_SizeMenuID,
                                       action_ANY,
                                       Gases_SizeMenuHandler,
                                       NULL );
      event_deregister_toolbox_handler ( Gases_DiameterMenuID,
                                       action_ANY,
                                       Gases_DiameterMenuHandler,
                                       NULL );
      event_deregister_toolbox_handler ( Gases_XsectionMenuID,
                                       action_ANY,
                                       Gases_XsectionMenuHandler,
                                       NULL );
      break;
  }

  return (TRUE);

  /* for compiler */
  IGNORE (handle);
  IGNORE (id_block);
  IGNORE (action);
}






/************************************************************/

static osbool Gases_KeyPress ( wimp_event_no event,
                                  wimp_block * blk,
                                  toolbox_block * id_block,
                                  void * handle )
{
  wimp_key *wkey;

  wkey = (wimp_key*)blk;
  if (wkey->c == wimp_KEY_F1)
    IconbarShowHelp();
  else
  if (( wkey->c < 32 ) || ( wkey->c > 126 ))
    wimp_process_key (wkey->c);

  return (TRUE);

  /* for compiler */
  IGNORE (handle);
  IGNORE (id_block);
  IGNORE (event);
}




/************************************************************/

static osbool Gases_Handler ( bits event_code,
                                  toolbox_action *action,
                                  toolbox_block *id_block,
                                  void *handle )
{
  PopUpAboutToBeShownBlock *popupblk;


  switch (event_code)
  {

    case uevent_GASES_CALC:
      Gases_Calculate ( ) ;
      break ;

    case action_POP_UP_ABOUT_TO_BE_SHOWN:
      popupblk = (PopUpAboutToBeShownBlock *)action;

      switch (id_block->this_cmp)
      {
        case GASES_POPUP_PRESSURE:
          Gases_PressureMenuID = popupblk->menu_id;
          event_register_toolbox_handler ( Gases_PressureMenuID,
                                           action_ANY,
                                           Gases_PressureMenuHandler,
                                           NULL );
          break;

        case GASES_POPUP_SIZE:
          Gases_SizeMenuID = popupblk->menu_id;
          event_register_toolbox_handler ( Gases_SizeMenuID,
                                           action_ANY,
                                           Gases_SizeMenuHandler,
                                           NULL );
          /* create the two submenus */
          Gases_DiameterMenuID = toolbox_create_object ( 0, GASES_DIAM_MENUTEMPLATE);
          Gases_XsectionMenuID = toolbox_create_object ( 0, GASES_XSEC_MENUTEMPLATE);
          event_register_toolbox_handler ( Gases_DiameterMenuID,
                                           action_ANY,
                                           Gases_DiameterMenuHandler,
                                           NULL );
          event_register_toolbox_handler ( Gases_XsectionMenuID,
                                           action_ANY,
                                           Gases_XsectionMenuHandler,
                                           NULL );
          break;
      }
      break;

    case action_WINDOW_DIALOGUE_COMPLETED:
      /* get current position of Gases window */
      CJL_GetTopLeftWinPos ( Gases_winhandle, &Gases_win_pos );

      event_deregister_toolbox_handler ( Gases_winid,
                                        action_ANY,
                                        Gases_Handler,
                                        NULL);
      event_deregister_wimp_handler ( Gases_winid,
                                      wimp_KEY_PRESSED,
                                      Gases_KeyPress,
                                      NULL );
      toolbox_delete_object ( 0, Gases_winid );
      Gases_winid = toolbox_NULL_OBJECT;
      break;
  }

  return(TRUE);

  /* for compiler */
  IGNORE (handle);
  IGNORE (id_block);
  IGNORE (action);
}




/************************************************************/

void Gases_Open ( void )
{
  if (Gases_winid == toolbox_NULL_OBJECT)
  {
    Gases_winid = toolbox_create_object ( 0, GASES_TEMPLATE);
    Gases_winhandle = window_get_wimp_handle (0, Gases_winid);
    event_register_toolbox_handler ( Gases_winid, action_ANY,
                                     Gases_Handler, NULL);
    event_register_wimp_handler ( Gases_winid,
                                  wimp_KEY_PRESSED,
                                  Gases_KeyPress,
                                  NULL );

  }
  if (Gases_win_pos.top_left.x == 0)
  {
    toolbox_show_object ( 0,
                          Gases_winid,
                          toolbox_POSITION_CENTRED,
                          0,
                          toolbox_NULL_OBJECT,
                          toolbox_NULL_COMPONENT ) ;
  }
  else
  {
    toolbox_show_object (0,
                        Gases_winid,
                        toolbox_POSITION_TOP_LEFT,
                        &Gases_win_pos,
                        toolbox_NULL_OBJECT,
                        toolbox_NULL_COMPONENT ) ;
  }
  return;
}



/************************************************************/





/*************  End of c.gases  ***********************/

