#include <glib.h>
#include <stdint.h>

struct val_comp_mstk
{
  gdouble etalon;
  gdouble aver_signal;
  gdouble aver_poly;
  gdouble sys_mstk;
  gdouble sko_score;
  gdouble mstk_sum;
  gdouble abs_mstk;
};

struct metrology
{
  guint32 ftype;

  gint32 xml_len;
  gchar   *xml_str;    /// not NULL-terminated string

  gint32 ch_izm_len;
  gchar   *ch_izm;    /// not NULL-terminated string

  gint32 date_len;
  gchar   *date;      /// not NULL-terminated string

  gdouble low_lim;
  gdouble high_lim;
  gdouble resolution;
  gdouble precision;

  gdouble temperature;
  gdouble humidity;
  gdouble pressure;

  int32_t ncycles;
  int32_t nsteps;
  int32_t nmeases;

  int32_t  ncoeffs;
  GArray  *coeffs; /// 1d-array

  GArray *val_comp_mstk_arr; /// 1d-array %val_comp_mstk_arr[@ncycles]

  gdouble abs_mstk;
  gdouble norm_high_lim;
  gdouble norm_mstk;

  GArray *meas_results; /// 1d-array of 3d-data: ncycles x nsteps x nmeases
};

struct metrology *
metrology_new ()
{
  int32_t i = 0,
          j = 0,
	  k = 0;
  double tmp_dbl = 0.0;
  static const gchar * const xml_str = "<root><node arg1=\"params\"></node></root>";
  static const gchar * const ch_izm = "channel123";
  static const gchar * const date = "2012.03.11 18:45:23.15";
  struct metrology *ret_val = NULL;
  struct val_comp_mstk *val_comp_mstk_tmp = NULL;

  if (!(ret_val = g_new0 (struct metrology, 1)))
    {
      goto end;
    };

  ret_val->ftype = 0xBEEF6;
  ret_val->xml_len = (gint32) g_utf8_strlen (xml_str, G_MAXINT) - 1;
  ret_val->xml_str = g_strndup (xml_str, (gsize) ret_val->xml_len);

  ret_val->ch_izm_len = (gint32) g_utf8_strlen (ch_izm, G_MAXINT) - 1;
  ret_val->ch_izm = g_strndup (ch_izm, (gsize) ret_val->ch_izm_len);

  ret_val->date_len = (gint32) g_utf8_strlen (date, G_MAXINT) - 1;
  ret_val->date = g_strndup (date, (gsize) ret_val->date_len);

  ret_val->low_lim = 0.235;
  ret_val->high_lim = 7.38;
  ret_val->resolution = 0.03;
  ret_val->precision = 0.01;

  ret_val->temperature = 23.5;
  ret_val->humidity = 65.0;
  ret_val->pressure = 1e5;

  ret_val->ncycles = 3;
  ret_val->nsteps = 11;
  ret_val->nmeases = 25;

  ret_val->ncoeffs = 5;
  ret_val->coeffs = g_array_new (FALSE, FALSE, sizeof (gdouble));
  for (i = 0; i < 5; i++)
    {
      tmp_dbl = i * i * 0.94 - i * 2.18 + 19.21; 
      g_array_append_val (ret_val->coeffs, tmp_dbl);
    }

  ret_val->val_comp_mstk_arr = g_array_new (FALSE, FALSE, sizeof (struct val_comp_mstk));
  for (i = 0; i < ret_val->ncycles; i++)
    {
      val_comp_mstk_tmp = g_new0 (struct val_comp_mstk, 1);

      val_comp_mstk_tmp->etalon = i * i * 0.3 - i * 3.2 + 8.38;
      val_comp_mstk_tmp->aver_signal = i * i * 4.1 - i * 1.8 + 2.38;
      val_comp_mstk_tmp->aver_poly = i * i * 3.5 - i * 2.9 + 3.22;
      val_comp_mstk_tmp->sys_mstk = i * i * 2.1 - i * 4.1 + 9.22;
      val_comp_mstk_tmp->sko_score = i * i * 8.3 - i * 8.5 + 1.43;
      val_comp_mstk_tmp->mstk_sum = i * i * 3.4 - i * 9.8 + 3.94;
      val_comp_mstk_tmp->abs_mstk = i * i * 1.1 - i * 2.3 + 8.82;

      g_array_append_val (ret_val->val_comp_mstk_arr, val_comp_mstk_tmp);
    }

    ret_val->abs_mstk = 0.243;
    ret_val->norm_high_lim = 0.222;
    ret_val->norm_mstk = 0.333;

  ret_val->meas_results = g_array_new (FALSE, FALSE, sizeof (gdouble));
  for (i = 0; i < ret_val->ncycles; i++)
    for (j = 0; j < ret_val->nsteps; j++)
      for (k = 0; k < ret_val->nmeases; k++)
        {
	  tmp_dbl = i * i * 0.43 - i * 1.8 + 7.88;
	  g_array_append_val (ret_val->meas_results, tmp_dbl);
	}

end:
  return ret_val;
}

gsize
metrology_solid_mem (const struct metrology *m,
                     GByteArray **mem)
{
  gsize ret_val = 0,
        size = 0;
  GByteArray *gbarr = NULL;

  gbarr = g_byte_array_new ();

  g_byte_array_append (gbarr, &m->ftype, sizeof (m->ftype));
  size += sizeof (m->ftype);

  ret_val = size;
  *mem = gbarr;

end:
  return ret_val;
}

void
metrology_destroy (struct metrology *m)
{
  g_free (m->xml_str);
  g_free (m->ch_izm);
  g_free (m->date);
  g_array_free (m->coeffs, FALSE);
  g_array_free (m->val_comp_mstk_arr, FALSE);
  g_array_free (m->meas_results, FALSE);
  g_free (m);
}

int main (int argc, char *argv[])
{
  GError *err = NULL;
  struct metrology *m = NULL;
  GByteArray *mem = NULL;
  gsize size = 0;

  m = metrology_new ();

  g_assert (m);

  size = metrology_solid_mem (m, &mem);

  g_assert (size && mem);

  g_file_set_contents (argv[1], mem->data, size, err);

  metrology_destroy (m);

  return 0;
}
