/*

Copyright (C) 2001  Gopal Narayanan <gopal@astro.umass.edu>

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.

*/

/* 
 * microstrip.c - Puts up window for microstrip and 
 * performs the associated calculations
 */


#include <stdlib.h>
#include <stdio.h>
#include <gtk/gtk.h>
#include <string.h>
#include <math.h>
#include "unitscombo.h"
#include "coax.h"

gboolean doutfixed, dinfixed;
extern void error_mes (char *);



/*
 * get_coax_sub
 * get and assign coax substrate parameters
 * into coax structure
 */

void 
get_coax_sub (trans_win *cwin,
			 coax *cx)
{

  if (sscanf (gtk_entry_get_text(GTK_ENTRY (cwin->subparam_text[0])), 
	      "%g", &cx->er) != 1) error_mes("Error: cx->er");

  if (sscanf (gtk_entry_get_text(GTK_ENTRY (cwin->subparam_text[1])),  
	      "%g", &cx->mur) != 1) error_mes("Error: cx->mur");

  if (sscanf (gtk_entry_get_text(GTK_ENTRY (cwin->subparam_text[2])), 
	      "%g", &cx->tand) != 1) error_mes("Error: cx->tand");

  if (sscanf (gtk_entry_get_text(GTK_ENTRY (cwin->subparam_text[3])), 
	      "%g", &cx->sigma) != 1) error_mes("Error: cx->sigma");
}

/*
 * get_coax_comp
 * get and assign coax component parameters
 * into coax structure
 */

void 
get_coax_comp (trans_win *cwin,
                          coax *cx)
{
  short curr_unit;

  if (sscanf (gtk_entry_get_text(GTK_ENTRY (cwin->component_param_text[0])), 
              "%g", &cx->f) != 1) error_mes("Error: cx->f");
  curr_unit = getunit (gtk_entry_get_text (GTK_ENTRY 
                                           (GTK_COMBO 
					    (cwin->component_param_combo[0])->entry)));
  cx->f = cx->f * conv_freq[curr_unit][FREQ_HZ];
}

/*
 * get_coax_elec
 * get and assign coax electrical parameters
 * into coax structure
 */

void 
get_coax_elec (trans_win *cwin,
                          coax *cx)
{
  short curr_unit;

  if (sscanf (gtk_entry_get_text(GTK_ENTRY (cwin->electrical_param_text[0])), 
              "%g", &cx->Z0) != 1) error_mes("Error: cx->Z0");
  curr_unit = getunit (gtk_entry_get_text (GTK_ENTRY 
                                           (GTK_COMBO
					    (cwin->electrical_param_combo[0])->entry)));
  cx->Z0 = cx->Z0 * conv_res[curr_unit][RES_OHM];

  if (sscanf (gtk_entry_get_text(GTK_ENTRY (cwin->electrical_param_text[1])), 
              "%g", &cx->ang_l) != 1) error_mes("Error: cx->ang_l");
  curr_unit = getunit (gtk_entry_get_text (GTK_ENTRY 
                                           (GTK_COMBO 
					    (cwin->electrical_param_combo[1])->entry)));
  cx->ang_l = cx->ang_l * conv_ang[curr_unit][ANG_RAD];
}

/*
 * get_coax_phys
 * get and assign coax physical parameters
 * into coax structure
 */

void 
get_coax_phys (trans_win *cwin,
                          coax *cx)
{
  short curr_unit;

  if (sscanf (gtk_entry_get_text(GTK_ENTRY (cwin->physical_param_text[0])), 
              "%g", &cx->din) != 1) error_mes("Error: cx->din");
  curr_unit = getunit (gtk_entry_get_text (GTK_ENTRY 
                                           (GTK_COMBO 
					    (cwin->physical_param_combo[0])->entry)));
  cx->din = cx->din * conv_length[curr_unit][LENGTH_M];

  if (sscanf (gtk_entry_get_text(GTK_ENTRY (cwin->physical_param_text[1])), 
              "%g", &cx->dout) != 1) error_mes("Error: cx->dout");
  curr_unit = getunit (gtk_entry_get_text (GTK_ENTRY 
                                           (GTK_COMBO 
					    (cwin->physical_param_combo[1])->entry)));
  cx->dout = cx->dout * conv_length[curr_unit][LENGTH_M];

  if (sscanf (gtk_entry_get_text(GTK_ENTRY (cwin->physical_param_text[2])), 
              "%g", &cx->l) != 1) error_mes("Error: cx->l");
  curr_unit = getunit (gtk_entry_get_text (GTK_ENTRY 
                                           (GTK_COMBO 
					    (cwin->physical_param_combo[2])->entry)));
  cx->l = cx->l * conv_length[curr_unit][LENGTH_M];

}



void
fixdin (GtkWidget *parent, trans_win *cwin)
{
  
  gtk_label_set_text (GTK_LABEL (GTK_BIN (parent)->child), "Fixed");
  gtk_widget_set_sensitive (GTK_WIDGET (parent), FALSE);  
  gtk_label_set_text (GTK_LABEL (GTK_BIN (cwin->physical_param_fix[1])->child), 
"Fix");
  gtk_widget_set_sensitive (GTK_WIDGET (cwin->physical_param_fix[1]), TRUE);  
  dinfixed = TRUE;
  doutfixed = FALSE;
}

void
fixdout (GtkWidget *parent, trans_win *cwin)
{
  
  gtk_label_set_text (GTK_LABEL (GTK_BIN (parent)->child), "Fixed");
  gtk_widget_set_sensitive (GTK_WIDGET (parent), FALSE);  
  gtk_label_set_text (GTK_LABEL (GTK_BIN (cwin->physical_param_fix[0])->child), 
"Fix");
  gtk_widget_set_sensitive (GTK_WIDGET (cwin->physical_param_fix[0]), TRUE);  
  dinfixed = FALSE;
  doutfixed = TRUE;
}


gfloat 
alphad_coax (coax *cx)
{
  gfloat f, er, tand, ad;

  f = cx->f;
  er = cx->er;
  tand = cx->tand;
  
  ad = (M_PI/C0) * f * sqrt(er) * tand;
  ad = ad * 8.686;
  return ad;
}

gfloat 
alphac_coax (coax *cx)
{
  gfloat er, mur, din, dout;
  gfloat f, Rs, sigma;
  gfloat ac;

  er = cx->er;
  mur = cx->mur;
  sigma = cx->sigma;
  f = cx->f;
  din = cx->din;
  dout = cx->dout;
  
  Rs = sqrt((M_PI * f * mur* MU0)/sigma);
  ac = (0.5 * sqrt(er)) * (((1/din) + (1/dout))/log(dout/din)) * 
    (Rs/(120. * M_PI));
  ac = ac * 8.686;
  return ac;

}

/*
 * analyze_coax - analysis function
 */
void
analyze_coax (GtkWidget *parent,
                       trans_win *cwin)
{
  gchar *text, *results, *temp;
  coax *cx;
  short required_unit;
  gfloat lambda_g;
  short m, n;
  gfloat fc;


  /*allocate memory for text */
  if ((text = (char *) malloc(10*sizeof(char)))  == NULL){
    perror("text error: malloc");
    exit(-1);
  }


  /*allocate memory for pointer cx */
  if ((cx = g_malloc(sizeof *cx)) != NULL)
    {
      /* Get and assign substrate parameters */
      get_coax_sub(cwin, cx);

      /* Get and assign component parameters */
      get_coax_comp(cwin, cx);
      
      /* Get and assign physical parameters */
      get_coax_phys(cwin, cx);
 
      if (cx->din != 0.0){
	cx->Z0 = (60.0/sqrt(cx->er))*log(cx->dout/cx->din);
      }

      lambda_g = (C0/(cx->f))/sqrt(cx->er * cx->mur);
      /* calculate electrical angle */
      cx->ang_l = (2.0 * M_PI * cx->l)/lambda_g;    /* in radians */
     
      cx->atten_dielectric = alphad_coax (cx) * cx->l;
      cx->atten_cond = alphac_coax (cx) * cx->l;
      
      

      required_unit = getunit (gtk_entry_get_text 
			       (GTK_ENTRY 
                                (GTK_COMBO (cwin->electrical_param_combo[0])->entry)));
      sprintf(text,"%g", (float) (cx->Z0 * conv_res[RES_OHM][required_unit]));
      gtk_entry_set_text (GTK_ENTRY (cwin->electrical_param_text[0]), text);
      
      required_unit = getunit (gtk_entry_get_text 
                               (GTK_ENTRY 
                                (GTK_COMBO(cwin->electrical_param_combo[1])->entry)));
      sprintf(text,"%g", (float) (cx->ang_l * conv_ang[ANG_RAD][required_unit]));
      gtk_entry_set_text (GTK_ENTRY (cwin->electrical_param_text[1]), text);

      free(text);
      
      if ((text = (char *) malloc(1000*sizeof(char)))  == NULL){
        perror("results text error: malloc");
        exit (-1);
      }
      if ((results = (char *) malloc(1000*sizeof(char)))  == NULL){
        perror("results text error: malloc");
        exit (-1);
      }
      if ((temp = (char *) malloc(1000*sizeof(char)))  == NULL){
        perror("results text error: malloc");
        exit (-1);
      }

      sprintf(results,"Conductor Losses = %.4g dB\n", cx->atten_cond);
      sprintf(text, "Dielectric Losses = %.4g dB\n", 
              cx->atten_dielectric);
      strcat(results, text);
      
      n = 1;
      fc = C0 / (M_PI * (cx->dout + cx->din)/(float) n);
      if (fc <= cx->f) {
	strcpy(text, "\nWarning: The following additional \nTE modes can propagate:\n TE(1,1) ");
	strcat(results, text);
	strcpy(text, " ");	
	m = 2;
	fc = C0 / (2 * (cx->dout - cx->din)/(float) (m-1));
	while ((fc <= cx->f) && (m<10)) {
	    sprintf(temp, "TE(n,%d) ",m);
	    strcat(text,temp);
	    m++;
	    fc = C0 / (2 * (cx->dout - cx->din)/(float) (m-1));
	}
	strcat(results, text);
	strcat(results,"\n\n");
      }

      m = 1;
      fc = C0 / (2 * (cx->dout - cx->din)/(float) m);
      if (fc <= cx->f) {
	strcpy(text, "\nWarning: The following additional \nTM modes can propagate:\n");
	strcat(results, text);
	strcpy(text, " ");

	while ((fc <= cx->f) && (m<10)) {
	  sprintf(temp, "TM(n,%d) ",m);
	  strcat(text,temp);
	  m++;
	  fc = C0 / (2 * (cx->dout - cx->din)/(float) m);
	}
	strcat(results,text);
	strcat(results,"\n");
      }
      
      gtk_label_set (GTK_LABEL (cwin->results_text), results);
      free(results);
      free(text);
      free(temp);

      if (statusexists){
	if (statusint != CONSISTENT) {
	  gtk_label_set_text (GTK_LABEL (cwin->status), "Values are consistent");
	} 
      }
      statusint = CONSISTENT;
        
    } else {
      perror("malloc cx");
      exit (-1);
    }
}


/*
 * synthesize_coax - synthesis function 
 */

void
synthesize_coax (GtkWidget *parent,
		trans_win *cwin)
{

  gchar *text, *results, *temp;
  coax *cx;
  short required_unit;
  gfloat lambda_g;
  gfloat f, er, din, dout, Z0;
  gfloat fc;
  short m, n;


  /*allocate memory for text */
  if ((text = (char *) malloc(10*sizeof(char)))  == NULL){
    perror("text error: malloc");
    exit (-1);
  }

  /* allocate memory for cx */
  if ((cx = g_malloc (sizeof *cx)) != NULL)
    {
      /* Get and assign substrate parameters */
      get_coax_sub(cwin, cx);

      /* Get and assign component parameters */
      get_coax_comp(cwin, cx);

      /* Get and assign electrical parameters */
      get_coax_elec (cwin, cx);

      /* Get and assign physical parameters */
      get_coax_phys(cwin, cx);
      
      f = cx->f;
      din = cx->din;
      dout = cx->dout;
      Z0 = cx->Z0;
      er = cx->er;

      if (doutfixed) {
	/* solve for din */
	cx->din = dout / exp(Z0*sqrt(er)/60.0);
        required_unit = getunit (gtk_entry_get_text 
                               (GTK_ENTRY 
                                (GTK_COMBO(cwin->physical_param_combo[0])->entry)));
        sprintf(text,"%g", (float) (cx->din * conv_length[LENGTH_M][required_unit]));
        gtk_entry_set_text (GTK_ENTRY (cwin->physical_param_text[0]), text);
      } else {
	/* solve for dout */
	cx->dout = din * exp(Z0*sqrt(er)/60.0);
        required_unit = getunit (gtk_entry_get_text 
                               (GTK_ENTRY 
                                (GTK_COMBO(cwin->physical_param_combo[1])->entry)));
        sprintf(text,"%g", (float) (cx->dout * conv_length[LENGTH_M][required_unit]));
        gtk_entry_set_text (GTK_ENTRY (cwin->physical_param_text[1]), text);	
      }


      lambda_g = (C0/(cx->f))/sqrt(cx->er * cx->mur);
      /* calculate physical length */
      cx->l = (lambda_g * cx->ang_l)/(2.0 * M_PI);    /* in m */
      required_unit = getunit (gtk_entry_get_text 
                               (GTK_ENTRY 
                                (GTK_COMBO(cwin->physical_param_combo[2])->entry)));
      sprintf(text,"%g", (float) (cx->l * conv_length[LENGTH_M][required_unit]));
      gtk_entry_set_text (GTK_ENTRY (cwin->physical_param_text[2]), text);
     
      cx->atten_dielectric = alphad_coax (cx) * cx->l;
      cx->atten_cond = alphac_coax (cx) * cx->l;

      free(text);
      
      if ((text = (char *) malloc(1000*sizeof(char)))  == NULL){
        perror("results text error: malloc");
        exit (-1);
      }
      if ((results = (char *) malloc(1000*sizeof(char)))  == NULL){
        perror("results text error: malloc");
        exit (-1);
      }
      if ((temp = (char *) malloc(1000*sizeof(char)))  == NULL){
        perror("results text error: malloc");
        exit (-1);
      }

      sprintf(results,"Conductor Losses = %.4g dB\n", cx->atten_cond);
      sprintf(text, "Dielectric Losses = %.4g dB\n", 
              cx->atten_dielectric);
      strcat(results, text);
      
      n = 1;
      fc = C0 / (M_PI * (cx->dout + cx->din)/(float) n);
      if (fc <= cx->f) {
	strcpy(text, "\nWarning: The following additional \nTE modes can propagate:\n TE(1,1) ");
	strcat(results, text);
	strcpy(text, " ");	
	m = 2;
	fc = C0 / (2 * (cx->dout - cx->din)/(float) (m-1));
	while ((fc <= cx->f) && (m<10)) {
	    sprintf(temp, "TE(n,%d) ",m);
	    strcat(text,temp);
	    m++;
	    fc = C0 / (2 * (cx->dout - cx->din)/(float) (m-1));
	}
	strcat(results, text);
	strcat(results,"\n\n");
      }

      m = 1;
      fc = C0 / (2 * (cx->dout - cx->din)/(float) m);
      if (fc <= cx->f) {
	strcpy(text, "\nWarning: The following additional \nTM modes can propagate:\n");
	strcat(results, text);
	strcpy(text, " ");

	while ((fc <= cx->f) && (m<10)) {
	  sprintf(temp, "TM(n,%d) ",m);
	  strcat(text,temp);
	  m++;
	  fc = C0 / (2 * (cx->dout - cx->din)/(float) m);
	}
	strcat(results,text);
	strcat(results,"\n");
      }
      
      gtk_label_set (GTK_LABEL (cwin->results_text), results);
      free(results);
      free(text);
      free(temp);

      if (statusexists){
	if (statusint != CONSISTENT) {
	  gtk_label_set_text (GTK_LABEL (cwin->status), "Values are consistent");
	} 
      }
      statusint = CONSISTENT;
        
    } else {
      perror("malloc cx");
      exit (-1);
    }
}


/*
 * the window aspect 
 */


void 
coax_win (GtkWidget *parent)
{
  short row;

  /* if there is a window that already exists kill it first */
  if (main_body_window != NULL)   {
    gtk_widget_destroy(main_body_window);
    g_free (twin);
    twin = g_malloc(sizeof(*twin));
  }

  setup_transgui(COAX, parent, twin);

  gtk_label_set_text (GTK_LABEL (GTK_BIN (twin->physical_param_fix[1])->child), "Fixed");
  gtk_widget_set_sensitive (GTK_WIDGET (twin->physical_param_fix[1]), FALSE);
  doutfixed = TRUE;
  dinfixed = FALSE;

  for (row = 0; row<=1; row++) {
    switch(row) {
    case 0: 
      gtk_signal_connect (GTK_OBJECT (twin->physical_param_fix[row]), "clicked",
                          GTK_SIGNAL_FUNC (fixdin), twin);
      break;
    case 1:
      gtk_signal_connect (GTK_OBJECT (twin->physical_param_fix[row]), "clicked",
                          GTK_SIGNAL_FUNC (fixdout), twin);
      break;
    }
  }

  gtk_signal_connect (GTK_OBJECT (twin->Analbutton), "clicked",
                      GTK_SIGNAL_FUNC (analyze_coax), twin); 

  gtk_signal_connect (GTK_OBJECT (twin->Synbutton), "clicked",
		      GTK_SIGNAL_FUNC (synthesize_coax), twin); 

  if (statusint == INCONSISTENT)  {
    analyze_coax(parent, (trans_win *) twin);
  }

  for (row = 0; row<=1; row++){
    gtk_signal_connect (GTK_OBJECT (twin->electrical_param_text[row]), "changed",
                        GTK_SIGNAL_FUNC (setstatus), twin);
  }

}
