// stufpic.h
//
// Written by John A deLaubenfels, https://www.adaptune.com/steg.htm .
// Permission granted to use freely in any non-fraudulent way.
//
//
//
//
//
//



#pragma once

#include "globs.h"
#include "jgrlil.h"
#include "jarq.h"



// qxbitsPair

struct bitsPair {
   int nBits;                  // number of bits we can embed; might increase if hurdle isn't too high.
   int highRemain;              // any hurdle this high or higher won't bump nBits.

   bitsPair(int nb=0, int bh=0) : nBits(nb), highRemain(bh) {}
};  // struct bitsPair


// qx bitsLib

struct bitsLib {
   int                                numer;
   int                                denom;
   int                                maxBits;        // if > 0, never embed more bits than this
   int                                mostestBits;    // most bits that numer/denom can embed.
   std::vector<std::vector<bitsPair>> vcVcLib;

   bitsLib(int num=0, int den=0, int mb=0) : numer(num), denom(den), maxBits(mb), mostestBits(0) {
      this->clrPairs();
   } // bitsLib()...

   void clrPairs() {
      vcVcLib.clear();
      vcVcLib.resize(256);                                      // 256 iVals
      for(int iVal=0; iVal<256; iVal++) {
         std::vector<bitsPair> &vcPairs = vcVcLib[iVal];
         vcPairs.resize(256);                                   // 256 iOffsets
      } // for(int iVal=0; iVal<256; iVal++) 
   } // void clrPairs()

   inline int calcFast(int iVal, int iScatOff, int nHurdle) const {
      bitsPair bp = vcVcLib[iVal][iScatOff];

      int iRet = bp.nBits;
      if(bp.highRemain > nHurdle)
         iRet++;

      return iRet;
   } // inline int calcFast(int iVal, int iScatOff, int nHurdle) const

   int calcScattel(int iVal, int iScatOff, int nHurdle) const {
      if((iVal     < 0) || (iVal     >= 256)) return -1;
      if((iScatOff < 0) || (iScatOff >= 256)) return -1;

      bitsPair bp = vcVcLib[iVal][iScatOff];

      int iRet = bp.nBits;
      if(bp.highRemain > nHurdle)
         iRet++;

      return iRet;
   } // int calcScattel(int iVal, int iScatOff, int nHurdl) const 
}; // struct bitsLib



int updateShrink(const jgrLil &jgGuy, int bytesEmbed, int bytesBack, bool bScatter, int &fileBytesOut, int &widPix, int &hgtPix, double &safety, int maxBits, const std::vector<onePair> &vcBackRatios, twoPairs &twoGuys, MT64 &anMT);

int doEmbed(const jgrLil &jgSrc, jgrLil &jgDest, std::vector<unsigned char> &vcEmbed, const std::vector<unsigned long long> &passwordSeedVector, int widPix, int hgtPix, int maxBits, twoPairs &twoGuys, MT64 &anMTin, bool bScatter, bool bShuffle, bool bConserv, bool bTrim, onePair *pOneOverride);

int doExtract(jgrLil &jgGuy, const std::vector<unsigned long long> &passwordSeedVector, const std::vector<onePair> &vcBackRatios, JarqAnch &jrqOut);

double bitsCanTakeScattered(const jgrLil &jgGuy, int    nNumer, int nDenom, int maxBits, double *pBitsPerIval=NULL, double *pErrsPerIval=NULL, bitsLib *pBitsLib=NULL);

double bitsCanTakeScattered(const jgrLil &jgGuy, double dNumer, int nDenom, int maxBits);

inline double bytesCanTakeScattered(const jgrLil &jgGuy, int    nNumer, int nDenom, int maxBits, double *pBitsPerIval=NULL, double *pErrsPerIval=NULL, bitsLib *pBitsLib=NULL) {return bitsCanTakeScattered(jgGuy, nNumer, nDenom, maxBits, pBitsPerIval, pErrsPerIval, pBitsLib) / (double)BITS_PER_BYTE;}

inline double bytesCanTakeScattered(const jgrLil &jgGuy, double dNumer, int nDenom, int maxBits) {return bitsCanTakeScattered(jgGuy, dNumer, nDenom, maxBits) / (double)BITS_PER_BYTE;}

int calcScatter(int iVal, int iScatoff, int nNumer, int nDenom, int nHurdl, int maxBits, bool bDbg, int *pRemainOut=NULL, double *pValShiftAvg=NULL);

std::string makeSillyWord(MT64 &anMT, int nSyllables);

static void initByTwo(MT64 &anMT, const std::vector<unsigned long long> &passwordSeedVector, const char *secondPassword);

static void initByThree(MT64 &anMT, const std::vector<unsigned long long> &passwordSeedVector, const char *secondPassword, const char *thirdPassword);

int applyBytesg3(jgrLil &ajg, const UCHAR *cBytes, int nBytes, int nGuardNumer, int nGuardDenom, int maxBits, MT64 &anMT, bool bBackward, bool bFillEntireFile, bool bScatter, const bitsLib *pBitsLib=NULL, bool bShuffle=false, bool bConserv=false, bool bTrim=false);

int extractBytesg3(const jgrLil &ajg, UCHAR *&cBytes, int nValidIn, int nGuardNumer, int nGuardDenom, int maxBits, MT64 &anMT, bool bBackward, bool bScatter, const bitsLib *pBitsLib=NULL, bool bShuffle=false, bool bConserv=false, bool bTrim=false);

int bitsCanTakeg(const jgrLil &ajg, int nGuard);
inline int bytesCanTakeg(const jgrLil &ajg, int nGuard) {return (bitsCanTakeg(ajg, nGuard) / BITS_PER_BYTE);}

int bitsCanTakeg3(const jgrLil &ajg, int nNumer, int nDenom, int maxBits);
inline int bytesCanTakeg3(const jgrLil &ajg, int nNumer, int nDenom, int maxBits) {return (bitsCanTakeg3(ajg, nNumer, nDenom, maxBits) / BITS_PER_BYTE);}

int bytesCanTakegPegged(const jgrLil &ajg, int nGuard);


