/**
 *  SkDecodingImageGenerator has an Options struct which lets the
 *  client of the generator set sample size, dithering, and bitmap
 *  config.  This test loops through many possible options and tries
 *  them on a set of 5 small encoded images (each in a different
 *  format).  We test both SkData and SkStreamRewindable decoding.
 */
DEF_TEST(ImageDecoderOptions, reporter) {
    const char* files[]  = {
        "randPixels.bmp",
        "randPixels.jpg",
        "randPixels.png",
        "randPixels.webp",
        #if !defined(SK_BUILD_FOR_WIN)
        // TODO(halcanary): Find out why this fails sometimes.
        "randPixels.gif",
        #endif
    };

    SkString resourceDir = GetResourcePath();
    if (!sk_exists(resourceDir.c_str())) {
        return;
    }

    int scaleList[] = {1, 2, 3, 4};
    bool ditherList[] = {true, false};
    SkColorType colorList[] = {
        kAlpha_8_SkColorType,
        kRGB_565_SkColorType,
        kARGB_4444_SkColorType,  // Most decoders will fail on 4444.
        kN32_SkColorType
        // Note that indexed color is left out of the list.  Lazy
        // decoding doesn't do indexed color.
    };
    const bool useDataList[] = {true, false};

    for (size_t fidx = 0; fidx < SK_ARRAY_COUNT(files); ++fidx) {
        SkString path = SkOSPath::SkPathJoin(resourceDir.c_str(), files[fidx]);
        if (!sk_exists(path.c_str())) {
            continue;
        }

        SkAutoDataUnref encodedData(SkData::NewFromFileName(path.c_str()));
        REPORTER_ASSERT(reporter, encodedData.get() != NULL);
        SkAutoTUnref<SkStreamRewindable> encodedStream(
            SkStream::NewFromFile(path.c_str()));
        REPORTER_ASSERT(reporter, encodedStream.get() != NULL);

        for (size_t i = 0; i < SK_ARRAY_COUNT(scaleList); ++i) {
            for (size_t j = 0; j < SK_ARRAY_COUNT(ditherList); ++j) {
                for (size_t m = 0; m < SK_ARRAY_COUNT(useDataList); ++m) {
                    for (size_t k = 0; k < SK_ARRAY_COUNT(colorList); ++k) {
                        SkDecodingImageGenerator::Options opts(scaleList[i],
                                                               ditherList[j],
                                                               colorList[k]);
                        test_options(reporter, opts, encodedStream, encodedData,
                                     useDataList[m], path);

                    }
                    SkDecodingImageGenerator::Options options(scaleList[i],
                                                              ditherList[j]);
                    test_options(reporter, options, encodedStream, encodedData,
                                 useDataList[m], path);
                }
            }
        }
    }
}
std::string PhraseTableCreator::CompressEncodedCollection(std::string encodedCollection)
{
  enum EncodeState {
    ReadSymbol, ReadScore, ReadAlignment,
    EncodeSymbol, EncodeScore, EncodeAlignment
  };
  EncodeState state = ReadSymbol;

  unsigned phraseStopSymbolId;
  if(m_coding == REnc)
    phraseStopSymbolId = EncodeREncSymbol1(GetTargetSymbolId(m_phraseStopSymbol));
  else if(m_coding == PREnc)
    phraseStopSymbolId = EncodePREncSymbol1(GetTargetSymbolId(m_phraseStopSymbol));
  else
    phraseStopSymbolId = GetTargetSymbolId(m_phraseStopSymbol);
  AlignPoint alignStopSymbol(-1, -1);

  std::stringstream encodedStream(encodedCollection);
  encodedStream.unsetf(std::ios::skipws);

  std::string compressedEncodedCollection;
  BitWrapper<> bitStream(compressedEncodedCollection);

  unsigned symbol;
  float score;
  size_t currScore = 0;
  AlignPoint alignPoint;

  while(encodedStream) {
    switch(state) {
    case ReadSymbol:
      encodedStream.read((char*) &symbol, sizeof(unsigned));
      state = EncodeSymbol;
      break;
    case ReadScore:
      if(currScore == m_numScoreComponent) {
        currScore = 0;
        if(m_useAlignmentInfo)
          state = ReadAlignment;
        else
          state = ReadSymbol;
      } else {
        encodedStream.read((char*) &score, sizeof(float));
        currScore++;
        state = EncodeScore;
      }
      break;
    case ReadAlignment:
      encodedStream.read((char*) &alignPoint, sizeof(AlignPoint));
      state = EncodeAlignment;
      break;

    case EncodeSymbol:
      state = (symbol == phraseStopSymbolId) ? ReadScore : ReadSymbol;
      m_symbolTree->Put(bitStream, symbol);
      break;
    case EncodeScore: {
      state = ReadScore;
      size_t idx = m_multipleScoreTrees ? currScore-1 : 0;
      if(m_quantize)
        score = m_scoreCounters[idx]->LowerBound(score);
      m_scoreTrees[idx]->Put(bitStream, score);
    }
    break;
    case EncodeAlignment:
      state = (alignPoint == alignStopSymbol) ? ReadSymbol : ReadAlignment;
      m_alignTree->Put(bitStream, alignPoint);
      break;
    }
  }

  return compressedEncodedCollection;
}