/**
   * Retrives precincts and code-blocks coordinates in the given resolution, component and tile. It
   * terminates TagTreeEncoder initialization as well.
   *
   * @param t Tile index.
   * @param c Component index.
   * @param r Resolution level index.
   */
  private void fillPrecInfo(int t, int c, int r) {
    if (ppinfo[t][c][r].length == 0) return; // No precinct in this
    // resolution level

    Point tileI = infoSrc.getTile(null);
    Point nTiles = infoSrc.getNumTiles(null);

    int x0siz = infoSrc.getImgULX();
    int y0siz = infoSrc.getImgULY();
    int xsiz = x0siz + infoSrc.getImgWidth();
    int ysiz = y0siz + infoSrc.getImgHeight();
    int xt0siz = infoSrc.getTilePartULX();
    int yt0siz = infoSrc.getTilePartULY();
    int xtsiz = infoSrc.getNomTileWidth();
    int ytsiz = infoSrc.getNomTileHeight();

    int tx0 = (tileI.x == 0) ? x0siz : xt0siz + tileI.x * xtsiz;
    int ty0 = (tileI.y == 0) ? y0siz : yt0siz + tileI.y * ytsiz;
    int tx1 = (tileI.x != nTiles.x - 1) ? xt0siz + (tileI.x + 1) * xtsiz : xsiz;
    int ty1 = (tileI.y != nTiles.y - 1) ? yt0siz + (tileI.y + 1) * ytsiz : ysiz;

    int xrsiz = infoSrc.getCompSubsX(c);
    int yrsiz = infoSrc.getCompSubsY(c);

    int tcx0 = (int) Math.ceil(tx0 / (double) (xrsiz));
    int tcy0 = (int) Math.ceil(ty0 / (double) (yrsiz));
    int tcx1 = (int) Math.ceil(tx1 / (double) (xrsiz));
    int tcy1 = (int) Math.ceil(ty1 / (double) (yrsiz));

    int ndl = infoSrc.getAnSubbandTree(t, c).resLvl - r;
    int trx0 = (int) Math.ceil(tcx0 / (double) (1 << ndl));
    int try0 = (int) Math.ceil(tcy0 / (double) (1 << ndl));
    int trx1 = (int) Math.ceil(tcx1 / (double) (1 << ndl));
    int try1 = (int) Math.ceil(tcy1 / (double) (1 << ndl));

    int cb0x = infoSrc.getCbULX();
    int cb0y = infoSrc.getCbULY();

    double twoppx = (double) wp.getPrecinctPartition().getPPX(t, c, r);
    double twoppy = (double) wp.getPrecinctPartition().getPPY(t, c, r);
    int twoppx2 = (int) (twoppx / 2);
    int twoppy2 = (int) (twoppy / 2);

    // Precincts are located at (cb0x+i*twoppx,cb0y+j*twoppy)
    // Valid precincts are those which intersect with the current
    // resolution level
    int maxPrec = ppinfo[t][c][r].length;
    int nPrec = 0;

    int istart = (int) Math.floor((try0 - cb0y) / twoppy);
    int iend = (int) Math.floor((try1 - 1 - cb0y) / twoppy);
    int jstart = (int) Math.floor((trx0 - cb0x) / twoppx);
    int jend = (int) Math.floor((trx1 - 1 - cb0x) / twoppx);

    int acb0x, acb0y;

    SubbandAn root = infoSrc.getAnSubbandTree(t, c);
    SubbandAn sb = null;

    int p0x, p0y, p1x, p1y; // Precinct projection in subband
    int s0x, s0y, s1x, s1y; // Active subband portion
    int cw, ch;
    int kstart, kend, lstart, lend, k0, l0;
    int prg_ulx, prg_uly;
    int prg_w = (int) twoppx << ndl;
    int prg_h = (int) twoppy << ndl;

    CBlkCoordInfo cb;

    for (int i = istart; i <= iend; i++) { // Vertical precincts
      for (int j = jstart; j <= jend; j++, nPrec++) { // Horizontal precincts
        if (j == jstart && (trx0 - cb0x) % (xrsiz * ((int) twoppx)) != 0) {
          prg_ulx = tx0;
        } else {
          prg_ulx = cb0x + j * xrsiz * ((int) twoppx << ndl);
        }
        if (i == istart && (try0 - cb0y) % (yrsiz * ((int) twoppy)) != 0) {
          prg_uly = ty0;
        } else {
          prg_uly = cb0y + i * yrsiz * ((int) twoppy << ndl);
        }

        ppinfo[t][c][r][nPrec] =
            new PrecInfo(
                r,
                (int) (cb0x + j * twoppx),
                (int) (cb0y + i * twoppy),
                (int) twoppx,
                (int) twoppy,
                prg_ulx,
                prg_uly,
                prg_w,
                prg_h);

        if (r == 0) { // LL subband
          acb0x = cb0x;
          acb0y = cb0y;

          p0x = acb0x + j * (int) twoppx;
          p1x = p0x + (int) twoppx;
          p0y = acb0y + i * (int) twoppy;
          p1y = p0y + (int) twoppy;

          sb = (SubbandAn) root.getSubbandByIdx(0, 0);
          s0x = (p0x < sb.ulcx) ? sb.ulcx : p0x;
          s1x = (p1x > sb.ulcx + sb.w) ? sb.ulcx + sb.w : p1x;
          s0y = (p0y < sb.ulcy) ? sb.ulcy : p0y;
          s1y = (p1y > sb.ulcy + sb.h) ? sb.ulcy + sb.h : p1y;

          // Code-blocks are located at (acb0x+k*cw,acb0y+l*ch)
          cw = sb.nomCBlkW;
          ch = sb.nomCBlkH;
          k0 = (int) Math.floor((sb.ulcy - acb0y) / (double) ch);
          kstart = (int) Math.floor((s0y - acb0y) / (double) ch);
          kend = (int) Math.floor((s1y - 1 - acb0y) / (double) ch);
          l0 = (int) Math.floor((sb.ulcx - acb0x) / (double) cw);
          lstart = (int) Math.floor((s0x - acb0x) / (double) cw);
          lend = (int) Math.floor((s1x - 1 - acb0x) / (double) cw);

          if (s1x - s0x <= 0 || s1y - s0y <= 0) {
            ppinfo[t][c][r][nPrec].nblk[0] = 0;
            ttIncl[t][c][r][nPrec][0] = new TagTreeEncoder(0, 0);
            ttMaxBP[t][c][r][nPrec][0] = new TagTreeEncoder(0, 0);
          } else {
            ttIncl[t][c][r][nPrec][0] = new TagTreeEncoder(kend - kstart + 1, lend - lstart + 1);
            ttMaxBP[t][c][r][nPrec][0] = new TagTreeEncoder(kend - kstart + 1, lend - lstart + 1);
            ppinfo[t][c][r][nPrec].cblk[0] =
                new CBlkCoordInfo[kend - kstart + 1][lend - lstart + 1];
            ppinfo[t][c][r][nPrec].nblk[0] = (kend - kstart + 1) * (lend - lstart + 1);

            for (int k = kstart; k <= kend; k++) { // Vertical cblks
              for (int l = lstart; l <= lend; l++) { // Horiz. cblks

                cb = new CBlkCoordInfo(k - k0, l - l0);
                ppinfo[t][c][r][nPrec].cblk[0][k - kstart][l - lstart] = cb;
              } // Horizontal code-blocks
            } // Vertical code-blocks
          }
        } else { // HL, LH and HH subbands
          // HL subband
          acb0x = 0;
          acb0y = cb0y;

          p0x = acb0x + j * twoppx2;
          p1x = p0x + twoppx2;
          p0y = acb0y + i * twoppy2;
          p1y = p0y + twoppy2;

          sb = (SubbandAn) root.getSubbandByIdx(r, 1);
          s0x = (p0x < sb.ulcx) ? sb.ulcx : p0x;
          s1x = (p1x > sb.ulcx + sb.w) ? sb.ulcx + sb.w : p1x;
          s0y = (p0y < sb.ulcy) ? sb.ulcy : p0y;
          s1y = (p1y > sb.ulcy + sb.h) ? sb.ulcy + sb.h : p1y;

          // Code-blocks are located at (acb0x+k*cw,acb0y+l*ch)
          cw = sb.nomCBlkW;
          ch = sb.nomCBlkH;
          k0 = (int) Math.floor((sb.ulcy - acb0y) / (double) ch);
          kstart = (int) Math.floor((s0y - acb0y) / (double) ch);
          kend = (int) Math.floor((s1y - 1 - acb0y) / (double) ch);
          l0 = (int) Math.floor((sb.ulcx - acb0x) / (double) cw);
          lstart = (int) Math.floor((s0x - acb0x) / (double) cw);
          lend = (int) Math.floor((s1x - 1 - acb0x) / (double) cw);

          if (s1x - s0x <= 0 || s1y - s0y <= 0) {
            ppinfo[t][c][r][nPrec].nblk[1] = 0;
            ttIncl[t][c][r][nPrec][1] = new TagTreeEncoder(0, 0);
            ttMaxBP[t][c][r][nPrec][1] = new TagTreeEncoder(0, 0);
          } else {
            ttIncl[t][c][r][nPrec][1] = new TagTreeEncoder(kend - kstart + 1, lend - lstart + 1);
            ttMaxBP[t][c][r][nPrec][1] = new TagTreeEncoder(kend - kstart + 1, lend - lstart + 1);
            ppinfo[t][c][r][nPrec].cblk[1] =
                new CBlkCoordInfo[kend - kstart + 1][lend - lstart + 1];
            ppinfo[t][c][r][nPrec].nblk[1] = (kend - kstart + 1) * (lend - lstart + 1);

            for (int k = kstart; k <= kend; k++) { // Vertical cblks
              for (int l = lstart; l <= lend; l++) { // Horiz. cblks
                cb = new CBlkCoordInfo(k - k0, l - l0);
                ppinfo[t][c][r][nPrec].cblk[1][k - kstart][l - lstart] = cb;
              } // Horizontal code-blocks
            } // Vertical code-blocks
          }

          // LH subband
          acb0x = cb0x;
          acb0y = 0;

          p0x = acb0x + j * twoppx2;
          p1x = p0x + twoppx2;
          p0y = acb0y + i * twoppy2;
          p1y = p0y + twoppy2;

          sb = (SubbandAn) root.getSubbandByIdx(r, 2);
          s0x = (p0x < sb.ulcx) ? sb.ulcx : p0x;
          s1x = (p1x > sb.ulcx + sb.w) ? sb.ulcx + sb.w : p1x;
          s0y = (p0y < sb.ulcy) ? sb.ulcy : p0y;
          s1y = (p1y > sb.ulcy + sb.h) ? sb.ulcy + sb.h : p1y;

          // Code-blocks are located at (acb0x+k*cw,acb0y+l*ch)
          cw = sb.nomCBlkW;
          ch = sb.nomCBlkH;
          k0 = (int) Math.floor((sb.ulcy - acb0y) / (double) ch);
          kstart = (int) Math.floor((s0y - acb0y) / (double) ch);
          kend = (int) Math.floor((s1y - 1 - acb0y) / (double) ch);
          l0 = (int) Math.floor((sb.ulcx - acb0x) / (double) cw);
          lstart = (int) Math.floor((s0x - acb0x) / (double) cw);
          lend = (int) Math.floor((s1x - 1 - acb0x) / (double) cw);

          if (s1x - s0x <= 0 || s1y - s0y <= 0) {
            ppinfo[t][c][r][nPrec].nblk[2] = 0;
            ttIncl[t][c][r][nPrec][2] = new TagTreeEncoder(0, 0);
            ttMaxBP[t][c][r][nPrec][2] = new TagTreeEncoder(0, 0);
          } else {
            ttIncl[t][c][r][nPrec][2] = new TagTreeEncoder(kend - kstart + 1, lend - lstart + 1);
            ttMaxBP[t][c][r][nPrec][2] = new TagTreeEncoder(kend - kstart + 1, lend - lstart + 1);
            ppinfo[t][c][r][nPrec].cblk[2] =
                new CBlkCoordInfo[kend - kstart + 1][lend - lstart + 1];
            ppinfo[t][c][r][nPrec].nblk[2] = (kend - kstart + 1) * (lend - lstart + 1);

            for (int k = kstart; k <= kend; k++) { // Vertical cblks
              for (int l = lstart; l <= lend; l++) { // Horiz cblks
                cb = new CBlkCoordInfo(k - k0, l - l0);
                ppinfo[t][c][r][nPrec].cblk[2][k - kstart][l - lstart] = cb;
              } // Horizontal code-blocks
            } // Vertical code-blocks
          }

          // HH subband
          acb0x = 0;
          acb0y = 0;

          p0x = acb0x + j * twoppx2;
          p1x = p0x + twoppx2;
          p0y = acb0y + i * twoppy2;
          p1y = p0y + twoppy2;

          sb = (SubbandAn) root.getSubbandByIdx(r, 3);
          s0x = (p0x < sb.ulcx) ? sb.ulcx : p0x;
          s1x = (p1x > sb.ulcx + sb.w) ? sb.ulcx + sb.w : p1x;
          s0y = (p0y < sb.ulcy) ? sb.ulcy : p0y;
          s1y = (p1y > sb.ulcy + sb.h) ? sb.ulcy + sb.h : p1y;

          // Code-blocks are located at (acb0x+k*cw,acb0y+l*ch)
          cw = sb.nomCBlkW;
          ch = sb.nomCBlkH;
          k0 = (int) Math.floor((sb.ulcy - acb0y) / (double) ch);
          kstart = (int) Math.floor((s0y - acb0y) / (double) ch);
          kend = (int) Math.floor((s1y - 1 - acb0y) / (double) ch);
          l0 = (int) Math.floor((sb.ulcx - acb0x) / (double) cw);
          lstart = (int) Math.floor((s0x - acb0x) / (double) cw);
          lend = (int) Math.floor((s1x - 1 - acb0x) / (double) cw);

          if (s1x - s0x <= 0 || s1y - s0y <= 0) {
            ppinfo[t][c][r][nPrec].nblk[3] = 0;
            ttIncl[t][c][r][nPrec][3] = new TagTreeEncoder(0, 0);
            ttMaxBP[t][c][r][nPrec][3] = new TagTreeEncoder(0, 0);
          } else {
            ttIncl[t][c][r][nPrec][3] = new TagTreeEncoder(kend - kstart + 1, lend - lstart + 1);
            ttMaxBP[t][c][r][nPrec][3] = new TagTreeEncoder(kend - kstart + 1, lend - lstart + 1);
            ppinfo[t][c][r][nPrec].cblk[3] =
                new CBlkCoordInfo[kend - kstart + 1][lend - lstart + 1];
            ppinfo[t][c][r][nPrec].nblk[3] = (kend - kstart + 1) * (lend - lstart + 1);

            for (int k = kstart; k <= kend; k++) { // Vertical cblks
              for (int l = lstart; l <= lend; l++) { // Horiz cblks
                cb = new CBlkCoordInfo(k - k0, l - l0);
                ppinfo[t][c][r][nPrec].cblk[3][k - kstart][l - lstart] = cb;
              } // Horizontal code-blocks
            } // Vertical code-blocks
          }
        }
      } // Horizontal precincts
    } // Vertical precincts
  }