void fixupOffset(BaleRegion br, int off) {
      // get offset in region given offset in view]
      if (num_lines == 0) return;
      int spos = 0;
      int line = 0;
      for (int i = 1; i < num_lines; ++i) {
        int npos =
            spos
                + line_data[i].getOffset()
                - line_data[i - 1].getOffset()
                + line_data[i - 1].getViewDelta();
        if (off < npos) break;
        spos = npos;
        line = i;
      }
      int delta = off - spos - line_data[line].getAdd();
      if (delta >= 0) return;

      int off0 = line_data[line].getOffset() + br.getStart();
      int len0 = line_data[line].getDelete();
      int len1 = line_data[line].getAdd();
      if (len0 != 0) len1 += indent_size;
      try {
        if (len1 > 0) {
          String s = "";
          for (int i = 0; i < len1; ++i) s += " ";
          base_document.insertString(off0, s, null);
        }
        if (len0 > 0) base_document.remove(off0 + len1, len0);
      } catch (BadLocationException e) {
        BoardLog.logE("BALE", "Problem fixing line indent", e);
        delta = 0;
      }
      regions_valid = false;
    }
  private void validateRegions() {
    if (region_map == null) return;

    synchronized (region_map) {
      if (regions_valid) return;

      Segment s = new Segment();

      region_map.clear();

      for (BaleRegion br : fragment_regions) {
        RegionData rd = new RegionData(indent_size);
        region_map.put(br, rd);
        int soff = br.getStart();
        int eoff = br.getEnd();
        if (eoff < soff) continue;
        try {
          base_document.getText(soff, eoff - soff, s);
        } catch (BadLocationException e) {
          BoardLog.logE("BALE", "Problem getting region indentation", e);
          continue;
        }
        int ln = s.length();

        LineData ld;
        boolean sol = true;
        for (int i = 0; i < ln; ++i) {
          char c = s.charAt(i);
          if (sol) {
            ld = computeLineData(i, s);
            rd.add(ld);
            sol = false;
          }
          if (c == '\n') sol = true;
        }
        if (!sol) {
          ld = computeLineData(ln, s);
          rd.add(ld);
          ++ln;
        }
      }

      regions_valid = true;
    }
  }
  /** ***************************************************************************** */
  private LineData computeLineData(int offset, Segment s) {
    int delchar = 0;
    int addchar = 0;
    int indent = 0;
    int ln = s.length();
    boolean havetab = false;

    for (int i = offset; indent < indent_size; ++i) {
      char c = (i < ln ? s.charAt(i) : '\n');
      if (c == ' ') {
        ++indent;
        ++delchar;
      } else if (c == '\t') {
        havetab = true;
        indent = nextTabPosition(indent);
        if (indent > indent_size) {
          delchar = (i - offset + 1);
          addchar = indent - indent_size;
          break;
        } else {
          ++delchar;
        }
      } else if (c == '\n') {
        if (havetab) {
          delchar = (i - offset);
          addchar = indent_size;
        } else {
          addchar = indent_size - (i - offset);
        }
        break;
      } else {
        BoardLog.logE("BALE", "Minimum space compute incorrectly");
        break;
      }
    }

    return new LineData(offset, addchar, delchar);
  }
  /** ***************************************************************************** */
  private void setupSpacing() {
    // get the tab_size from appropriate property
    BoardProperties bp = BoardProperties.getProperties("Bale");
    String v = bp.getProperty("indent.tabulation.size");
    if (v == null)
      v = BumpClient.getBump().getOption("org.eclipse.jdt.core.formatter.tabulation.size");
    if (v == null) v = bp.getProperty("Bale.tabsize");
    tab_size = 8;
    try {
      if (v != null) tab_size = Integer.parseInt(v);
    } catch (NumberFormatException e) {
    }

    region_map = null;
    regions_valid = true;
    indent_size = 0;
    indent_string = null;

    // determine minimum indent
    Segment s = new Segment();
    int minsp = -1;
    for (BaleRegion br : fragment_regions) {
      int soff = br.getStart();
      int eoff = br.getEnd();
      try {
        base_document.getText(soff, eoff - soff, s);
      } catch (BadLocationException e) {
        BoardLog.logE(
            "BALE",
            "Problem getting region text "
                + soff
                + " "
                + eoff
                + " "
                + s.length()
                + " "
                + base_document.getLength(),
            e);
        // should this be "throw e;"
        continue;
      }

      int ln = s.length();

      boolean sol = true;
      int ind = 0;
      for (int i = 0; i < ln && (minsp < 0 || minsp >= MIN_INDENT); ++i) {
        char c = s.charAt(i);
        if (sol) {
          switch (c) {
            case ' ':
              ind += 1;
              break;
            case '\t':
              ind = nextTabPosition(ind);
              break;
            case '\n':
              ind = 0;
              break;
            default:
              if (minsp < 0 || minsp > ind) minsp = ind;
              sol = false;
              break;
          }
        } else if (c == '\n') {
          sol = true;
          ind = 0;
        }
      }

      if (minsp >= 0 && minsp < MIN_INDENT) break;
    }

    if (minsp <= 0 || minsp < MIN_INDENT) return;

    indent_size = minsp;
    indent_string = "";
    for (int i = 0; i < minsp; ++i) indent_string += " ";

    region_map = new HashMap<BaleRegion, RegionData>();
    regions_valid = false;
    for (BaleRegion br : fragment_regions) {
      for (int i = getRegionLength(br) - 1; i >= 0; --i) {
        fixupOffset(br, i, true);
      }
    }
  }