/**
   * Define Dimensions, Variables, Attributes in ncfile
   *
   * @param raf ucar.unidata.io.RandomAccessFile corresponds of SIGMET datafile.
   * @param ncfile an empty NetcdfFile object which will be filled.
   * @param hdrNames java.util.Map with values for "StationName.." Attributes
   * @return ArrayList of Variables of ncfile
   */
  public ArrayList<Variable> init(
      ucar.unidata.io.RandomAccessFile raf,
      ucar.nc2.NetcdfFile ncfile,
      java.util.Map<String, String> hdrNames)
      throws java.io.IOException {
    // prepare attribute values
    String[] data_name = {
      " ", "TotalPower", "Reflectivity", "Velocity", "Width", "Differential_Reflectivity"
    };
    String[] unit = {" ", "dbZ", "dbZ", "m/sec", "m/sec", "dB"};
    int[] type = {1, 2, 3, 4, 5};
    String def_datafile = "SIGMET-IRIS";
    String tim = "";
    int ngates = 0;

    recHdr = readRecordsHdr(raf);
    hdrNames = readStnNames(raf);

    String stnName = hdrNames.get("StationName");
    String stnName_util = hdrNames.get("StationName_SetupUtility");
    float radar_lat =
        recHdr.get("radar_lat").floatValue(); // System.out.println("rad_lat="+radar_lat);
    float radar_lon =
        recHdr.get("radar_lon").floatValue(); // System.out.println("rad_lon="+radar_lon);
    short ground_height =
        recHdr.get("ground_height").shortValue(); // System.out.println("ground_H="+ground_height);
    short radar_height =
        recHdr.get("radar_height").shortValue(); // System.out.println("radar_H="+radar_height);
    int radar_alt =
        (recHdr.get("radar_alt").intValue()) / 100; // System.out.println("rad_alt="+radar_alt);
    short num_rays =
        recHdr.get("num_rays").shortValue(); // System.out.println("num_rays="+num_rays);
    short bins = recHdr.get("bins").shortValue(); // System.out.println("bins="+bins);
    float range_first =
        (recHdr.get("range_first").intValue())
            * 0.01f; // System.out.println("range_1st="+range_first);
    float range_last =
        (recHdr.get("range_last").intValue()) * 0.01f; // System.out.println("step="+step);
    short number_sweeps = recHdr.get("number_sweeps").shortValue();
    // System.out.println("number_sweeps="+number_sweeps);
    int nparams = (recHdr.get("nparams").intValue()); // System.out.println("nparams="+nparams);
    short year = recHdr.get("year").shortValue(); // System.out.println("year="+year);
    short month = recHdr.get("month").shortValue();
    short day = recHdr.get("day").shortValue();
    int base_time = (recHdr.get("base_time").intValue());

    // define number of gates for every sweep
    sweep_bins = new int[nparams * number_sweeps];
    if (number_sweeps > 1) {
      sweep_bins = volScan.getNumberGates();
    } else {
      for (int kk = 0; kk < nparams; kk++) {
        sweep_bins[kk] = bins;
      }
    }

    // add Dimensions
    Dimension scanR = new Dimension("scanR", number_sweeps, true);
    Dimension radial = new Dimension("radial", num_rays, true);
    Dimension[] gateR = new Dimension[number_sweeps];
    String dim_name = "gateR";
    for (int j = 0; j < number_sweeps; j++) {
      if (number_sweeps > 1) {
        dim_name = "gateR_sweep_" + (j + 1);
      }
      gateR[j] = new Dimension(dim_name, sweep_bins[j], true);
    }
    ncfile.addDimension(null, scanR);
    ncfile.addDimension(null, radial);
    for (int j = 0; j < number_sweeps; j++) {
      ncfile.addDimension(null, gateR[j]);
    }
    ArrayList<Dimension> dims0 = new ArrayList<Dimension>();
    ArrayList<Dimension> dims1 = new ArrayList<Dimension>();
    ArrayList<Dimension> dims2 = new ArrayList<Dimension>();
    ArrayList<Dimension> dims3 = new ArrayList<Dimension>();

    ArrayList<Variable> varList = new ArrayList<Variable>();

    Variable[][] v = new Variable[nparams][number_sweeps];
    String var_name = "";
    for (int j = 0; j < nparams; j++) {
      int tp = type[j];
      var_name = data_name[tp];
      for (int jj = 0; jj < number_sweeps; jj++) {
        if (number_sweeps > 1) {
          var_name = data_name[tp] + "_sweep_" + (jj + 1);
        }
        v[j][jj] = new Variable(ncfile, null, null, var_name);
        v[j][jj].setDataType(DataType.FLOAT);
        dims2.add(radial);
        dims2.add(gateR[jj]);
        v[j][jj].setDimensions(dims2);
        v[j][jj].addAttribute(new Attribute(CDM.LONG_NAME, var_name));
        v[j][jj].addAttribute(new Attribute(CDM.UNITS, unit[tp]));
        String coordinates = "time elevationR azimuthR distanceR";
        v[j][jj].addAttribute(new Attribute(_Coordinate.Axes, coordinates));
        v[j][jj].addAttribute(new Attribute(CDM.MISSING_VALUE, -999.99f));
        ncfile.addVariable(null, v[j][jj]);
        varList.add(v[j][jj]);
        dims2.clear();
      }
    }
    tsu_sec = new int[number_sweeps];
    String[] tsu = new String[number_sweeps];
    String[] time_units = new String[number_sweeps];
    tsu_sec = volScan.getStartSweep();
    for (int i = 0; i < number_sweeps; i++) {
      String st1 = Short.toString(month);
      if (st1.length() < 2) st1 = "0" + st1;
      String st2 = Short.toString(day);
      if (st2.length() < 2) st2 = "0" + st2;
      date0 = String.valueOf(year) + "-" + st1 + "-" + st2;
      tsu[i] = date0 + "T" + calcTime(tsu_sec[i], 0) + "Z";
    }
    for (int j = 0; j < number_sweeps; j++) {
      time_units[j] = "secs since " + tsu[j];
    }

    dims0.add(radial);
    // add "time" variable
    Variable[] time = new Variable[number_sweeps];
    String tm = "time";
    String tm_name = "";
    for (int j = 0; j < number_sweeps; j++) {
      tm_name = tm;
      if (number_sweeps > 1) {
        tm_name = tm + "_sweep_" + (j + 1);
      }
      time[j] = new Variable(ncfile, null, null, tm_name);
      time[j].setDataType(DataType.INT);
      time[j].setDimensions(dims0);
      time[j].addAttribute(new Attribute(CDM.LONG_NAME, "time from start of sweep"));
      time[j].addAttribute(new Attribute(CDM.UNITS, time_units[j]));
      time[j].addAttribute(new Attribute(_Coordinate.AxisType, AxisType.Time.toString()));
      time[j].addAttribute(new Attribute(CDM.MISSING_VALUE, -99));
      ncfile.addVariable(null, time[j]);
      varList.add(time[j]);
    }

    // add "elevationR" variable
    Variable[] elevationR = new Variable[number_sweeps];
    String ele = "elevationR";
    String ele_name = "";
    for (int j = 0; j < number_sweeps; j++) {
      ele_name = ele;
      if (number_sweeps > 1) {
        ele_name = ele + "_sweep_" + (j + 1);
      }
      elevationR[j] = new Variable(ncfile, null, null, ele_name);
      elevationR[j].setDataType(DataType.FLOAT);
      elevationR[j].setDimensions(dims0);
      elevationR[j].addAttribute(new Attribute(CDM.LONG_NAME, "elevation angle"));
      elevationR[j].addAttribute(new Attribute(CDM.UNITS, "degrees"));
      elevationR[j].addAttribute(
          new Attribute(_Coordinate.AxisType, AxisType.RadialElevation.toString()));
      elevationR[j].addAttribute(new Attribute(CDM.MISSING_VALUE, -999.99f));
      ncfile.addVariable(null, elevationR[j]);
      varList.add(elevationR[j]);
    }

    // add "azimuthR" variable
    Variable[] azimuthR = new Variable[number_sweeps];
    String azim = "azimuthR";
    String azim_name = "";
    for (int j = 0; j < number_sweeps; j++) {
      azim_name = azim;
      if (number_sweeps > 1) {
        azim_name = azim + "_sweep_" + (j + 1);
      }
      azimuthR[j] = new Variable(ncfile, null, null, azim_name);
      azimuthR[j].setDataType(DataType.FLOAT);
      azimuthR[j].setDimensions(dims0);
      azimuthR[j].addAttribute(new Attribute(CDM.LONG_NAME, "azimuth angle"));
      azimuthR[j].addAttribute(new Attribute(CDM.UNITS, "degrees"));
      azimuthR[j].addAttribute(
          new Attribute(_Coordinate.AxisType, AxisType.RadialAzimuth.toString()));
      azimuthR[j].addAttribute(new Attribute(CDM.MISSING_VALUE, -999.99f));
      ncfile.addVariable(null, azimuthR[j]);
      varList.add(azimuthR[j]);
    }

    // add "distanceR" variable
    Variable[] distanceR = new Variable[number_sweeps];
    String dName = "distanceR";
    String dist_name = "";
    for (int j = 0; j < number_sweeps; j++) {
      dist_name = dName;
      if (number_sweeps > 1) {
        dist_name = dName + "_sweep_" + (j + 1);
      }
      distanceR[j] = new Variable(ncfile, null, null, dist_name);
      distanceR[j].setDataType(DataType.FLOAT);
      dims1.add(gateR[j]);
      distanceR[j].setDimensions(dims1);
      distanceR[j].addAttribute(new Attribute(CDM.LONG_NAME, "radial distance"));
      distanceR[j].addAttribute(new Attribute(CDM.UNITS, "m"));
      distanceR[j].addAttribute(
          new Attribute(_Coordinate.AxisType, AxisType.RadialDistance.toString()));
      ncfile.addVariable(null, distanceR[j]);
      varList.add(distanceR[j]);
      dims1.clear();
    }
    // add "numGates" variable
    dims3.add(scanR);
    Variable numGates = new Variable(ncfile, null, null, "numGates");
    numGates.setDataType(DataType.INT);
    numGates.setDimensions(dims3);
    numGates.addAttribute(new Attribute(CDM.LONG_NAME, "number of gates in the sweep"));
    ncfile.addVariable(null, numGates);
    varList.add(numGates);

    // add global attributes
    ncfile.addAttribute(null, new Attribute("definition", "SIGMET-IRIS RAW"));
    ncfile.addAttribute(
        null, new Attribute("description", "SIGMET-IRIS data are reading by Netcdf IOSP"));
    ncfile.addAttribute(null, new Attribute("StationName", stnName));
    ncfile.addAttribute(null, new Attribute("StationName_SetupUtility", stnName_util));
    ncfile.addAttribute(null, new Attribute("radar_lat", radar_lat));
    ncfile.addAttribute(null, new Attribute("radar_lon", radar_lon));
    ncfile.addAttribute(null, new Attribute("ground_height", ground_height));
    ncfile.addAttribute(null, new Attribute("radar_height", radar_height));
    ncfile.addAttribute(null, new Attribute("radar_alt", radar_alt));
    ncfile.addAttribute(null, new Attribute("num_data_types", nparams));
    ncfile.addAttribute(null, new Attribute("number_sweeps", number_sweeps));
    String sn = "start_sweep";
    String snn = "";
    for (int j = 0; j < number_sweeps; j++) {
      snn = sn;
      if (number_sweeps > 1) {
        snn = sn + "_" + (j + 1);
      }
      ncfile.addAttribute(null, new Attribute(snn, tsu[j]));
    }
    ncfile.addAttribute(null, new Attribute("num_rays", num_rays));
    ncfile.addAttribute(null, new Attribute("max_number_gates", bins));
    ncfile.addAttribute(null, new Attribute("range_first", range_first));
    ncfile.addAttribute(null, new Attribute("range_last", range_last));
    ncfile.addAttribute(null, new Attribute("DataType", "Radial"));
    ncfile.addAttribute(null, new Attribute(CDM.CONVENTIONS, _Coordinate.Convention));

    // --------- fill all of values in the ncfile ------
    doNetcdfFileCoordinate(
        ncfile, volScan.base_time, volScan.year, volScan.month, volScan.day, varList, recHdr);

    ncfile.finish();

    return varList;
  }
  public Variable makeVariable(
      NetcdfFile ncfile,
      int datatype,
      String shortName,
      String longName,
      String abbrev,
      List groups)
      throws IOException {
    int nscans = groups.size();

    if (nscans == 0) {
      throw new IllegalStateException("No data for " + shortName);
    }

    // get representative record
    List firstGroup = (List) groups.get(0);
    Cinrad2Record firstRecord = (Cinrad2Record) firstGroup.get(0);
    int ngates = firstRecord.getGateCount(datatype);

    String scanDimName = "scan" + abbrev;
    String gateDimName = "gate" + abbrev;
    Dimension scanDim = new Dimension(scanDimName, nscans);
    Dimension gateDim = new Dimension(gateDimName, ngates);
    ncfile.addDimension(null, scanDim);
    ncfile.addDimension(null, gateDim);

    ArrayList dims = new ArrayList();
    dims.add(scanDim);
    dims.add(radialDim);
    dims.add(gateDim);

    Variable v = new Variable(ncfile, null, null, shortName);
    v.setDataType(DataType.BYTE);
    v.setDimensions(dims);
    ncfile.addVariable(null, v);

    v.addAttribute(new Attribute(CDM.UNITS, Cinrad2Record.getDatatypeUnits(datatype)));
    v.addAttribute(new Attribute(CDM.LONG_NAME, longName));

    byte[] b = new byte[2];
    b[0] = Cinrad2Record.MISSING_DATA;
    b[1] = Cinrad2Record.BELOW_THRESHOLD;
    Array missingArray = Array.factory(DataType.BYTE.getPrimitiveClassType(), new int[] {2}, b);

    v.addAttribute(new Attribute(CDM.MISSING_VALUE, missingArray));
    v.addAttribute(
        new Attribute("signal_below_threshold", new Byte(Cinrad2Record.BELOW_THRESHOLD)));
    v.addAttribute(
        new Attribute(CDM.SCALE_FACTOR, new Float(Cinrad2Record.getDatatypeScaleFactor(datatype))));
    v.addAttribute(
        new Attribute(CDM.ADD_OFFSET, new Float(Cinrad2Record.getDatatypeAddOffset(datatype))));
    v.addAttribute(new Attribute(CDM.UNSIGNED, "true"));

    ArrayList dim2 = new ArrayList();
    dim2.add(scanDim);
    dim2.add(radialDim);

    // add time coordinate variable
    String timeCoordName = "time" + abbrev;
    Variable timeVar = new Variable(ncfile, null, null, timeCoordName);
    timeVar.setDataType(DataType.INT);
    timeVar.setDimensions(dim2);
    ncfile.addVariable(null, timeVar);

    // int julianDays = volScan.getTitleJulianDays();
    // Date d = Cinrad2Record.getDate( julianDays, 0);
    // Date d = Cinrad2Record.getDate(volScan.getTitleJulianDays(), volScan.getTitleMsecs());
    Date d = volScan.getStartDate();
    String units = "msecs since " + formatter.toDateTimeStringISO(d);

    timeVar.addAttribute(new Attribute(CDM.LONG_NAME, "time since base date"));
    timeVar.addAttribute(new Attribute(CDM.UNITS, units));
    timeVar.addAttribute(new Attribute(CDM.MISSING_VALUE, new Integer(MISSING_INT)));
    timeVar.addAttribute(new Attribute(_Coordinate.AxisType, AxisType.Time.toString()));

    // add elevation coordinate variable
    String elevCoordName = "elevation" + abbrev;
    Variable elevVar = new Variable(ncfile, null, null, elevCoordName);
    elevVar.setDataType(DataType.FLOAT);
    elevVar.setDimensions(dim2);
    ncfile.addVariable(null, elevVar);

    elevVar.addAttribute(new Attribute(CDM.UNITS, "degrees"));
    elevVar.addAttribute(
        new Attribute(
            CDM.LONG_NAME,
            "elevation angle in degres: 0 = parallel to pedestal base, 90 = perpendicular"));
    elevVar.addAttribute(new Attribute(CDM.MISSING_VALUE, new Float(MISSING_FLOAT)));
    elevVar.addAttribute(new Attribute(_Coordinate.AxisType, AxisType.RadialElevation.toString()));

    // add azimuth coordinate variable
    String aziCoordName = "azimuth" + abbrev;
    Variable aziVar = new Variable(ncfile, null, null, aziCoordName);
    aziVar.setDataType(DataType.FLOAT);
    aziVar.setDimensions(dim2);
    ncfile.addVariable(null, aziVar);

    aziVar.addAttribute(new Attribute(CDM.UNITS, "degrees"));
    aziVar.addAttribute(
        new Attribute(CDM.LONG_NAME, "azimuth angle in degrees: 0 = true north, 90 = east"));
    aziVar.addAttribute(new Attribute(CDM.MISSING_VALUE, new Float(MISSING_FLOAT)));
    aziVar.addAttribute(new Attribute(_Coordinate.AxisType, AxisType.RadialAzimuth.toString()));

    // add gate coordinate variable
    String gateCoordName = "distance" + abbrev;
    Variable gateVar = new Variable(ncfile, null, null, gateCoordName);
    gateVar.setDataType(DataType.FLOAT);
    gateVar.setDimensions(gateDimName);
    Array data =
        Array.makeArray(
            DataType.FLOAT,
            ngates,
            (double) firstRecord.getGateStart(datatype),
            (double) firstRecord.getGateSize(datatype));
    gateVar.setCachedData(data, false);
    ncfile.addVariable(null, gateVar);
    radarRadius = firstRecord.getGateStart(datatype) + ngates * firstRecord.getGateSize(datatype);

    gateVar.addAttribute(new Attribute(CDM.UNITS, "m"));
    gateVar.addAttribute(new Attribute(CDM.LONG_NAME, "radial distance to start of gate"));
    gateVar.addAttribute(new Attribute(_Coordinate.AxisType, AxisType.RadialDistance.toString()));

    // add number of radials variable
    String nradialsName = "numRadials" + abbrev;
    Variable nradialsVar = new Variable(ncfile, null, null, nradialsName);
    nradialsVar.setDataType(DataType.INT);
    nradialsVar.setDimensions(scanDim.getName());
    nradialsVar.addAttribute(new Attribute(CDM.LONG_NAME, "number of valid radials in this scan"));
    ncfile.addVariable(null, nradialsVar);

    // add number of gates variable
    String ngateName = "numGates" + abbrev;
    Variable ngateVar = new Variable(ncfile, null, null, ngateName);
    ngateVar.setDataType(DataType.INT);
    ngateVar.setDimensions(scanDim.getName());
    ngateVar.addAttribute(new Attribute(CDM.LONG_NAME, "number of valid gates in this scan"));
    ncfile.addVariable(null, ngateVar);

    makeCoordinateDataWithMissing(
        datatype, timeVar, elevVar, aziVar, nradialsVar, ngateVar, groups);

    // back to the data variable
    String coordinates =
        timeCoordName + " " + elevCoordName + " " + aziCoordName + " " + gateCoordName;
    v.addAttribute(new Attribute(_Coordinate.Axes, coordinates));

    // make the record map
    int nradials = radialDim.getLength();
    Cinrad2Record[][] map = new Cinrad2Record[nscans][nradials];
    for (int i = 0; i < groups.size(); i++) {
      Cinrad2Record[] mapScan = map[i];
      List group = (List) groups.get(i);
      for (int j = 0; j < group.size(); j++) {
        Cinrad2Record r = (Cinrad2Record) group.get(j);
        int radial = r.radial_num - 1;
        mapScan[radial] = r;
      }
    }

    Vgroup vg = new Vgroup(datatype, map);
    v.setSPobject(vg);

    return v;
  }