/** Resets the state of the object to the initial state, as if the object was just created. */
  public void reset() {
    int maxsbi, minsbi;

    // Invalidate save
    saved = false;
    // Invalidate last encoded body buffer
    lbbuf = null;

    // Reinitialize each element in the arrays

    // Use reference caches to minimize array access overhead
    TagTreeEncoder ttIncl_t_c[][][], ttMaxBP_t_c[][][], ttIncl_t_c_r[][], ttMaxBP_t_c_r[][];
    int lblock_t_c[][][], prevtIdxs_t_c_r[][];

    // Loop on tiles
    for (int t = ttIncl.length - 1; t >= 0; t--) {
      // Loop on components
      for (int c = ttIncl[t].length - 1; c >= 0; c--) {
        // Initialize reference caches
        lblock_t_c = lblock[t][c];
        ttIncl_t_c = ttIncl[t][c];
        ttMaxBP_t_c = ttMaxBP[t][c];
        // Loop on resolution levels
        for (int r = lblock_t_c.length - 1; r >= 0; r--) {
          // Initialize reference caches
          ttIncl_t_c_r = ttIncl_t_c[r];
          ttMaxBP_t_c_r = ttMaxBP_t_c[r];
          prevtIdxs_t_c_r = prevtIdxs[t][c][r];

          // Loop on subbands
          minsbi = (r == 0) ? 0 : 1;
          maxsbi = (r == 0) ? 1 : 4;
          for (int s = minsbi; s < maxsbi; s++) {
            // Reset 'prevtIdxs'
            ArrayUtil.intArraySet(prevtIdxs_t_c_r[s], -1);
            // Reset 'lblock'
            ArrayUtil.intArraySet(lblock_t_c[r][s], INIT_LBLOCK);
          } // End loop on subbands

          // Loop on precincts
          for (int p = ppinfo[t][c][r].length - 1; p >= 0; p--) {
            if (p < ttIncl_t_c_r.length) {
              // Loop on subbands
              for (int s = minsbi; s < maxsbi; s++) {
                ttIncl_t_c_r[p][s].reset();
                ttMaxBP_t_c_r[p][s].reset();
              } // End loop on subbands
            }
          } // End loop on precincts
        } // End loop on resolution levels
      } // End loop on components
    } // End loop on tiles
  }
  /**
   * Creates a new packet header encoder, using the information from the 'infoSrc' object. The
   * information used is the number of components, number of tiles, subband decomposition, etc.
   *
   * <p>Note that this constructor visits all the tiles in the 'infoSrc' object. The 'infoSrc'
   * object is left at the original tile (i.e. the current tile before calling this constructor),
   * but any side effects of visiting the tiles is not reverted.
   *
   * @param infoSrc The source of information to construct the object.
   * @param encSpec The parameters for the encoding
   * @param maxNumPrec Maximum number of precinct in each tile, component and resolution level.
   * @param pl ParameterList instance that holds command line options
   */
  public PktEncoder(CodedCBlkDataSrcEnc infoSrc, J2KImageWriteParamJava wp, Point[][][] numPrec) {
    this.infoSrc = infoSrc;
    this.wp = wp;
    //        this.numPrec = numPrec;

    // Get number of components and tiles
    int nc = infoSrc.getNumComps();
    int nt = infoSrc.getNumTiles();

    // Do initial allocation
    ttIncl = new TagTreeEncoder[nt][nc][][][];
    ttMaxBP = new TagTreeEncoder[nt][nc][][][];
    lblock = new int[nt][nc][][][];
    prevtIdxs = new int[nt][nc][][][];
    ppinfo = new PrecInfo[nt][nc][][];

    // Finish allocation
    SubbandAn root, sb;
    int maxs, mins;
    int mrl;
    Point tmpCoord = null;
    int numcb; // Number of code-blocks
    Vector cblks = null;
    infoSrc.setTile(0, 0);
    for (int t = 0; t < nt; t++) { // Loop on tiles
      for (int c = 0; c < nc; c++) { // Loop on components
        // Get number of resolution levels
        root = infoSrc.getAnSubbandTree(t, c);
        mrl = root.resLvl;

        lblock[t][c] = new int[mrl + 1][][];
        ttIncl[t][c] = new TagTreeEncoder[mrl + 1][][];
        ttMaxBP[t][c] = new TagTreeEncoder[mrl + 1][][];
        prevtIdxs[t][c] = new int[mrl + 1][][];
        ppinfo[t][c] = new PrecInfo[mrl + 1][];

        for (int r = 0; r <= mrl; r++) { // Loop on resolution levels
          mins = (r == 0) ? 0 : 1;
          maxs = (r == 0) ? 1 : 4;

          int maxPrec = numPrec[t][c][r].x * numPrec[t][c][r].y;

          ttIncl[t][c][r] = new TagTreeEncoder[maxPrec][maxs];
          ttMaxBP[t][c][r] = new TagTreeEncoder[maxPrec][maxs];
          prevtIdxs[t][c][r] = new int[maxs][];
          lblock[t][c][r] = new int[maxs][];

          // Precincts and code-blocks
          ppinfo[t][c][r] = new PrecInfo[maxPrec];
          fillPrecInfo(t, c, r);

          for (int s = mins; s < maxs; s++) {
            // Loop on subbands
            sb = (SubbandAn) root.getSubbandByIdx(r, s);
            numcb = sb.numCb.x * sb.numCb.y;

            lblock[t][c][r][s] = new int[numcb];
            ArrayUtil.intArraySet(lblock[t][c][r][s], INIT_LBLOCK);

            prevtIdxs[t][c][r][s] = new int[numcb];
            ArrayUtil.intArraySet(prevtIdxs[t][c][r][s], -1);
          }
        }
      }
      if (t != nt - 1) infoSrc.nextTile();
    }
  }