private static void addVector(
      final String name,
      final MetadataElement orbitVectorListElem,
      final MetadataElement orbitElem,
      final int num) {
    final MetadataElement orbitVectorElem = new MetadataElement(name + num);

    final MetadataElement positionElem = orbitElem.getElement("position");
    final MetadataElement velocityElem = orbitElem.getElement("velocity");

    orbitVectorElem.setAttributeUTC(
        AbstractMetadata.orbit_vector_time,
        ReaderUtils.getTime(orbitElem, "time", standardDateFormat));

    orbitVectorElem.setAttributeDouble(
        AbstractMetadata.orbit_vector_x_pos, positionElem.getAttributeDouble("x", 0));
    orbitVectorElem.setAttributeDouble(
        AbstractMetadata.orbit_vector_y_pos, positionElem.getAttributeDouble("y", 0));
    orbitVectorElem.setAttributeDouble(
        AbstractMetadata.orbit_vector_z_pos, positionElem.getAttributeDouble("z", 0));
    orbitVectorElem.setAttributeDouble(
        AbstractMetadata.orbit_vector_x_vel, velocityElem.getAttributeDouble("x", 0));
    orbitVectorElem.setAttributeDouble(
        AbstractMetadata.orbit_vector_y_vel, velocityElem.getAttributeDouble("y", 0));
    orbitVectorElem.setAttributeDouble(
        AbstractMetadata.orbit_vector_z_vel, velocityElem.getAttributeDouble("z", 0));

    orbitVectorListElem.addElement(orbitVectorElem);
  }
  private static void addSRGRCoefficients(
      final MetadataElement absRoot, final MetadataElement coordinateConversion) {
    if (coordinateConversion == null) return;
    final MetadataElement coordinateConversionList =
        coordinateConversion.getElement("coordinateConversionList");
    if (coordinateConversionList == null) return;

    final MetadataElement srgrCoefficientsElem =
        absRoot.getElement(AbstractMetadata.srgr_coefficients);

    int listCnt = 1;
    for (MetadataElement elem : coordinateConversionList.getElements()) {
      final MetadataElement srgrListElem =
          new MetadataElement(AbstractMetadata.srgr_coef_list + '.' + listCnt);
      srgrCoefficientsElem.addElement(srgrListElem);
      ++listCnt;

      final ProductData.UTC utcTime = ReaderUtils.getTime(elem, "azimuthTime", standardDateFormat);
      srgrListElem.setAttributeUTC(AbstractMetadata.srgr_coef_time, utcTime);

      final double grOrigin = elem.getAttributeDouble("gr0", 0);
      AbstractMetadata.addAbstractedAttribute(
          srgrListElem,
          AbstractMetadata.ground_range_origin,
          ProductData.TYPE_FLOAT64,
          "m",
          "Ground Range Origin");
      AbstractMetadata.setAttribute(srgrListElem, AbstractMetadata.ground_range_origin, grOrigin);

      final String coeffStr =
          elem.getElement("grsrCoefficients").getAttributeString("grsrCoefficients", "");
      if (!coeffStr.isEmpty()) {
        final StringTokenizer st = new StringTokenizer(coeffStr);
        int cnt = 1;
        while (st.hasMoreTokens()) {
          final double coefValue = Double.parseDouble(st.nextToken());

          final MetadataElement coefElem =
              new MetadataElement(AbstractMetadata.coefficient + '.' + cnt);
          srgrListElem.addElement(coefElem);
          ++cnt;
          AbstractMetadata.addAbstractedAttribute(
              coefElem,
              AbstractMetadata.srgr_coef,
              ProductData.TYPE_FLOAT64,
              "",
              "SRGR Coefficient");
          AbstractMetadata.setAttribute(coefElem, AbstractMetadata.srgr_coef, coefValue);
        }
      }
    }
  }
  private static void addDopplerCentroidCoefficients(
      final MetadataElement absRoot, final MetadataElement dopplerCentroid) {
    if (dopplerCentroid == null) return;
    final MetadataElement dcEstimateList = dopplerCentroid.getElement("dcEstimateList");
    if (dcEstimateList == null) return;

    final MetadataElement dopplerCentroidCoefficientsElem =
        absRoot.getElement(AbstractMetadata.dop_coefficients);

    int listCnt = 1;
    for (MetadataElement elem : dcEstimateList.getElements()) {
      final MetadataElement dopplerListElem =
          new MetadataElement(AbstractMetadata.dop_coef_list + '.' + listCnt);
      dopplerCentroidCoefficientsElem.addElement(dopplerListElem);
      ++listCnt;

      final ProductData.UTC utcTime = ReaderUtils.getTime(elem, "azimuthTime", standardDateFormat);
      dopplerListElem.setAttributeUTC(AbstractMetadata.dop_coef_time, utcTime);

      final double refTime = elem.getAttributeDouble("t0", 0) * 1e9; // s to ns
      AbstractMetadata.addAbstractedAttribute(
          dopplerListElem,
          AbstractMetadata.slant_range_time,
          ProductData.TYPE_FLOAT64,
          "ns",
          "Slant Range Time");
      AbstractMetadata.setAttribute(dopplerListElem, AbstractMetadata.slant_range_time, refTime);

      final String coeffStr =
          elem.getElement("geometryDcPolynomial").getAttributeString("geometryDcPolynomial", "");
      if (!coeffStr.isEmpty()) {
        final StringTokenizer st = new StringTokenizer(coeffStr);
        int cnt = 1;
        while (st.hasMoreTokens()) {
          final double coefValue = Double.parseDouble(st.nextToken());

          final MetadataElement coefElem =
              new MetadataElement(AbstractMetadata.coefficient + '.' + cnt);
          dopplerListElem.addElement(coefElem);
          ++cnt;
          AbstractMetadata.addAbstractedAttribute(
              coefElem,
              AbstractMetadata.dop_coef,
              ProductData.TYPE_FLOAT64,
              "",
              "Doppler Centroid Coefficient");
          AbstractMetadata.setAttribute(coefElem, AbstractMetadata.dop_coef, coefValue);
        }
      }
    }
  }
  private static void addOrbitStateVectors(
      final MetadataElement absRoot, final MetadataElement orbitList) {
    final MetadataElement orbitVectorListElem =
        absRoot.getElement(AbstractMetadata.orbit_state_vectors);

    final MetadataElement[] stateVectorElems = orbitList.getElements();
    for (int i = 1; i <= stateVectorElems.length; ++i) {
      addVector(AbstractMetadata.orbit_vector, orbitVectorListElem, stateVectorElems[i - 1], i);
    }

    // set state vector time
    if (absRoot
        .getAttributeUTC(AbstractMetadata.STATE_VECTOR_TIME, AbstractMetadata.NO_METADATA_UTC)
        .equalElems(AbstractMetadata.NO_METADATA_UTC)) {

      AbstractMetadata.setAttribute(
          absRoot,
          AbstractMetadata.STATE_VECTOR_TIME,
          ReaderUtils.getTime(stateVectorElems[0], "time", standardDateFormat));
    }
  }