#include "asf.h"
#include "asf_meta.h"
#include "dateUtil.h"

#include <assert.h>

#include <gsl/gsl_errno.h>
#include <gsl/gsl_math.h>
#include <gsl/gsl_vector.h>
#include <gsl/gsl_multiroots.h>

static FILE *fopen_workreport_ext(const char *fileName, report_level_t level)
{
  char *path = getPath(fileName);
  char *basename = get_basename(fileName);
  char *txtFile = MALLOC(sizeof(char) * (strlen(path)+strlen(fileName)+20));

  char *p;
  if (strncmp_case(basename, "LED-", 4)==0)
    p = basename + 4;
  else
    p = basename;

  if (strlen(path) > 0)
    sprintf(txtFile, "%s/%s", path, p);
  else
    strcpy(txtFile, p);

  char *workreport_filename = appendExt(txtFile, ".txt");

  // first attempt: basename.txt
  FILE *fp;
  if (!fileExists(workreport_filename)) {
    // second attempt: path/'workreport'
    FREE(workreport_filename);
    workreport_filename = MALLOC(sizeof(char) * (strlen(path) + 20));

    if (strlen(path) > 0)
      sprintf(workreport_filename, "%s/workreport", path);
    else
      strcpy(workreport_filename, "workreport");

    if (!fileExists(workreport_filename)) {

      // third attempt: path/'summary.txt'
      if (strlen(path) > 0)
        sprintf(workreport_filename, "%s/summary.txt", path);
      else
        strcpy(workreport_filename, "summary.txt");

      if (!fileExists(workreport_filename)) {
        // failed!
        fp = NULL;
      }
      else {
        // success with 'summary.txt'
        asfReport(level, "workreport file found as: summary.txt\n");
        fp = FOPEN(workreport_filename, "r");
      }
    }
    else {
      // success with 'workreport'
      asfReport(level, "workreport file found as: workreport\n");
      fp = FOPEN(workreport_filename, "r");
    }
  }
  else {
    // success with 'basename.txt'
    char *basename = get_basename(workreport_filename);
    asfReport(level, "workreport file found as: %s\n", basename);
    fp = FOPEN(workreport_filename, "r");
    FREE(basename);
  }

  FREE(workreport_filename);
  FREE(txtFile);
  FREE(path);
  FREE(basename);

  return fp;
}

FILE *fopen_workreport(const char *fileName)
{
  return fopen_workreport_ext(fileName, REPORT_LEVEL_STATUS);
}

// Get the delta image time for ALOS data out of the summary file
int get_alos_delta_time (const char *fileName, double *delta)
{
  struct dataset_sum_rec dssr;
  hms_time dssr_time, summary_time, start_time, end_time;
  ymd_date dssr_date, summary_date, start_date, end_date;
  char line[512], dateStr[30], *str;

  get_dssr(fileName, &dssr);
  date_dssr2date(dssr.inp_sctim, &dssr_date, &dssr_time);

  FILE *fp = fopen_workreport(fileName);
  if (!fp) {
    // no workreport file...
    *delta = 0;
    return FALSE;
  }

  while (fgets(line, 512, fp)) {
    if (strstr(line, "Img_SceneCenterDateTime")) {
      str = strchr(line, '"');
      sprintf(dateStr, "%s", str+1);
      dateStr[strlen(dateStr)-2] = '\0';
      date_alos2date(dateStr, &summary_date, &summary_time);
      // bumped up the tolerance to 2 seconds... can't see how this would
      // introduce any false positives, and definitely reduces false negatives
      if (date_difference(&dssr_date, &dssr_time,
          &summary_date, &summary_time) > 2.0)
      {
        asfPrintWarning("Summary file does not correspond to leader file.\n"
                        "DSSR: %s\nSummary: %s\n",
                        dssr.inp_sctim, dateStr);
        *delta = 0;
        FCLOSE(fp);
        return FALSE;
      }
    }
    else if (strstr(line, "Img_SceneStartDateTime")) {
      str = strchr(line, '"');
      sprintf(dateStr, "%s", str+1);
      dateStr[strlen(dateStr)-2] = '\0';
      date_alos2date(dateStr, &start_date, &start_time);
    }
    else if (strstr(line, "Img_SceneEndDateTime")) {
      str = strchr(line, '"');
      sprintf(dateStr, "%s", str+1);
      dateStr[strlen(dateStr)-2] = '\0';
      date_alos2date(dateStr, &end_date, &end_time);
    }
  }

  *delta = date_difference(&start_date, &start_time, &end_date, &end_time);
  FCLOSE(fp);
  return TRUE;
}

// Get the SAR processor version from the workreport
int get_alos_processor_version (const char *fileName, double *version)
{
  char line[512], versionStr[10], *str;

  FILE *fp = fopen_workreport_ext(fileName, REPORT_LEVEL_NONE);
  if (!fp) {
    // no workreport file...
    *version = 0.0;
    return FALSE;
  }

  while (fgets(line, 512, fp)) {
    if (strstr(line, "Ver_PSR_CorPrcSigmaSAR")) {
      str = strchr(line, '"');
      sprintf(versionStr, "%s", str+1);
      versionStr[strlen(versionStr)-2] = '\0';
      *version = atof(versionStr);
    }
  }

  FCLOSE(fp);
  return TRUE;
}

// ------------------------------------------------------------------------
// helper code for refine_slc_geolocation_from_workreport()

struct refine_shift_params {
    meta_parameters *meta;
    double center_lat, center_lon;
    double ul_lat, ul_lon;
    double ur_lat, ur_lon;
    double ll_lat, ll_lon;
    double lr_lat, lr_lon;
};

static double lldist(double lat1, double lat2, double lon1, double lon2)
{
    double dlat = lat1 - lat2;
    double dlon;

    // some kludgery to handle crossing the meridian
    // get lat1,lon1 to be on the same side as lat2,lon2
    if (fabs(lon1-lon2) > 300) {
        if (lon2 < 0 && lon1 > 0) lon1 -= 360;
        if (lon2 > 0 && lon1 < 0) lon1 += 360;
    }

    dlon = lon1 - lon2;

    // Scale longitude difference to take into accound the fact
    // that longitude lines are a lot closer at the pole.
    dlon *= cos (lat2 * PI / 180.0);

    return dlat * dlat + dlon * dlon;
}

static double err_at_pixel(struct refine_shift_params *p, double off_t,
                           double off_x, double line, double samp,
                           double real_lat, double real_lon)
{
    const double huge_err = 999999.9;

    meta_parameters *meta = p->meta;
    double lat, lon;
    int bad=0;

    bad = meta_get_latLon(meta, line, samp, 0.0, &lat, &lon);
    if (bad) return huge_err;

    return lldist(lat, real_lat, lon, real_lon);
}

static int
getObjective(const gsl_vector *x, void *params, gsl_vector *f)
{
    double dt = gsl_vector_get(x,0);
    double ds = gsl_vector_get(x,1);

    if (!meta_is_valid_double(ds) || !meta_is_valid_double(dt)) {
        // This does happen sometimes, when we've already found the root
	return GSL_FAILURE;
    }

    struct refine_shift_params *p = (struct refine_shift_params *)params;
    meta_parameters *meta = p->meta;

    int nl = meta->general->line_count;
    int ns = meta->general->sample_count;

    double saved_timeOffset = meta->sar->time_shift;
    double saved_slant = meta->sar->slant_shift;
    meta->sar->time_shift += dt;
    meta->sar->slant_shift += ds;

    double err = 0.0;

    // add up the errors for the 5 known points
    err += err_at_pixel(p, dt, ds, nl/2, ns/2, p->center_lat, p->center_lon);

    if (meta->general->orbit_direction=='A') {
      err += err_at_pixel(p, dt, ds, 0,    0,    p->ll_lat, p->ll_lon);
      err += err_at_pixel(p, dt, ds, nl-1, 0,    p->ul_lat, p->ul_lon);
      err += err_at_pixel(p, dt, ds, 0,    ns-1, p->lr_lat, p->lr_lon);
      err += err_at_pixel(p, dt, ds, nl-1, ns-1, p->ur_lat, p->ur_lon);
    }
    else {
      err += err_at_pixel(p, dt, ds, 0,    0,    p->ul_lat, p->ur_lon);
      err += err_at_pixel(p, dt, ds, nl-1, 0,    p->ll_lat, p->lr_lon);
      err += err_at_pixel(p, dt, ds, 0,    ns-1, p->ur_lat, p->ul_lon);
      err += err_at_pixel(p, dt, ds, nl-1, ns-1, p->lr_lat, p->ll_lon);
    }

    meta->sar->time_shift = saved_timeOffset;
    meta->sar->slant_shift = saved_slant;

    gsl_vector_set(f,0,err);
    gsl_vector_set(f,1,err);
    return GSL_SUCCESS;
}

static void coarse_search(double t_extent_min, double t_extent_max,
                          double s_extent_min, double s_extent_max,
                          double *t_min, double *s_min,
                          struct refine_shift_params *params)
{
    double the_min = 9999999;
    double min_t=99, min_s=99;
    int i,j,k=6;
    double t_extent = t_extent_max - t_extent_min;
    double s_extent = s_extent_max - s_extent_min;
    gsl_vector *v = gsl_vector_alloc(2);
    gsl_vector *u = gsl_vector_alloc(2);
    //printf("           ");
    //for (j = 0; j <= k; ++j) {
    //    double s = s_extent_min + ((double)j)/k*s_extent;
    //    printf("%9.3f ", s);
    //}
    //printf("\n           ");
    //for (j = 0; j <= k; ++j)
    //    printf("--------- ");
    //printf("\n");
    for (i = 0; i <= k; ++i) {
        double t = t_extent_min + ((double)i)/k*t_extent;
        //printf("%9.3f | ", t);

        for (j = 0; j <= k; ++j) {
            double s = s_extent_min + ((double)j)/k*s_extent;

            gsl_vector_set(v, 0, t);
            gsl_vector_set(v, 1, s);
            getObjective(v,(void*)params, u);
            double n = gsl_vector_get(u,0);
            //printf("%9.3f ", n);
            if (n<the_min) {
                the_min=n;
                min_t=gsl_vector_get(v,0);
                min_s=gsl_vector_get(v,1);
            }
        }
        //printf("\n");
    }

    *t_min = min_t;
    *s_min = min_s;

    gsl_vector_free(v);
    gsl_vector_free(u);
}

/* this one can be used to do a time-only search (no slant adjustment)
static void coarse_search_t(double t_extent_min, double t_extent_max,
                            double *t_min, struct refine_shift_params *params)
{
    double the_min = 9999999;
    double min_t=99;
    int i,k=10;
    double t_extent = t_extent_max - t_extent_min;
    gsl_vector *v = gsl_vector_alloc(2);
    gsl_vector *u = gsl_vector_alloc(2);
    for (i = 0; i <= k; ++i) {
        double t = t_extent_min + ((double)i)/k*t_extent;

        gsl_vector_set(v, 0, t);
        gsl_vector_set(v, 1, 0);
        getObjective(v,(void*)params, u);
        double n = gsl_vector_get(u,0);
        if (n<the_min) {
            the_min=n;
            min_t=gsl_vector_get(v,0);
        }
    }

    *t_min = min_t;

    gsl_vector_free(v);
    gsl_vector_free(u);
}
*/

static void generate_start(struct refine_shift_params *params,
                           double *start_t, double *start_s)
{
    int i;

    double extent_t_min = -20;
    double extent_t_max = 20;

    double extent_s_min = -5000;
    double extent_s_max = 5000;

    double t_range = extent_t_max - extent_t_min;
    double s_range = extent_s_max - extent_s_min;

    for (i = 0; i < 12; ++i)
    {
        coarse_search(extent_t_min, extent_t_max, extent_s_min, extent_s_max,
                      start_t, start_s, params);
        //coarse_search_t(extent_t_min, extent_t_max, start_t, params);

        t_range /= 3;
        s_range /= 3;

        extent_t_min = *start_t - t_range/2;
        extent_t_max = *start_t + t_range/2;

        extent_s_min = *start_s - s_range/2;
        extent_s_max = *start_s + s_range/2;

        //printf("refining search to region: (%9.3f,%9.3f)\n"
        //       "                           (%9.3f,%9.3f)\n",
        //       extent_t_min, extent_t_max,
        //       extent_s_min, extent_s_max);
    }
}

/* small debug func
static void print_state(int iter, gsl_multiroot_fsolver *s)
{
    printf("iter = %3d   x = (%.3f %.3f)   f(x) = %.8f\n", iter,
           gsl_vector_get(s->x, 0), gsl_vector_get(s->x, 1),
           gsl_vector_get(s->f, 0));
}
*/

// This won't change the passed-in metadata -- afterwards, if you want
// to apply the found corrections, do this:
//   meta->sar->slant_shift += slant_shift_adjustment;
//   meta->sar->time_shift += time_shift_adjustment;
// usually you will only want to do this if the function returns TRUE
// (on success), though if it returns FALSE (failed) these two parameters
// will be 0
int refine_slc_geolocation_from_workreport(const char *metaName,
                                           const char *basename,
                                           meta_parameters *meta,
                                           double *time_shift_adjustment,
                                           double *slant_shift_adjustment)
{
  char *fileName = MALLOC(sizeof(char)*(10+strlen(basename)+strlen(metaName)));
  char *dirname = get_dirname(metaName);
  if (strlen(dirname)>0)
    sprintf(fileName, "%s%s", dirname, basename);
  else
    strcpy(fileName, basename);
  FILE *fp = fopen_workreport(fileName);
  FREE(dirname);
  if (!fp) {
    // failed to open workreport file
    asfPrintWarning(
"Attempted to refine the geolocation with the workreport file.  However,\n"
"this file could not be found.  To get the most accurate geolocations with\n"
"Palsar SLC data, include the workreport file in the same directory as the\n"
"data file.  First <basename>.txt is checked, then 'workreport'.\n\n"
"Proceeding... however, extremely poor geolocations may result.\n");
    *slant_shift_adjustment = 0.0;
    *time_shift_adjustment = 0.0;
    FREE(fileName);
    return FALSE;
  }

  // Read the workreport file, find the 4 corners and scene center
  // lat and long info.  We also check to make sure this is the right
  // workreport file...

  struct dataset_sum_rec dssr;
  hms_time dssr_time, summary_time;
  ymd_date dssr_date, summary_date;
  char line[512], tmp[512], *p;
  get_dssr(metaName, &dssr);
  date_dssr2date(dssr.inp_sctim, &dssr_date, &dssr_time);

  double center_lat=-999, center_lon=-999;
  double ul_lat=-999, ul_lon=-999;
  double ur_lat=-999, ur_lon=-999;
  double ll_lat=-999, ll_lon=-999;
  double lr_lat=-999, lr_lon=-999;

  while (fgets(line, 512, fp)) {
    if (strstr(line, "Img_SceneCenterDateTime")) {
      p = strchr(line, '"');
      sprintf(tmp, "%s", p+1);
      tmp[strlen(tmp)-2] = '\0';
      date_alos2date(tmp, &summary_date, &summary_time);
      if (date_difference(&dssr_date, &dssr_time,
          &summary_date, &summary_time) > 10.0)
      {
        asfPrintWarning(
"Summary file does not correspond to leader file.\n"
"  DSSR: %s\n  Summary: %s\n"
"This is most likely because you have a mismatched workreport file.  Since\n"
"by default these files are all named 'workreport' this file may have been\n"
"overwritten with another scene's workreport file.  You may wish to rename\n"
"your workreport files using the <basename>.txt convention, for example:\n"
"  %s.txt\n"
"Proceeding... however, extremely poor geolocations may result.\n",
                        dssr.inp_sctim, tmp, fileName);
        *slant_shift_adjustment = 0;
        *time_shift_adjustment = 0;
        FCLOSE(fp);
        FREE(fileName);
        return 0;
      }
    }
    else if (strstr(line, "ImageSceneCenterLatitude")) {
      p = strchr(line, '"');
      if (p) center_lat = atof(p+1);
    }
    else if (strstr(line, "ImageSceneCenterLongitude")) {
      p = strchr(line, '"');
      if (p) center_lon = atof(p+1);
    }
    else if (strstr(line, "ImageSceneLeftTopLatitude")) {
      p = strchr(line, '"');
      if (p) ul_lat = atof(p+1);
    }
    else if (strstr(line, "ImageSceneLeftTopLongitude")) {
      p = strchr(line, '"');
      if (p) ul_lon = atof(p+1);
    }
    else if (strstr(line, "ImageSceneRightTopLatitude")) {
      p = strchr(line, '"');
      if (p) ur_lat = atof(p+1);
    }
    else if (strstr(line, "ImageSceneRightTopLongitude")) {
      p = strchr(line, '"');
      if (p) ur_lon = atof(p+1);
    }
    else if (strstr(line, "ImageSceneLeftBottomLatitude")) {
      p = strchr(line, '"');
      if (p) ll_lat = atof(p+1);
    }
    else if (strstr(line, "ImageSceneLeftBottomLongitude")) {
      p = strchr(line, '"');
      if (p) ll_lon = atof(p+1);
    }
    else if (strstr(line, "ImageSceneRightBottomLatitude")) {
      p = strchr(line, '"');
      if (p) lr_lat = atof(p+1);
    }
    else if (strstr(line, "ImageSceneRightBottomLongitude")) {
      p = strchr(line, '"');
      if (p) lr_lon = atof(p+1);
    }
  }

  FREE(fileName);
  fclose(fp);

  // Did we get all that we needed?
  int ok = TRUE;
  if (center_lat == -999) {
    asfPrintStatus("Missing: ImageSceneCenterLatitude\n");
    ok = FALSE;
  }
  if (center_lon == -999) {
    asfPrintStatus("Missing: ImageSceneCenterLongitude\n");
    ok = FALSE;
  }
  if (ul_lat == -999) {
    asfPrintStatus("Missing: ImageSceneTopLeftLatitude\n");
    ok = FALSE;
  }
  if (ul_lon == -999) {
    asfPrintStatus("Missing: ImageSceneTopLeftLongitude\n");
    ok = FALSE;
  }
  if (ur_lat == -999) {
    asfPrintStatus("Missing: ImageSceneTopRightLatitude\n");
    ok = FALSE;
  }
  if (ur_lon == -999) {
    asfPrintStatus("Missing: ImageSceneTopRightLongitude\n");
    ok = FALSE;
  }
  if (ll_lat == -999) {
    asfPrintStatus("Missing: ImageSceneBottomLeftLatitude\n");
    ok = FALSE;
  }
  if (ll_lon == -999) {
    asfPrintStatus("Missing: ImageSceneBottomLeftLongitude\n");
    ok = FALSE;
  }
  if (lr_lat == -999) {
    asfPrintStatus("Missing: ImageSceneBottomRightLatitude\n");
    ok = FALSE;
  }
  if (lr_lon == -999) {
    asfPrintStatus("Missing: ImageSceneBottomRightLongitude\n");
    ok = FALSE;
  }
  if (!ok) {
    asfPrintWarning("Not all necessary information is available in the "
                    "workreport file.\nProceeding... however, extremely "
                    "poor geolocations may result.\n");
    *slant_shift_adjustment = 0.0;
    *time_shift_adjustment = 0.0;
    return FALSE;
  }

  // all required info is present-- search for min slant and time shifts

  struct refine_shift_params params;
  params.meta = meta;
  params.center_lat = center_lat;
  params.center_lon = center_lon;
  params.ul_lat = ul_lat;
  params.ul_lon = ul_lon;
  params.ur_lat = ur_lat;
  params.ur_lon = ur_lon;
  params.ll_lat = ll_lat;
  params.ll_lon = ll_lon;
  params.lr_lat = lr_lat;
  params.lr_lon = lr_lon;

  //int status;
  //int iter = 0, max_iter = 1000;
  //const gsl_multiroot_fsolver_type *T;
  //gsl_multiroot_fsolver *s;
  //gsl_error_handler_t *prev;
  //const size_t n = 2;

  //gsl_multiroot_function F = {&getObjective, n, &params};
  //gsl_vector *x = gsl_vector_alloc(n);

  double start_t, start_s;
  generate_start(&params, &start_t, &start_s);
  //printf("Starting point at (%f, %f)\n", start_t, start_s);

/*
  gsl_vector_set (x, 0, start_t);
  gsl_vector_set (x, 1, start_s);

  T = gsl_multiroot_fsolver_hybrid;
  s = gsl_multiroot_fsolver_alloc(T, n);
  gsl_multiroot_fsolver_set(s, &F, x);

  prev = gsl_set_error_handler_off();

  do {
    ++iter;
    status = gsl_multiroot_fsolver_iterate(s);

    //print_state(iter, s);

    // abort if stuck
    if (status) break;

    status = gsl_multiroot_test_residual (s->f, 1e-8);
  } while (status == GSL_CONTINUE && iter < max_iter);

  *time_shift_adjustment = gsl_vector_get(s->x, 0);
  *slant_shift_adjustment = gsl_vector_get(s->x, 1);

  gsl_vector *retrofit = gsl_vector_alloc(n);
  gsl_vector_set(retrofit, 0, *time_shift_adjustment);
  gsl_vector_set(retrofit, 1, *slant_shift_adjustment);
  gsl_vector *output = gsl_vector_alloc(n);
  getObjective(retrofit, (void*)&params, output);
  double val= gsl_vector_get(output,0);
  printf("GSL Result: %f at (%f,%f)\n",
         val, *time_shift_adjustment, *slant_shift_adjustment);
  gsl_vector_free(retrofit);
  gsl_vector_free(output);

  gsl_multiroot_fsolver_free(s);
  gsl_vector_free(x);
  gsl_set_error_handler(prev);
*/
  *time_shift_adjustment = start_t;
  *slant_shift_adjustment = start_s;

  // the rest of this is a bunch of debug code
/*
  int nl = meta->general->line_count;
  int ns = meta->general->sample_count;
  double lat,lon;

  if (meta->general->orbit_direction=='A') {

    printf("BEFORE-->\n");
    meta_get_latLon(meta, nl/2, ns/2, 0, &lat, &lon);
    printf("  CN: mgll: %f,%f - wr:%f,%f - err:%f\n",
           lat,lon,center_lat,center_lon,
           lldist(lat,center_lat,lon,center_lon));
    meta_get_latLon(meta, nl-1, 0, 0, &lat, &lon);
    printf("  UL: mgll: %f,%f - wr:%f,%f - err:%f\n",
           lat,lon,ul_lat,ul_lon,lldist(lat,ul_lat,lon,ul_lon));
    meta_get_latLon(meta, nl-1, ns-1, 0, &lat, &lon);
    printf("  UR: mgll: %f,%f - wr:%f,%f - err:%f\n",
           lat,lon,ur_lat,ur_lon,lldist(lat,ur_lat,lon,ur_lon));
    meta_get_latLon(meta, 0, 0, 0, &lat, &lon);
    printf("  LL: mgll: %f,%f - wr:%f,%f - err:%f\n",
           lat,lon,ll_lat,ll_lon,lldist(lat,ll_lat,lon,ll_lon));
    meta_get_latLon(meta, 0, ns-1, 0, &lat, &lon);
    printf("  LR: mgll: %f,%f - wr:%f,%f - err:%f\n",
           lat,lon,lr_lat,lr_lon,lldist(lat,lr_lat,lon,lr_lon));

    double saved_timeOffset = meta->sar->time_shift;
    double saved_slant = meta->sar->slant_shift;
    meta->sar->time_shift += *time_shift_adjustment;
    meta->sar->slant_shift += *slant_shift_adjustment;

    printf("AFTER-->\n");
    meta_get_latLon(meta, nl/2, ns/2, 0, &lat, &lon);
    printf("  CN: mgll: %f,%f - wr:%f,%f - err:%f\n",
           lat,lon,center_lat,center_lon,
           lldist(lat,center_lat,lon,center_lon));
    meta_get_latLon(meta, nl-1, 0, 0, &lat, &lon);
    printf("  UL: mgll: %f,%f - wr:%f,%f - err:%f\n",
           lat,lon,ul_lat,ul_lon,lldist(lat,ul_lat,lon,ul_lon));
    meta_get_latLon(meta, nl-1, ns-1, 0, &lat, &lon);
    printf("  UR: mgll: %f,%f - wr:%f,%f - err:%f\n",
           lat,lon,ur_lat,ur_lon,lldist(lat,ur_lat,lon,ur_lon));
    meta_get_latLon(meta, 0, 0, 0, &lat, &lon);
    printf("  LL: mgll: %f,%f - wr:%f,%f - err:%f\n",
           lat,lon,ll_lat,ll_lon,lldist(lat,ll_lat,lon,ll_lon));
    meta_get_latLon(meta, 0, ns-1, 0, &lat, &lon);
    printf("  LR: mgll: %f,%f - wr:%f,%f - err:%f\n",
           lat,lon,lr_lat,lr_lon,lldist(lat,lr_lat,lon,lr_lon));

    meta->sar->time_shift = saved_timeOffset;
    meta->sar->slant_shift = saved_slant;
  }
  else {
    printf("BEFORE-->\n");
    meta_get_latLon(meta, nl/2, ns/2, 0, &lat, &lon);
    printf("  CN: mgll: %f,%f - wr:%f,%f - err:%f\n",
           lat,lon,center_lat,center_lon,
           lldist(lat,center_lat,lon,center_lon));
    meta_get_latLon(meta, 0, ns-1, 0, &lat, &lon);
    printf("  UL: mgll: %f,%f - wr:%f,%f - err:%f\n",
           lat,lon,ul_lat,ul_lon,lldist(lat,ul_lat,lon,ul_lon));
    meta_get_latLon(meta, 0, 0, 0, &lat, &lon);
    printf("  UR: mgll: %f,%f - wr:%f,%f - err:%f\n",
           lat,lon,ur_lat,ur_lon,lldist(lat,ur_lat,lon,ur_lon));
    meta_get_latLon(meta, nl-1, ns-1, 0, &lat, &lon);
    printf("  LL: mgll: %f,%f - wr:%f,%f - err:%f\n",
           lat,lon,ll_lat,ll_lon,lldist(lat,ll_lat,lon,ll_lon));
    meta_get_latLon(meta, nl-1, 0, 0, &lat, &lon);
    printf("  LR: mgll: %f,%f - wr:%f,%f - err:%f\n",
           lat,lon,lr_lat,lr_lon,lldist(lat,lr_lat,lon,lr_lon));

    double saved_timeOffset = meta->sar->time_shift;
    double saved_slant = meta->sar->slant_shift;
    meta->sar->time_shift += *time_shift_adjustment;
    meta->sar->slant_shift += *slant_shift_adjustment;

    printf("AFTER-->\n");
    meta_get_latLon(meta, nl/2, ns/2, 0, &lat, &lon);
    printf("  CN: mgll: %f,%f - wr:%f,%f - err:%f\n",
           lat,lon,center_lat,center_lon,
           lldist(lat,center_lat,lon,center_lon));
    meta_get_latLon(meta, 0, ns-1, 0, &lat, &lon);
    printf("  UL: mgll: %f,%f - wr:%f,%f - err:%f\n",
           lat,lon,ul_lat,ul_lon,lldist(lat,ul_lat,lon,ul_lon));
    meta_get_latLon(meta, 0, 0, 0, &lat, &lon);
    printf("  UR: mgll: %f,%f - wr:%f,%f - err:%f\n",
           lat,lon,ur_lat,ur_lon,lldist(lat,ur_lat,lon,ur_lon));
    meta_get_latLon(meta, nl-1, ns-1, 0, &lat, &lon);
    printf("  LL: mgll: %f,%f - wr:%f,%f - err:%f\n",
           lat,lon,ll_lat,ll_lon,lldist(lat,ll_lat,lon,ll_lon));
    meta_get_latLon(meta, nl-1, 0, 0, &lat, &lon);
    printf("  LR: mgll: %f,%f - wr:%f,%f - err:%f\n",
           lat,lon,lr_lat,lr_lon,lldist(lat,lr_lat,lon,lr_lon));

    meta->sar->time_shift = saved_timeOffset;
    meta->sar->slant_shift = saved_slant;
  }
*/
  return TRUE;
}


#pragma once

#include <imageview/ContinuousImageView.h>
#include <imageview/internal/ImageViewStorage.h>
#include <imageview/internal/PixelRef.h>

#include <gsl/span>

#include <cstddef>

namespace imageview {

template <class PixelFormat, bool Mutable = false>
class ImageView {
 public:
  static_assert(IsPixelFormat<PixelFormat>::value, "Not a PixelFormat.");

  using byte_type = std::conditional_t<Mutable, std::byte, const std::byte>;
  using value_type = typename PixelFormat::color_type;
  // TODO: consider using 'const value_type' instead of 'value_type' for immutable views.
  using reference = std::conditional_t<Mutable, detail::PixelRef<PixelFormat>, value_type>;

  // Construct an empty view.
  template <class Enable = std::enable_if_t<std::is_default_constructible_v<PixelFormat>>>
  constexpr ImageView() noexcept(noexcept(std::is_nothrow_default_constructible_v<PixelFormat>)) {}

  // Construct a view into an image.
  // \param height - height of the image.
  // \param width - width of the image.
  // \param stride -
  // \param data - bitmap data.
  constexpr ImageView(unsigned int height, unsigned int width, unsigned int stride, gsl::span<byte_type> data);

  // Construct a view into an image.
  // \param height - height of the image.
  // \param width - width of the image.
  // \param stride -
  // \param data - bitmap data.
  // \param pixel_format - PixelFormat instance to use.
  constexpr ImageView(unsigned int height, unsigned int width, unsigned int stride, gsl::span<byte_type> data,
                      const PixelFormat& pixel_format);
  constexpr ImageView(unsigned int height, unsigned int width, unsigned int stride, gsl::span<byte_type> data,
                      PixelFormat&& pixel_format);

  // Construct a read-only view from a mutable view.
  template <class Enable = std::enable_if_t<!Mutable>>
  constexpr ImageView(ImageView<PixelFormat, !Mutable> other);

  constexpr ImageView(ContinuousImageView<PixelFormat, Mutable> image);
  // Construct a read-only view from a mutable contiguous view.
  template <class Enable = std::enable_if_t<!Mutable>>
  constexpr ImageView(ContinuousImageView<PixelFormat, !Mutable> image);

  // Return the height of the image
  constexpr unsigned int height() const noexcept;

  constexpr unsigned int width() const noexcept;

  constexpr unsigned int stride() const noexcept;

  constexpr unsigned int area() const noexcept;

  // Returns true if the image has zero area, false otherwise.
  constexpr bool empty() const noexcept;

  // Returns the pixel format used by this image.
  constexpr const PixelFormat& pixelFormat() const noexcept;

  constexpr gsl::span<byte_type> data() const noexcept;

  constexpr reference operator()(unsigned int y, unsigned int x) const;

  constexpr ImageRowView<PixelFormat, Mutable> row(unsigned int y) const;

 private:
  detail::ImageViewStorage<PixelFormat, Mutable> storage_;
  unsigned int height_ = 0;
  unsigned int width_ = 0;
  unsigned int stride_ = 0;
};

template <class PixelFormat, bool Mutable>
constexpr ImageView<PixelFormat, Mutable>::ImageView(unsigned int height, unsigned int width, unsigned int stride,
                                                     gsl::span<byte_type> data)
    : storage_(data.data()), height_(height), width_(width), stride_(stride) {
  Expects(width <= stride);
  const std::size_t expected_size = (height == 0) ? 0 : ((height - 1) * stride + width) * PixelFormat::kBytesPerPixel;
  Expects(data.size() == expected_size);
}

template <class PixelFormat, bool Mutable>
constexpr ImageView<PixelFormat, Mutable>::ImageView(unsigned int height, unsigned int width, unsigned int stride,
                                                     gsl::span<byte_type> data, const PixelFormat& pixel_format)
    : storage_(data.data(), pixel_format), height_(height), width_(width), stride_(stride) {
  Expects(width <= stride);
  const std::size_t expected_size = (height == 0) ? 0 : ((height - 1) * stride + width) * PixelFormat::kBytesPerPixel;
  Expects(data.size() == expected_size);
}

template <class PixelFormat, bool Mutable>
constexpr ImageView<PixelFormat, Mutable>::ImageView(unsigned int height, unsigned int width, unsigned int stride,
                                                     gsl::span<byte_type> data, PixelFormat&& pixel_format)
    : storage_(data.data(), std::move(pixel_format)), height_(height), width_(width), stride_(stride) {
  Expects(width <= stride);
  const std::size_t expected_size = (height == 0) ? 0 : ((height - 1) * stride + width) * PixelFormat::kBytesPerPixel;
  Expects(data.size() == expected_size);
}

template <class PixelFormat, bool Mutable>
template <class Enable>
constexpr ImageView<PixelFormat, Mutable>::ImageView(ImageView<PixelFormat, !Mutable> other)
    : ImageView(other.height(), other.width(), other.stride(), other.data(), other.pixelFormat()) {}

template <class PixelFormat, bool Mutable>
constexpr ImageView<PixelFormat, Mutable>::ImageView(ContinuousImageView<PixelFormat, Mutable> image)
    : ImageView(image.height(), image.width(), image.width(), image.data()) {}

template <class PixelFormat, bool Mutable>
template <class Enable>
constexpr ImageView<PixelFormat, Mutable>::ImageView(ContinuousImageView<PixelFormat, !Mutable> image)
    : ImageView(ContinuousImageView<PixelFormat, Mutable>(image)) {}

template <class PixelFormat, bool Mutable>
constexpr unsigned int ImageView<PixelFormat, Mutable>::height() const noexcept {
  return height_;
}

template <class PixelFormat, bool Mutable>
constexpr unsigned int ImageView<PixelFormat, Mutable>::width() const noexcept {
  return width_;
}

template <class PixelFormat, bool Mutable>
constexpr unsigned int ImageView<PixelFormat, Mutable>::stride() const noexcept {
  return stride_;
}

template <class PixelFormat, bool Mutable>
constexpr unsigned int ImageView<PixelFormat, Mutable>::area() const noexcept {
  return height_ * width_;
}

template <class PixelFormat, bool Mutable>
constexpr bool ImageView<PixelFormat, Mutable>::empty() const noexcept {
  return height_ == 0 || width_ == 0;
}

template <class PixelFormat, bool Mutable>
constexpr const PixelFormat& ImageView<PixelFormat, Mutable>::pixelFormat() const noexcept {
  return storage_.pixelFormat();
}

template <class PixelFormat, bool Mutable>
constexpr auto ImageView<PixelFormat, Mutable>::data() const noexcept -> gsl::span<byte_type> {
  const std::size_t data_size = (height_ == 0) ? 0 : ((height_ - 1) * stride_ + width_) * PixelFormat::kBytesPerPixel;
  return gsl::span<byte_type>(storage_.data(), data_size);
}

template <class PixelFormat, bool Mutable>
constexpr auto ImageView<PixelFormat, Mutable>::operator()(unsigned int y, unsigned int x) const -> reference {
  Expects(y < height_);
  Expects(x < width_);
  const gsl::span<byte_type, PixelFormat::kBytesPerPixel> pixel_data(
      storage_.data() + (y * stride_ + x) * PixelFormat::kBytesPerPixel, PixelFormat::kBytesPerPixel);
  if constexpr (Mutable) {
    return detail::PixelRef<PixelFormat>(pixel_data, pixelFormat());
  } else {
    return pixelFormat().read(pixel_data);
  }
}

template <class PixelFormat, bool Mutable>
constexpr ImageRowView<PixelFormat, Mutable> ImageView<PixelFormat, Mutable>::row(unsigned int y) const {
  Expects(y < height_);
  const gsl::span<byte_type> row_data(storage_.data() + y * stride_ * PixelFormat::kBytesPerPixel,
                                      width_ * PixelFormat::kBytesPerPixel);
  return ImageRowView<PixelFormat>(row_data, width_, pixelFormat());
}

}  // namespace imageview


// Copyright © Matt Jones and Contributors. Licensed under the MIT Licence (MIT). See LICENCE.md in the repository root
// for more information.

#ifndef NOVELRT_EXPERIMENTAL_GRAPHICS_H
#define NOVELRT_EXPERIMENTAL_GRAPHICS_H

// Graphics dependencies
#include "../../Graphics/RGBAColour.h"
#include "../../Maths/Maths.h"
#include "../../Utilities/Event.h"
#include "../../Utilities/Misc.h"
#include "../EngineConfig.h"
#include "../Threading/Threading.h"
#include <chrono>
#include <cstdint>
#include <filesystem>
#include <gsl/span>
#include <list>
#include <memory>
#include <mutex>
#include <optional>
#include <string>
#include <typeindex>
#include <utility>
#include <vector>

/**
 * @brief The experimental Graphics plugin API. Comes with built-in support for the ECS.
 */
namespace NovelRT::Experimental::Graphics
{
    enum class ShaderProgramKind : uint32_t;
    class GraphicsDeviceObject;
    enum class GraphicsResourceAccess : uint32_t;
    enum class GraphicsSurfaceKind : uint32_t;
    class IGraphicsSurface;
    class GraphicsAdapter;
    class GraphicsDevice;
    class GraphicsResource;
    class GraphicsBuffer;
    class GraphicsTexture;
    class ShaderProgram;
    class GraphicsPipeline;
    class GraphicsPipelineSignature;
    class GraphicsPipelineInput;
    class GraphicsPipelineResource;
    class GraphicsPipelineInputElement;
    enum class GraphicsPipelineInputElementKind : uint32_t;
    enum class GraphicsPipelineResourceKind : uint32_t;
    enum class ShaderProgramVisibility : uint32_t;
    class GraphicsContext;
    class GraphicsFence;
    class GraphicsPrimitive;
    class GraphicsProvider;
    class GraphicsMemoryAllocator;
    struct GraphicsMemoryAllocatorSettings;
    enum class GraphicsTextureKind : uint32_t;
    class IGraphicsAdapterSelector;
    enum class GraphicsMemoryRegionAllocationFlags : uint32_t;
    class GraphicsMemoryBlockCollection;
    class GraphicsMemoryBlock;
    enum class GraphicsMemoryRegionAllocationFlags : uint32_t;
    class GraphicsMemoryBudget;
    enum class GraphicsBufferKind : uint32_t;
    enum class TexelFormat : uint32_t;
    class GraphicsSurfaceContext;
}

// Graphics types
// clang-format off

#include "ShaderProgramKind.h"
#include "EcsDefaultRenderingComponentTypes.h"
#include "EcsDefaultRenderingSystem.h"
#include "GraphicsAdapter.h"
#include "GraphicsDeviceObject.h"
#include "GraphicsContext.h"
#include "GraphicsFence.h"
#include "GraphicsMemoryAllocatorSettings.h"
#include "GraphicsMemoryRegion.h"
#include "IGraphicsMemoryRegionCollection.h"
#include "GraphicsMemoryRegionAllocationFlags.h"
#include "TexelFormat.h"
#include "GraphicsMemoryAllocator.h"
#include "GraphicsMemoryBlockCollection.h"
#include "GraphicsMemoryBudget.h"
#include "GraphicsMemoryBlock.h"
#include "GraphicsResourceAccess.h"
#include "GraphicsSurfaceKind.h"
#include "GraphicsTextureKind.h"
#include "IGraphicsSurface.h"
#include "GraphicsSurfaceContext.h"
#include "GraphicsDevice.h"
#include "GraphicsResource.h"
#include "GraphicsBufferKind.h"
#include "GraphicsBuffer.h"
#include "GraphicsTexture.h"
#include "IGraphicsAdapterSelector.h"
#include "ShaderProgram.h"
#include "GraphicsPipeline.h"
#include "GraphicsPipelineSignature.h"
#include "GraphicsPrimitive.h"
#include "GraphicsProvider.h"
#include "GraphicsPipelineInput.h"
#include "GraphicsPipelineInputElement.h"
#include "GraphicsPipelineInputElementKind.h"
#include "GraphicsPipelineResource.h"
#include "GraphicsPipelineResourceKind.h"
#include "ShaderProgramVisibility.h"

// clang-format on

#endif // !NOVELRT_EXPERIMENTAL_GRAPHICS_H


#ifndef LIC_CALL_STACK_FRAME
#define LIC_CALL_STACK_FRAME

#include <stack>
#include <gsl/gsl>

#include "format/Opcodes.h"
#include "loader/MethodDefinition.h"
#include "EvaluationStack.h"

namespace lic
{

class CallStackFrame
{
public:
    CallStackFrame(MethodDefinition& method, gsl::span<TypedValue> args, Opcode* returnAddress);
    CallStackFrame(MethodDefinition& method, TypedValue& thisRef, gsl::span<TypedValue> args, Opcode* returnAddress);

    MethodDefinition& Method();
    TypedValue& Arg(size_t index);
    TypedValue& Local(size_t index);
    EvaluationStack& Stack();
    Opcode* ReturnAddress() const;

private:
    MethodDefinition& method;
    std::vector<TypedValue> args;
    std::vector<TypedValue> locals;
    EvaluationStack stack;
    Opcode* returnAddress;
};

}

#endif // !LIC_CALL_STACK_FRAME


#pragma once

#include <gsl/span>

#include <memory>

#include <qbuffer.h>
#include <qthread.h>

#if QT_VERSION >= 0x060000
    #include <QtMultimedia/QAudioSink>
#else
    #include <QtMultimedia/QAudioOutput>
#endif
namespace contour
{
class Audio: public QObject
{
    Q_OBJECT

  public:
    Audio();
    ~Audio() override;
  signals:
    void play(int volume, int duration, std::vector<int> const& notes);
  private slots:
    void handleStateChanged(QAudio::State state);
    void handlePlayback(int volume, int duration, std::vector<int> const& notes);

  private:
    void fillBuffer(int volume, int duration, gsl::span<const int> notes);
    std::vector<std::int16_t> createMusicalNote(double volume, int duration, int note_) noexcept;

    QByteArray byteArray_;
    QBuffer audioBuffer_;
    QThread soundThread_;
#if QT_VERSION >= 0x060000
    std::unique_ptr<QAudioSink> audio;
#else
    std::unique_ptr<QAudioOutput> audio;
#endif
};
} // namespace contour


#pragma once
#include <gsl/gsl>
#include <map>
#include <optional>

#include "aseprite_file.h"
#include "halley/text/halleystring.h"
#include "halley/maths/vector4.h"

namespace Halley
{
	class Path;
	class Image;
	struct ImageData;

	class AsepriteReader
	{
	public:
		static std::map<String, Vector<ImageData>> importAseprite(const String& spriteName, const Path& filename, gsl::span<const gsl::byte> fileData, bool trim, int padding, bool groupSeparated, bool sequenceSeparated);
		static void addImageData(int tagFrameNumber, int origFrameNumber, Vector<ImageData>& frameData, std::unique_ptr<Image> frameImage,
		                  const AsepriteFile& aseFile, const String& baseName, const String& sequence, const String& direction,
						  int duration, bool trim, int padding, bool hasFrameNumber, std::optional<String> group, bool firstImage,
		                  const String& spriteName, const Path& filename);
	};
}


/*
 *  Copyright (C) 2021 FISCO BCOS.
 *  SPDX-License-Identifier: Apache-2.0
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *
 * @brief scale decoder
 * @file ScaleDecoderStream.cpp
 */
#pragma once
#include "../../libutilities/Common.h"
#include "../../libutilities/DataConvertUtility.h"
#include "../../libutilities/FixedBytes.h"
#include "Common.h"
#include "FixedWidthIntegerCodec.h"
#include <boost/multiprecision/cpp_int.hpp>
#include <boost/optional.hpp>
#include <boost/variant.hpp>
#include <array>
#include <gsl/span>

namespace bcos
{
namespace codec
{
namespace scale
{
class ScaleDecoderStream
{
public:
    // special tag to differentiate decoding streams from others
    static constexpr auto is_decoder_stream = true;
    explicit ScaleDecoderStream(gsl::span<byte const> span);

    /**
     * @brief scale-decodes pair of values
     * @tparam F first value type
     * @tparam S second value type
     * @param p pair of values to decode
     * @return reference to stream
     */
    template <class F, class S>
    ScaleDecoderStream& operator>>(std::pair<F, S>& p)
    {
        static_assert(!std::is_reference_v<F> && !std::is_reference_v<S>);
        return *this >> const_cast<std::remove_const_t<F>&>(p.first)  // NOLINT
               >> const_cast<std::remove_const_t<S>&>(p.second);      // NOLINT
    }

    /**
     * @brief scale-decoding of tuple
     * @tparam T enumeration of tuples types
     * @param v reference to tuple
     * @return reference to stream
     */
    template <class... T>
    ScaleDecoderStream& operator>>(std::tuple<T...>& v)
    {
        if constexpr (sizeof...(T) > 0)
        {
            decodeElementOfTuple<0>(v);
        }
        return *this;
    }

    /**
     * @brief scale-decoding of variant
     * @tparam T enumeration of various types
     * @param v reference to variant
     * @return reference to stream
     */
    template <class... Ts>
    ScaleDecoderStream& operator>>(boost::variant<Ts...>& v)
    {
        // first byte means type index
        uint8_t type_index = 0u;
        *this >> type_index;  // decode type index

        // ensure that index is in [0, types_count)
        if (type_index >= sizeof...(Ts))
        {
            BOOST_THROW_EXCEPTION(
                ScaleDecodeException() << errinfo_comment("exception for WRONG_TYPE_INDEX"));
        }

        tryDecodeAsOneOfVariant<0>(v, type_index);
        return *this;
    }

    /**
     * @brief scale-decodes shared_ptr value
     * @tparam T value type
     * @param v value to decode
     * @return reference to stream
     */
    template <class T>
    ScaleDecoderStream& operator>>(std::shared_ptr<T>& v)
    {
        using mutableT = std::remove_const_t<T>;

        static_assert(std::is_default_constructible_v<mutableT>);

        v = std::make_shared<mutableT>();
        return *this >> const_cast<mutableT&>(*v);  // NOLINT
    }

    /**
     * @brief scale-decodes unique_ptr value
     * @tparam T value type
     * @param v value to decode
     * @return reference to stream
     */
    template <class T>
    ScaleDecoderStream& operator>>(std::unique_ptr<T>& v)
    {
        using mutableT = std::remove_const_t<T>;

        static_assert(std::is_default_constructible_v<mutableT>);

        v = std::make_unique<mutableT>();
        return *this >> const_cast<mutableT&>(*v);  // NOLINT
    }

    /**
     * @brief scale-encodes any integral type including bool
     * @tparam T integral type
     * @param v value of integral type
     * @return reference to stream
     */
    template <typename T, typename I = std::decay_t<T>,
        typename = std::enable_if_t<std::is_integral<I>::value>>
    ScaleDecoderStream& operator>>(T& v)
    {
        // check bool
        if constexpr (std::is_same<I, bool>::value)
        {
            v = decodeBool();
            return *this;
        }
        // check byte
        if constexpr (sizeof(T) == 1u)
        {
            v = nextByte();
            return *this;
        }
        // decode any other integer
        v = decodeInteger<I>(*this);
        return *this;
    }

    /**
     * @brief scale-decodes any optional value
     * @tparam T type of optional value
     * @param v optional value reference
     * @return reference to stream
     */
    template <class T>
    ScaleDecoderStream& operator>>(boost::optional<T>& v)
    {
        using mutableT = std::remove_const_t<T>;

        static_assert(std::is_default_constructible_v<mutableT>);

        // optional bool is special case of optional values
        // it is encoded as one byte instead of two
        // as described in specification
        if constexpr (std::is_same<mutableT, bool>::value)
        {
            v = decodeOptionalBool();
            return *this;
        }
        // detect if optional has value
        bool has_value = false;
        *this >> has_value;
        if (!has_value)
        {
            v.reset();
            return *this;
        }
        // decode value
        v.emplace();
        return *this >> const_cast<mutableT&>(*v);  // NOLINT
    }

    ScaleDecoderStream& operator>>(u256& v);
    /**
     * @brief scale-decodes compact integer value
     * @param v compact integer reference
     * @return
     */
    ScaleDecoderStream& operator>>(CompactInteger& v);
    ScaleDecoderStream& operator>>(s256& v)
    {
        u256 unsignedValue;
        *this >> unsignedValue;
        v = u2s(unsignedValue);
        return *this;
    }

    template <unsigned N>
    ScaleDecoderStream& operator>>(FixedBytes<N>& fixedData)
    {
        bytes decodedData;
        *this >> decodedData;
        if (decodedData.size() < FixedBytes<N>::size)
        {
            BOOST_THROW_EXCEPTION(ScaleDecodeException() << errinfo_comment(
                                      "exception for invalid FixedBytes, expected size:" +
                                      std::to_string(FixedBytes<N>::size) +
                                      ", decoded data size:" + std::to_string(decodedData.size())));
        }
        fixedData = FixedBytes<N>(decodedData.data(), FixedBytes<N>::ConstructorType::FromPointer);
        return *this;
    }
    /**
     * @brief decodes vector of items
     * @tparam T item type
     * @param v reference to vector
     * @return reference to stream
     */
    template <class T>
    ScaleDecoderStream& operator>>(std::vector<T>& v)
    {
        using mutableT = std::remove_const_t<T>;
        using size_type = typename std::list<T>::size_type;

        static_assert(std::is_default_constructible_v<mutableT>);

        CompactInteger size{0u};
        *this >> size;

        auto item_count = size.convert_to<size_type>();
        std::vector<mutableT> vec;
        try
        {
            vec.resize(item_count);
        }
        catch (const std::bad_alloc&)
        {
            BOOST_THROW_EXCEPTION(
                ScaleDecodeException()
                << errinfo_comment("exception for TOO_MANY_ITEMS: " + std::to_string(item_count)));
        }
        if constexpr (sizeof(T) == 1u)
        {
            vec.assign(m_currentIterator, m_currentIterator + item_count);
            m_currentIterator += item_count;
            m_currentIndex += item_count;
        }
        else
        {
            for (size_type i = 0u; i < item_count; ++i)
            {
                *this >> vec[i];
            }
        }
        v = std::move(vec);
        return *this;
    }

    /**
     * @brief decodes map of pairs
     * @tparam T item type
     * @tparam F item type
     * @param m reference to map
     * @return reference to stream
     */
    template <class T, class F>
    ScaleDecoderStream& operator>>(std::map<T, F>& m)
    {
        using mutableT = std::remove_const_t<T>;
        static_assert(std::is_default_constructible_v<mutableT>);
        using mutableF = std::remove_const_t<F>;
        static_assert(std::is_default_constructible_v<mutableF>);

        using size_type = typename std::map<T, F>::size_type;

        CompactInteger size{0u};
        *this >> size;

        auto item_count = size.convert_to<size_type>();
        std::map<mutableT, mutableF> map;
        for (size_type i = 0u; i < item_count; ++i)
        {
            std::pair<mutableT, mutableF> p;
            *this >> p;
            map.emplace(std::move(p));
        }
        m = std::move(map);
        return *this;
    }

    /**
     * @brief decodes collection of items
     * @tparam T item type
     * @param v reference to collection
     * @return reference to stream
     */
    template <class T>
    ScaleDecoderStream& operator>>(std::list<T>& v)
    {
        using mutableT = std::remove_const_t<T>;
        using size_type = typename std::list<T>::size_type;

        static_assert(std::is_default_constructible_v<mutableT>);

        CompactInteger size{0u};
        *this >> size;

        auto item_count = size.convert_to<size_type>();

        std::list<T> lst;
        try
        {
            lst.reserve(item_count);
        }
        catch (const std::bad_alloc&)
        {
            BOOST_THROW_EXCEPTION(ScaleDecodeException() << errinfo_comment(
                                      "exception for TOO_MANY_ITEMS" + std::to_string(item_count)));
        }

        for (size_type i = 0u; i < item_count; ++i)
        {
            lst.emplace_back();
            *this >> lst.back();
        }
        v = std::move(lst);
        return *this;
    }

    /**
     * @brief decodes array of items
     * @tparam T item type
     * @tparam size of the array
     * @param a reference to the array
     * @return reference to stream
     */
    template <class T, size_t size>
    ScaleDecoderStream& operator>>(std::array<T, size>& a)
    {
        using mutableT = std::remove_const_t<T>;
        for (size_t i = 0u; i < size; ++i)
        {
            *this >> const_cast<mutableT&>(a[i]);  // NOLINT
        }
        return *this;
    }

    /**
     * @brief decodes string from stream
     * @param v value to decode
     * @return reference to stream
     */
    ScaleDecoderStream& operator>>(std::string& v);

    /**
     * @brief hasMore Checks whether n more bytes are available
     * @param n Number of bytes to check
     * @return True if n more bytes are available and false otherwise
     */
    bool hasMore(uint64_t n) const;

    /**
     * @brief takes one byte from stream and
     * advances current byte iterator by one
     * @return current byte
     */
    uint8_t nextByte()
    {
        if (!hasMore(1))
        {
            BOOST_THROW_EXCEPTION(ScaleDecodeException()
                                  << errinfo_comment("nextByte exception for NOT_ENOUGH_DATA"));
        }
        ++m_currentIndex;
        return *m_currentIterator++;
    }
    using SizeType = gsl::span<const byte>::size_type;

    gsl::span<byte const> span() const { return m_span; }
    SizeType currentIndex() const { return m_currentIndex; }

private:
    bool decodeBool();
    /**
     * @brief special case of optional values as described in specification
     * @return boost::optional<bool> value
     */
    boost::optional<bool> decodeOptionalBool();

    template <size_t I, class... Ts>
    void decodeElementOfTuple(std::tuple<Ts...>& v)
    {
        using T = std::remove_const_t<std::tuple_element_t<I, std::tuple<Ts...>>>;
        *this >> const_cast<T&>(std::get<I>(v));  // NOLINT
        if constexpr (sizeof...(Ts) > I + 1)
        {
            decodeElementOfTuple<I + 1>(v);
        }
    }

    template <size_t I, class... Ts>
    void tryDecodeAsOneOfVariant(boost::variant<Ts...>& v, size_t i)
    {
        using T = std::remove_const_t<std::tuple_element_t<I, std::tuple<Ts...>>>;
        static_assert(std::is_default_constructible_v<T>);
        if (I == i)
        {
            T val;
            *this >> val;
            v = std::forward<T>(val);
            return;
        }
        if constexpr (sizeof...(Ts) > I + 1)
        {
            tryDecodeAsOneOfVariant<I + 1>(v, i);
        }
    }

private:
    gsl::span<byte const> m_span;
    gsl::span<byte const>::const_iterator m_currentIterator;
    SizeType m_currentIndex;
};
}  // namespace scale
}  // namespace codec
}  // namespace bcos


// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

#pragma once

#include <gsl/span>

#include "core/common/common.h"
#include "core/optimizer/graph_transformer.h"

namespace onnxruntime {

struct FreeDimensionOverride;

/**
@Class FreeDimensionOverrideTransformer

Transformer that overrides free dimensions in the graph with the specific value
that matches the denotation for that dimension.
*/
class FreeDimensionOverrideTransformer : public GraphTransformer {
 public:
  explicit FreeDimensionOverrideTransformer(gsl::span<const FreeDimensionOverride> overrides_to_apply);

 private:
  Status ApplyImpl(Graph& graph, bool& modified, int graph_level) const override;

  std::map<std::string, int64_t> dimension_override_by_denotation_;
};

}  // namespace onnxruntime


#pragma once

#include <gsl/gsl>

#include "exception.h"
#include <fmt/format.h>
#include "mathutil.h"
#include "stringutil.h"
#include "version.h"
#include "stopwatch.h"
#include "logging.h"


#ifndef OPENMC_TALLIES_FILTER_CELL_H
#define OPENMC_TALLIES_FILTER_CELL_H

#include <cstdint>
#include <unordered_map>

#include <gsl/gsl>

#include "openmc/tallies/filter.h"
#include "openmc/vector.h"

namespace openmc {

//==============================================================================
//! Specifies which geometric cells tally events reside in.
//==============================================================================

class CellFilter : public Filter
{
public:
  //----------------------------------------------------------------------------
  // Constructors, destructors

  ~CellFilter() = default;

  //----------------------------------------------------------------------------
  // Methods

  std::string type() const override {return "cell";}

  void from_xml(pugi::xml_node node) override;

  void get_all_bins(const Particle& p, TallyEstimator estimator, FilterMatch& match)
  const override;

  void to_statepoint(hid_t filter_group) const override;

  std::string text_label(int bin) const override;

  //----------------------------------------------------------------------------
  // Accessors

  const vector<int32_t>& cells() const { return cells_; }

  void set_cells(gsl::span<int32_t> cells);

protected:
  //----------------------------------------------------------------------------
  // Data members

  //! The indices of the cells binned by this filter.
  vector<int32_t> cells_;

  //! A map from cell indices to filter bin indices.
  std::unordered_map<int32_t, int> map_;
};

} // namespace openmc
#endif // OPENMC_TALLIES_FILTER_CELL_H