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

#include "pch.h"
#include "Steg2.h"
#include "afxdialogex.h"
#include "ssprint.h"
#include "EmbedDlg.h"
#include "PassDlg.h"
// #include "stufpic.h"
#include "jgrlil.h"
#include "ShowtxtDlg.h"
#include "mmsystem.h"     // for timeGetTime()
#include "fiwrap.h"
#include "wild.h"
// #include "rndWrap.h"

#pragma warning( disable : 4996 )


static int iFormat = 1;   // compress by default




// EmbedDlg dialog

IMPLEMENT_DYNAMIC(EmbedDlg, CDialogEx)

EmbedDlg::EmbedDlg(CWnd* pParent /*=nullptr*/)
   : CDialogEx(IDD_EMBED_PIC, pParent)
{

   m_enterAction = VK_TAB;
   m_bDidEmbedListThing = false;
   m_myJrq.setSize(1);                             // the dummy message guy, with blank file name.
   m_pCommonInfo = NULL;
   // m_pCommonInfo->maxBits     = 0;                              // 0 means "unlimited".

   // make a random guy anyone can use:
   std::vector<unsigned long long> aLongLongSeed;
   MT64::getAutoSeed(aLongLongSeed);
   m_anMT.init_by_array64(&(aLongLongSeed[0]), aLongLongSeed.size());
}

EmbedDlg::~EmbedDlg()
{
}

void EmbedDlg::DoDataExchange(CDataExchange* pDX)
{
    CDialogEx::DoDataExchange(pDX);
    DDX_Control(pDX, IDC_EDT_WRAPPER, m_cEdt_wrapper);
    DDX_Control(pDX, IDC_EDT_EMBEDS, m_cEdt_embeds);
    // DDX_Control(pDX, IDC_EDT_OUTFIL, m_cEdt_outfil);
    DDX_Control(pDX, IDC_EDT_OUTSIZ, m_cEdt_outsiz);
    DDX_Control(pDX, IDC_EDT_OUTWID, m_cEdt_outwid);
    DDX_Control(pDX, IDC_EDT_OUTHGT, m_cEdt_outhgt);
    DDX_Control(pDX, IDC_EDT_DIFFICULTY, m_cEdt_difficulty);
    DDX_Control(pDX, IDC_EDT_AVAILABLE, m_cEdt_available);
    DDX_Control(pDX, IDC_EDT_REQUIRED, m_cEdt_required);
    DDX_Control(pDX, IDC_STC_HAPPY, m_stcHappy);
    DDX_Control(pDX, IDC_SLIDER1, m_slySlider1);
    DDX_Control(pDX, IDC_CHK_SCATTER, m_chkScatter);
    DDX_Control(pDX, IDC_CHK_EMBFOLDER, m_chkEmbFolder);
}


BEGIN_MESSAGE_MAP(EmbedDlg, CDialogEx)
    ON_EN_KILLFOCUS(IDC_EDT_WRAPPER, &EmbedDlg::OnKillfocusEdtWrapper)
    ON_EN_KILLFOCUS(IDC_EDT_EMBEDS, &EmbedDlg::OnKillfocusEdtEmbeds)
    // ON_EN_KILLFOCUS(IDC_EDT_OUTFIL, &EmbedDlg::OnKillfocusEdtOutfil)
    ON_EN_KILLFOCUS(IDC_EDT_OUTSIZ, &EmbedDlg::OnKillfocusEdtOutsiz)
    ON_EN_KILLFOCUS(IDC_EDT_OUTWID, &EmbedDlg::OnKillfocusEdtOutwid)
    ON_EN_KILLFOCUS(IDC_EDT_OUTHGT, &EmbedDlg::OnKillfocusEdtOuthgt)
    ON_EN_KILLFOCUS(IDC_EDT_DIFFICULTY, &EmbedDlg::OnKillfocusEdtDifficulty)
    ON_BN_CLICKED(IDC_BUTN_WRAPPER, &EmbedDlg::OnBnClickedButnWrapper)
    ON_BN_CLICKED(IDC_BUTN_EMBEDS, &EmbedDlg::OnClickedButnEmbeds)
    // ON_BN_CLICKED(IDC_BUTN_OUTFIL, &EmbedDlg::OnClickedButnOutfil)
    ON_BN_CLICKED(IDC_BUTN_GO, &EmbedDlg::OnClickedButnGo)
    ON_BN_SETFOCUS(IDC_BUTN_GO, &EmbedDlg::OnSetfocusButnGo)
    ON_BN_KILLFOCUS(IDC_BUTN_GO, &EmbedDlg::OnKillfocusButnGo)
    ON_EN_SETFOCUS(IDC_EDT_WRAPPER, &EmbedDlg::OnSetfocusEdtWrapper)
    ON_EN_SETFOCUS(IDC_EDT_EMBEDS, &EmbedDlg::OnSetfocusEdtEmbeds)
    // ON_EN_SETFOCUS(IDC_EDT_OUTFIL, &EmbedDlg::OnSetfocusEdtOutfil)
    ON_EN_SETFOCUS(IDC_EDT_OUTSIZ, &EmbedDlg::OnSetfocusEdtOutsiz)
    ON_EN_SETFOCUS(IDC_EDT_OUTWID, &EmbedDlg::OnSetfocusEdtOutwid)
    ON_EN_SETFOCUS(IDC_EDT_OUTHGT, &EmbedDlg::OnSetfocusEdtOuthgt)
    ON_EN_SETFOCUS(IDC_EDT_DIFFICULTY, &EmbedDlg::OnSetfocusEdtDifficulty)
    ON_BN_CLICKED(IDC_BUTN_TYPEME, &EmbedDlg::OnClickedButnTypeme)
    ON_WM_HSCROLL()
    ON_WM_VSCROLL()
    ON_BN_CLICKED(IDC_CHK_SCATTER, &EmbedDlg::OnClickedChkScatter)
    ON_BN_CLICKED(IDC_CHK_EMBFOLDER, &EmbedDlg::OnClickedChkEmbFolder)
END_MESSAGE_MAP()



BOOL EmbedDlg::OnInitDialog() {
   CDialogEx::OnInitDialog();

   const char *pcSysRoot = getenv("SystemRoot");
   // m_cEdt_outfil.SetWindowText(pcSysRoot);

   hideChoices("");

   GetDlgItem(IDC_EDT_AVAILABLE)->ShowWindow(SW_HIDE);
   GetDlgItem(IDC_EDT_REQUIRED)->ShowWindow(SW_HIDE);
   GetDlgItem(IDC_STC_AVAILABLE)->ShowWindow(SW_HIDE);
   GetDlgItem(IDC_STC_REQUIRED)->ShowWindow(SW_HIDE);
   GetDlgItem(IDC_CHK_SCATTER)->ShowWindow(SW_HIDE);

   m_cEdt_wrapper.SetWindowText("Click me");
   m_cEdt_embeds.SetWindowText("Click me");

   if(m_pCommonInfo->useScatter < 0) {
      m_pCommonInfo->lastScatter = 0;
   } else if(m_pCommonInfo->useScatter > 0) {
      m_pCommonInfo->lastScatter = 1;
   } else {
      // leave lastScatter wherever it is.
   }
   m_chkScatter.SetCheck(m_pCommonInfo->lastScatter);
   m_chkEmbFolder.SetCheck(m_pCommonInfo->embFolder);
   if(m_pCommonInfo->embFolder == 0) {
      GetDlgItem(IDC_STC_FILES_TO_EMBED)->ShowWindow(SW_SHOW);
      GetDlgItem(IDC_STC_FOLDR_TO_EMBED)->ShowWindow(SW_HIDE);
   } else {
      GetDlgItem(IDC_STC_FILES_TO_EMBED)->ShowWindow(SW_HIDE);
      GetDlgItem(IDC_STC_FOLDR_TO_EMBED)->ShowWindow(SW_SHOW);
   } // !if(m_pCommonInfo->embFolder == 0)

   m_bytesRequired  = 0;
   m_bytesAvailable = 0;

   m_colFacts[0] = m_pCommonInfo->factBlu;
   m_colFacts[1] = m_pCommonInfo->factGrn;
   m_colFacts[2] = m_pCommonInfo->factRed;

   qprintf(fp_dbg, "Color factors: %6.3f %6.3f %6.3f\n", m_colFacts[0], m_colFacts[1], m_colFacts[2]);  // qxtemp

   return TRUE;  // return TRUE unless you set the focus to a control
   // EXCEPTION: OCX Property Pages should return FALSE
}




// EmbedDlg message handlers


BOOL EmbedDlg::PreTranslateMessage(MSG* pMsg)
{
   if (pMsg->message == WM_KEYDOWN) {
      if (pMsg->wParam == VK_RETURN)
         pMsg->wParam = m_enterAction;
   }
   return CDialogEx::PreTranslateMessage(pMsg);
}


void EmbedDlg::OnKillfocusEdtWrapper()
{
    // TODO: Add your control notification handler code here
}


void EmbedDlg::OnKillfocusEdtEmbeds()
{
    // TODO: Add your control notification handler code here
}


// void EmbedDlg::OnKillfocusEdtOutfil() {
//     // TODO: Add your control notification handler code here
// }


void EmbedDlg::OnBnClickedButnWrapper() {
   LPCTSTR pcFilter = _T("Image Files (*.jpg;*.jpeg;*.bmp;*.png)|*.jpg; *.jpeg; *.bmp; *.png||");
   DWORD dwFlags = 0;

   CFileDialog dlgOpen(TRUE, NULL, NULL, dwFlags, pcFilter);

   dlgOpen.m_ofn.lpstrTitle       = "Select wrapper input file";
   if(m_pCommonInfo->ssWrapperLoc.size() > 0)
      dlgOpen.m_ofn.lpstrInitialDir  = m_pCommonInfo->ssWrapperLoc.c_str();

   // m_ssFileName.clear();
   // m_ssPathName.clear();

   long long il = dlgOpen.DoModal();

   if(il == IDOK) {
      CWaitCursor wait1;

      CString csFileName = dlgOpen.GetFileName();
      m_ssFileName = (const char *)(LPCTSTR)csFileName;

      CString csPathName = dlgOpen.GetPathName();
      m_ssPathName = (const char *)(LPCTSTR)csPathName;

      qprintf(fp_dbg, "EmbedDlg::OnBnClickedButnWrapper() has set m_ssPathName to \"%s\".\n", m_ssPathName.c_str()); qflush(fp_dbg);

      m_cEdt_wrapper.SetWindowText(csPathName);

      int i = m_jgrSrc.readFile(m_ssPathName.c_str());
      if(i != 0) {
         m_cEdt_wrapper.SetWindowText("Failed!");
         m_jgrSrc.clear();
      } else {

         SMARTA(pcDir, char, (m_ssPathName.size()+32), smaDir);
         SMARTA(pcFil, char, (m_ssPathName.size()+32), smaFil);

         cut_file_name(m_ssPathName.c_str(), pcDir, pcFil);

         m_pCommonInfo->ssWrapperLoc = pcDir;

      } // !if(i != 0)

      if(m_jgrSrc.nHoriz() > 0) {
         if(m_pCommonInfo->lastScatter > 0) {
            m_bytesAvailable = (int)((bytesCanTakeScattered(m_jgrSrc, 1, 1, m_pCommonInfo->maxBits, NULL, NULL, NULL, m_colFacts) - 384.0) / 1.015);  // rough, conservative guess.
         } else {
            m_bytesAvailable = (int)((bytesCanTakeg3(m_jgrSrc, 1, 1, m_pCommonInfo->maxBits) - 384.0) / 1.015);  // rough, conservative guess.
         } // !if(m_pCommonInfo->lastScatter > 0)

         GetDlgItem(IDC_EDT_AVAILABLE)->ShowWindow(SW_SHOW);
         GetDlgItem(IDC_STC_AVAILABLE)->ShowWindow(SW_SHOW);
         if(m_pCommonInfo->useScatter == 0)                       // -1 and 1 are forcing; 0 means user's choice.
            GetDlgItem(IDC_CHK_SCATTER)->ShowWindow(SW_SHOW);

         const int maxxie = 256;
         char ccomma[maxxie];
         comma_me(m_bytesAvailable, ccomma, maxxie);
         m_cEdt_available.SetWindowText(ccomma);
      } // if(m_jgrSrc.nHoriz() > 0)

      if((m_bytesRequired > 0) && (m_jgrSrc.nHoriz() > 0)) {
         calcWrap();
      } else {
         hideChoices("");
      } // !if((m_vcSsEmbedFiles.size() > 0) && (m_jgrSrc.nHoriz() > 0)) {
   } // if(il == IDOK)

   return;
} // void EmbedDlg::OnBnClickedButnWrapper()...



void EmbedDlg::OnClickedButnEmbeds() {

   if(m_pCommonInfo->embFolder == 0) {
      CFileDialog dlgOpen(TRUE);

      OPENFILENAME& ofn = dlgOpen.GetOFN();
      ofn.Flags |= OFN_ALLOWMULTISELECT;

      if(m_pCommonInfo->ssEmbedLoc.size() > 0)
         dlgOpen.m_ofn.lpstrInitialDir  = m_pCommonInfo->ssEmbedLoc.c_str();

      // Create buffer for several filenames:
      const int iSiz = 10000000;     // ten million.
      SMARTA(pBuf, char, iSiz, smaBuf);
      dlgOpen.m_ofn.lpstrFile = pBuf;
      dlgOpen.m_ofn.nMaxFile  = iSiz;
      // for some reason this is necessary:
      pBuf[0] = '\0';


      dlgOpen.m_ofn.lpstrTitle  = "Select file(s) to embed";

      if(dlgOpen.DoModal() != IDOK)
         return;

      CWaitCursor wait1;

      CString csFileName = dlgOpen.GetFileName();
      std::string ssFileName = (const char *)(LPCTSTR)csFileName;

      CString csPathName = dlgOpen.GetPathName();
      std::string ssPathName = (const char *)(LPCTSTR)csPathName;

      qprintf(fp_dbg, "ssFileName = \"%s\"; ssPathName = \"%s\".\n", ssFileName.c_str(), ssPathName.c_str());  // qxtemp

      if(is_a_dir(ssPathName.c_str())) {
         // this seems to happen when we choose multiple files.
         m_pCommonInfo->ssEmbedLoc = ssPathName;
      } else {
         // happens when we choose a single file; wheeee!
         SMARTA(pcDir, char, (ssPathName.size()+32), smaDir);
         SMARTA(pcFil, char, (ssPathName.size()+32), smaFil);

         cut_file_name(ssPathName.c_str(), pcDir, pcFil);

         m_pCommonInfo->ssEmbedLoc = pcDir;
      } // !if(is_a_dir(ssPathName.c_str()))

#ifdef WONT_GET_EXERCISED  // nothing is blank.
      if(m_pCommonInfo->ssEmbedFoldr.size() == 0)
         m_pCommonInfo->ssEmbedFoldr = m_pCommonInfo->ssEmbedLoc;
#endif // WONT_GET_EXERCISED  // nothing is blank.

      m_vcSsEmbedFiles.clear();
      m_myJrq.setSize(1);                             // leave only the dummy message guy, with blank file name.
      m_vcToStuff.clear();

      POSITION pos = dlgOpen.GetStartPosition();

      if(pos) {
         CString PathName;

         do {
           PathName = dlgOpen.GetNextPathName(pos);
           // Do something with 'PathName'
           // fprintf(fp_out, "%s\n", (LPCTSTR)PathName);

           m_vcSsEmbedFiles.push_back((const char *)(LPCTSTR)PathName);
         } while(pos);
      }

      // fclose(fp_out); fp_out=NULL;

      m_myJrq.addFiles(m_vcSsEmbedFiles, iFormat, true);  // true: don't save path info of files in archive.

      recalcStuffVec(true);                               // true: do everything.


      switch(m_vcSsEmbedFiles.size()) {
         case 0:
            m_cEdt_embeds.SetWindowText("Try again");
            break;
         case 1:
            m_cEdt_embeds.SetWindowText(csPathName);
            break;
         default:
            char cbuf[256];
            sprintf(cbuf, "[%d files selected]", (int)m_vcSsEmbedFiles.size());
            m_cEdt_embeds.SetWindowText(cbuf);
            break;
      } // switch(m_vcSsEmbedFiles.size())

   } else {

      // m_pCommonInfo->embFolder != 0 : go for folder(s)

//    CFolderPickerDialog dlgFoldr(m_pCommonInfo->ssEmbedFoldr.c_str());
      CFolderPickerDialog dlgFoldr;

      OPENFILENAME& ofn = dlgFoldr.GetOFN();
      ofn.Flags |= OFN_ALLOWMULTISELECT;

      if(m_pCommonInfo->ssEmbedFoldr.size() > 0)
         dlgFoldr.m_ofn.lpstrInitialDir  = m_pCommonInfo->ssEmbedFoldr.c_str();

      dlgFoldr.m_ofn.lpstrTitle  = "Select folder(s) to embed";

      if(dlgFoldr.DoModal() != IDOK)
         return;

      CWaitCursor wait1;

      CString csFileName = dlgFoldr.GetFileName();
      std::string ssFileName = (const char *)(LPCTSTR)csFileName;

      CString csPathName = dlgFoldr.GetPathName();
      std::string ssPathName = (const char *)(LPCTSTR)csPathName;

      qprintf(fp_dbg, "Foldr ssFileName = \"%s\"; ssPathName = \"%s\".\n", ssFileName.c_str(), ssPathName.c_str());  // qxtemp

      // m_pCommonInfo->ssEmbedFoldr = ssPathName;

      if(ssFileName.size() == 0) {
         // this seems to happen when we choose multiple files.
         m_pCommonInfo->ssEmbedFoldr = ssPathName;
      } else {
         // happens when we choose a single file; wheeee!
         SMARTA(pcDir, char, (ssPathName.size()+32), smaDir);
         SMARTA(pcFil, char, (ssPathName.size()+32), smaFil);

         cut_file_name(ssPathName.c_str(), pcDir, pcFil);

         m_pCommonInfo->ssEmbedFoldr = pcDir;
      } // !if(is_a_dir(ssPathName.c_str()))

#ifdef WONT_GET_EXERCISED  // nothing is blank.
      if(m_pCommonInfo->ssEmbedLoc.size() == 0)
         m_pCommonInfo->ssEmbedLoc = m_pCommonInfo->ssEmbedFoldr;
#endif // WONT_GET_EXERCISED  // nothing is blank.

      m_vcSsEmbedFiles.clear();
      m_myJrq.setSize(1);                             // leave only the dummy message guy, with blank file name.
      m_vcToStuff.clear();
      vetSet<std::string> vtSrcFiles;

      POSITION pos = dlgFoldr.GetStartPosition();

      if(pos) {
         CString PathName;

         do {
           PathName = dlgFoldr.GetNextPathName(pos);
           // Do something with 'PathName'
           qprintf(fp_dbg, "Possible folder name: %s\n", (LPCTSTR)PathName);

           fillSrcFiles((LPCTSTR)PathName, vtSrcFiles, -1, true);  // -1: down forever; true: include final folders

//         m_vcSsEmbedFiles.push_back((const char *)(LPCTSTR)PathName);
         } while(pos);
      }
      m_vcSsEmbedFiles = vtSrcFiles.getVec();

      std::string ssTrim;         // consistent early folder stuff that we'll trim off of saved file names
      if(vtSrcFiles.size() > 0) {
         std::string ssOne = vtSrcFiles[0];
         std::string ssUndr;

         cut_file_name(ssOne.c_str(), ssTrim, ssUndr);

         if((ssTrim.size() > 0) && (!is_slash(ssTrim[ssTrim.size()-1]))) {
            ssTrim += SLASH;
         } // if((ssTrim.size() > 0) && (!is_slash(ssone[ssTrim.size()-1])))
      } // if(vtSrcFiles.size() > 0)

      m_myJrq.addFiles(m_vcSsEmbedFiles, iFormat, false);  // false: do save path info of files in archive.

      // strip off consistent prefix folder:
      if(ssTrim.size() > 0) {
         for(int i=0; i<m_myJrq.size(); i++) {
            JarqOne *pOne = m_myJrq.getIthOne(i);
            std::string ssNow, ssDir, ssFil;
            ssNow = pOne->getFileNams();

            // if blank file name, don't modify.
            if(ssNow.size() == 0)
               continue;

            if(ssNow.find(ssTrim) == 0) {
               std::string ssLil = ssNow.substr(ssTrim.size(), std::string::npos);

               pOne->setFileName(ssLil.c_str());
            } // if(ssNow.find(ssTrim) == 0)

         } // for(int i=0; i<m_myJrq.size(); i++)
      } // if(ssTrim.size() > 0)

      recalcStuffVec(true);                               // true: do everything.

      switch(m_vcSsEmbedFiles.size()) {
         case 0:
            m_cEdt_embeds.SetWindowText("Try again");
            break;
         case 1:
            m_cEdt_embeds.SetWindowText(csPathName);
            break;
         default:
            char cbuf[256];
            sprintf(cbuf, "[%d files selected]", (int)m_vcSsEmbedFiles.size());
            m_cEdt_embeds.SetWindowText(cbuf);
            break;
      } // switch(m_vcSsEmbedFiles.size())
   } // !if(m_pCommonInfo->embFolder == 0)


   return;
}




void EmbedDlg::OnClickedButnGo() {
   // too soon?
   if((m_bytesRequired == 0) || (m_jgrSrc.nHoriz() == 0) || (m_bytesAvailable < m_bytesRequired))
      return;

   // get 80-byte vector from password:
   PassDlg dlgP;
   dlgP.m_pCommonInfo = m_pCommonInfo;

   long long il = dlgP.DoModal();

   if(il == IDOK) {
      // char cbuf[1024];

      m_passwordSeedVector = dlgP.m_passwordSeedVector;
      zeroMe(dlgP.m_passwordSeedVector);

      unsigned long tgt0 = timeGetTime();

      CWaitCursor wait1;

      int nCycle = 100000;
      MT64::rescrambleVector(m_passwordSeedVector, nCycle);

      unsigned long tgt1 = timeGetTime();

      // char cbuf[256];
      // sprintf(cbuf, "Time spent rescrambling: %ld msec.", (tgt1 - tgt0));
      // doThing(cbuf);

      // m_jgrOut = m_jgrSrc;

      onePair overRidy;
      onePair *pOneOverride = NULL;
      if((m_pCommonInfo->nNumer > 0) && (m_pCommonInfo->nDenom > 0)) {
         overRidy.numer = m_pCommonInfo->nNumer;
         overRidy.denom = m_pCommonInfo->nDenom;
         pOneOverride = &overRidy;
      } // if((m_pCommonInfo->nNumer > 0) && (m_pCommonInfo->nDenom > 0))

      int iCyc(0), ij(NADA);
      for(iCyc=0; iCyc<16; iCyc++) {
         unsigned long long ull0 = getProccyTime();

         ij = doEmbed(m_jgrSrc, m_jgrOut, m_vcToStuff, m_passwordSeedVector, m_iOutwid, m_iOuthgt, m_pCommonInfo->maxBits, m_twoGuys, m_anMT, m_pCommonInfo->lastScatter, m_pCommonInfo->bShuffle, m_pCommonInfo->bConserv, m_pCommonInfo->bTrim, pOneOverride, m_colFacts);

         unsigned long long ull1 = getProccyTime();
         unsigned long long ullDif = ull1 - ull0;

         double secTot = (double)(ullDif) / 1.0E7;      // yep, ten MILLION slices per second from this function.
         double minTot = secTot / 60.0;
         double hrrTot = minTot / 60.0;

         const char *pSucc = ((ij == 0) ? ("success") : ("FAIL"));

         qprintf(fp_dbg, "doEmbed() %s: %llu (%8.3f seconds, %8.3f minutes, %8.3f hours).\n", pSucc, ullDif, secTot, minTot, hrrTot);

         if(ij == 0)
            break;

         // failed; try again.
         recalcStuffVec(false);    // false: quick out: same size as before.
      } // for(iCyc=0; iCyc<16; iCyc++)

      if(ij == 0) {
         qprintf(fp_dbg, "doEmbed() returns 0 in iCyc %d.\n", iCyc);

         std::string ssDir, ssFil, ssNuu;
         cut_file_name(m_ssPathName.c_str(), ssDir, ssFil);


         while(1) {
            std::string ssSilly = makeSillyWord(m_anMT, 2);

            ssprint(ssNuu, "%s%c%s", ssDir.c_str(), SLASH, ssSilly.c_str());

            if(!is_a_dir(ssNuu.c_str()))
               break;

         } // while(1)

         mkdirWrap(ssNuu.c_str());
         std::string ssTempy = ssNuu;
         ssAppend(ssTempy, "%c%s", SLASH, "blah.dbg");
         m_pCommonInfo->vcSsBlahNames.push_back(ssTempy);

//       sprintf(cbuf, "explorer /e,""%s""", ssNuu.c_str());

         m_pCommonInfo->ssName        = ssNuu;
         m_pCommonInfo->ssExtractWarm = ssNuu;

         std::string ssBody, ssDott, ssExtt;
         break_file_name(m_ssFileName.c_str(), ssBody, ssDott, ssExtt);

         ssAppend(ssNuu, "%c%s%s", SLASH, ssBody.c_str(), ".bmp");

         m_jgrOut.writeBmp(ssNuu.c_str());
         if(m_pCommonInfo->doPng) {
            std::string ssPng = ReplaceExtension(ssNuu.c_str(), PNG_EXT1);
            bmpToPng(ssNuu.c_str(), ssPng.c_str());

            if(!m_pCommonInfo->doBmp) {
               remove(ssNuu.c_str());
            } // if(!m_pCommonInfo->doBmp)
         } // if(m_pCommonInfo->doPng)

         qprintf(fp_dbg, "Wrote stuffed file at %s.\n", ssNuu.c_str());
      } else {
         // barfed!
         qflush(fp_dbg);
         AfxMessageBox("Something barfed.");
      } // !if(ij == 0)

      // in case we want to output again; doEmbed() scrambled it.
      int iSizHold = m_iOutsiz;
      int iWidHold = m_iOutwid;
      int iHgtHold = m_iOuthgt;
      m_jgrOut.clear();
      recalcStuffVec(false);    // false: quick out: same size as before.
   } // if(il == IDOK)
}


void EmbedDlg::OnSetfocusButnGo()
{
    // TODO: Add your control notification handler code here
    m_enterAction = VK_RETURN;
}


void EmbedDlg::OnKillfocusButnGo()
{
    // TODO: Add your control notification handler code here
    m_enterAction = VK_TAB;

}


void EmbedDlg::OnSetfocusEdtWrapper()
{
   m_enterAction = VK_TAB;

#ifdef GETS_ALL_TANGLED_UP
   char cbuf[256];
   m_cEdt_wrapper.GetWindowText(cbuf, 256);
   if(strlen(cbuf) == 0)
      PostMessage(WM_COMMAND, IDC_BUTN_WRAPPER);
#endif // GETS_ALL_TANGLED_UP

   // qprintf(fp_dbg, "EmbedDlg::OnSetfocusEdtWrapper() has m_ssPathName \"%s\".\n", m_ssPathName.c_str()); qflush(fp_dbg);

#ifdef REPLACED_D
   if(m_ssPathName.size() == 0) {
      m_ssPathName = "x";
      PostMessage(WM_COMMAND, IDC_BUTN_WRAPPER);
   } // if(m_ssPathName.size() == 0)
#endif // REPLACED_D


   if(!m_bDidWrapThing) {
      m_bDidWrapThing = true;
      m_cEdt_wrapper.SetWindowText("");
      PostMessage(WM_COMMAND, IDC_BUTN_WRAPPER);
   } // if(!m_bDidWrapThing)
}


void EmbedDlg::OnSetfocusEdtEmbeds()
{
   m_enterAction = VK_TAB;

   if(!m_bDidEmbedListThing) {
      m_bDidEmbedListThing = true;
      m_cEdt_embeds.SetWindowText("");
      PostMessage(WM_COMMAND, IDC_BUTN_EMBEDS);
   } // if(!m_bDidEmbedListThing)
}


// void EmbedDlg::OnSetfocusEdtOutfil() {
//     // TODO: Add your control notification handler code here
//     m_enterAction = VK_TAB;
// }



// qxapplyFourGuys()

void EmbedDlg::applyFourGuys() {
   char cbuf[256];

   if((m_jgrSrc.nHoriz() == 0) || (m_bytesRequired == 0)) {
      hideChoices("");
   } else if(m_bytesAvailable < m_bytesRequired) {
      hideChoices("Either pick a larger wrapper file or smaller embed(s).");
   } else {
      showChoices("If you're happy with the sizes shown below, click GO, otherwise...");

      comma_me(m_iOutsiz, cbuf, 256);
      m_ssOutsiz = cbuf;
      m_cEdt_outsiz.SetWindowText(m_ssOutsiz.c_str());

      ssprint(m_ssOutwid, "%d", m_iOutwid);
      // sprintf(cbuf, "%d", m_iOutwid);
      // m_ssOutwid = cbuf;
      m_cEdt_outwid.SetWindowText(m_ssOutwid.c_str());

      ssprint(m_ssOuthgt, "%d", m_iOuthgt);
      // sprintf(cbuf, "%d", m_iOuthgt);
      // m_ssOuthgt = cbuf;
      m_cEdt_outhgt.SetWindowText(m_ssOuthgt.c_str());

      ssprint(m_ssDifficulty, "%.*f", m_pCommonInfo->nDigitsSafe, m_difficulty);
      // sprintf(cbuf, "%.*f", m_pCommonInfo->nDigitsSafe, m_difficulty);
      // m_ssDifficulty = cbuf;
      m_cEdt_difficulty.SetWindowText(m_ssDifficulty.c_str());

      // update slider:
      int ipos = m_iHii - (int)(0.5 + 100.0 * m_difficulty);
      m_slySlider1.SetPos(ipos);
   } // !if((m_vcSsEmbedFiles.size() == 0) || (m_jgrSrc.nHoriz() == 0) || (m_bytesAvailable < m_bytesRequired))
}



// qxrecalcStuffVec()

void EmbedDlg::recalcStuffVec(bool bDoFull) {
   m_vcToStuff.clear();

   int nSkip = 0;
   if(m_ssTypedMessage.size() == 0)
      nSkip = 1;                           // don't need to archive the first, dummy guy, for blank message.

   if((m_myJrq.size() - nSkip) > 0) {
      spitObj mySpit(NULL, &m_vcToStuff);
      m_myJrq.archiveJarq(NADA, mySpit, 12, nSkip);  // 12 extra bytes at the beginning.
   } // if((m_myJrq.size() - nSkip) > 0)

   if(!bDoFull) {
      // when we know it'll come back as before, but unscrambled.
      int bytesNew = (int)m_vcToStuff.size();

      // sanity check:
      if(bytesNew != m_bytesRequired) {
         int bytesDiff = bytesNew - m_bytesRequired;
         qprintf(fp_dbg, "New bytes is %d different from old: %d -> %d.\n", bytesDiff, m_bytesRequired, bytesNew);

         char cbuf[256];
         sprintf(cbuf, "New bytes is %d different from old: %d -> %d.\n", bytesDiff, m_bytesRequired, bytesNew);
         AfxMessageBox(cbuf);  // qxtemp.
      } // if(bytesNew != m_bytesRequired)

      return;
   } // if(!bDoFull)

   m_bytesRequired = (int)m_vcToStuff.size();

   if(m_bytesRequired > 0) {
      GetDlgItem(IDC_EDT_REQUIRED)->ShowWindow(SW_SHOW);
      GetDlgItem(IDC_STC_REQUIRED)->ShowWindow(SW_SHOW);

      const int maxxie = 256;
      char ccomma[maxxie];
      comma_me(m_bytesRequired, ccomma, maxxie);
      m_cEdt_required.SetWindowText(ccomma);
   } else {
      GetDlgItem(IDC_EDT_REQUIRED)->ShowWindow(SW_HIDE);
      GetDlgItem(IDC_STC_REQUIRED)->ShowWindow(SW_HIDE);

      m_cEdt_required.SetWindowText("0");
   } // if(m_bytesRequired > 0)

   if((m_bytesRequired > 0) && (m_jgrSrc.nHoriz() > 0)) {
      calcWrap();
   } else {
      hideChoices("");
   } // !if((m_bytesRequired > 0) && (m_jgrSrc.nHoriz() > 0)) {

} // void EmbedDlg::recalcStuffVec()





//
// call this only when wrapper file is picked and stuff vector is stuffed.
//
// qxcalcSliderRange()

void EmbedDlg::calcSliderRange() {
   if((m_bytesRequired == 0) || (m_jgrSrc.nHoriz() == 0))
      return;

   int iOutsiz(0), iOutwid(0), iOuthgt(0);
   double difficulty(-1.0);
   twoPairs twoGuys;

   int iu = updateShrink(m_jgrSrc, m_bytesRequired, 16, m_pCommonInfo->lastScatter, (iOutsiz=0), (iOutwid=m_jgrSrc.nHoriz()), (iOuthgt=0), (difficulty=-1.0), m_pCommonInfo->maxBits, m_pCommonInfo->vcBackRatEmb, twoGuys, m_anMT, m_colFacts);

   // max difficulty will have been returned; somewhat restrict range:
   double rangeMax = RANGE(difficulty, 2.0, 4.0);

   // check: if very little stuffed, make range enough to reach 90000 bytes:
   int iu2 = updateShrink(m_jgrSrc, m_bytesRequired, 16, m_pCommonInfo->lastScatter, (iOutsiz=0), (iOutwid=0), (iOuthgt=0), (difficulty=rangeMax), m_pCommonInfo->maxBits, m_pCommonInfo->vcBackRatEmb, twoGuys, m_anMT, m_colFacts);
   if(iOutsiz < 90000) {
      int iu2 = updateShrink(m_jgrSrc, m_bytesRequired, 16, m_pCommonInfo->lastScatter, (iOutsiz=90000), (iOutwid=0), (iOuthgt=0), (difficulty=-1.0), m_pCommonInfo->maxBits, m_pCommonInfo->vcBackRatEmb, twoGuys, m_anMT, m_colFacts);
      rangeMax = MAX(rangeMax, difficulty);
   } // if(iOutsiz < 90000)

   m_iHii = (int)(0.5 + 100.0 * rangeMax);

   m_slySlider1.SetRange(0, m_iHii);

} // void EmbedDlg::calcSliderRange()



//
// new 04-01-25, to consider any desired width, etc.
//
//
//
// qxcalcWrap()
//

void EmbedDlg::calcWrap() {
   calcSliderRange();

   m_iOutsiz    =    0;
   m_iOutwid    =    0;
   m_iOuthgt    =    0;
   m_difficulty = -1.0;

   if(m_pCommonInfo->difDesired >= 0.0) {
      m_difficulty = m_pCommonInfo->difDesired;
   } else if(m_pCommonInfo->fszDesired > 0) {
      m_iOutsiz    = m_pCommonInfo->fszDesired;
   } else if(m_pCommonInfo->hgtDesired > 0) {
      m_iOuthgt    = m_pCommonInfo->hgtDesired;
   } else if(m_pCommonInfo->widDesired > 0) {
      m_iOutwid    = m_pCommonInfo->widDesired;
   } else {
      // let everybody float.
   }

   int iu = updateShrink(m_jgrSrc, m_bytesRequired, 16, m_pCommonInfo->lastScatter, m_iOutsiz, m_iOutwid, m_iOuthgt, m_difficulty, m_pCommonInfo->maxBits, m_pCommonInfo->vcBackRatEmb, m_twoGuys, m_anMT, m_colFacts);

   applyFourGuys();
} // void EmbedDlg::calcWrap()



// qxhideChoices()

void EmbedDlg::hideChoices(const char *pcMsg) {

   GetDlgItem(IDC_EDT_OUTSIZ)->ShowWindow(SW_HIDE);
   GetDlgItem(IDC_EDT_OUTWID)->ShowWindow(SW_HIDE);
   GetDlgItem(IDC_EDT_OUTHGT)->ShowWindow(SW_HIDE);
   GetDlgItem(IDC_EDT_DIFFICULTY)->ShowWindow(SW_HIDE);
   GetDlgItem(IDC_STC_GROUP_MODIFY)->ShowWindow(SW_HIDE);
   GetDlgItem(IDC_STC_OUTSIZ)->ShowWindow(SW_HIDE);
   GetDlgItem(IDC_STC_OUTWID)->ShowWindow(SW_HIDE);
   GetDlgItem(IDC_STC_OUTHGT)->ShowWindow(SW_HIDE);
   GetDlgItem(IDC_STC_DIFFICULTY)->ShowWindow(SW_HIDE);
   GetDlgItem(IDC_SLIDER1)->ShowWindow(SW_HIDE);
// GetDlgItem(IDC_CHK_SCATTER)->ShowWindow(SW_HIDE);
   m_stcHappy.SetWindowText(pcMsg);

} // void EmbedDlg::hideChoices()




// qxshowChoices()

void EmbedDlg::showChoices(const char *pcMsg) {

   GetDlgItem(IDC_EDT_OUTSIZ)->ShowWindow(SW_SHOW);
   GetDlgItem(IDC_EDT_OUTWID)->ShowWindow(SW_SHOW);
   GetDlgItem(IDC_EDT_OUTHGT)->ShowWindow(SW_SHOW);
   GetDlgItem(IDC_EDT_DIFFICULTY)->ShowWindow(SW_SHOW);
   GetDlgItem(IDC_STC_GROUP_MODIFY)->ShowWindow(SW_SHOW);
   GetDlgItem(IDC_STC_OUTSIZ)->ShowWindow(SW_SHOW);
   GetDlgItem(IDC_STC_OUTWID)->ShowWindow(SW_SHOW);
   GetDlgItem(IDC_STC_OUTHGT)->ShowWindow(SW_SHOW);
   GetDlgItem(IDC_STC_DIFFICULTY)->ShowWindow(SW_SHOW);
   GetDlgItem(IDC_SLIDER1)->ShowWindow(SW_SHOW);

// if(m_pCommonInfo->useScatter == 0)                       // -1 and 1 are forcing; 0 means user's choice.
//    GetDlgItem(IDC_CHK_SCATTER)->ShowWindow(SW_SHOW);

   m_stcHappy.SetWindowText(pcMsg);

} // void EmbedDlg::showChoices()




void EmbedDlg::OnSetfocusEdtOutsiz()
{
   m_enterAction = VK_TAB;

   char cbuf[256];
   m_cEdt_outsiz.GetWindowText(cbuf, 256);
   m_ssOutsiz = cbuf;
}


void EmbedDlg::OnKillfocusEdtOutsiz() {
   char cbuf[256];
   m_cEdt_outsiz.GetWindowText(cbuf, 256);

   if(strcmp(cbuf, m_ssOutsiz.c_str()) != 0) {
      // he didn't just tab through; he changed the box's contents.
      m_iOutsiz  = atoi(cbuf);
      m_ssOutsiz = cbuf;

      if(m_iOutsiz < 1) {
         // arggh, that would fool updateShrink() into starting over.
         m_iOutsiz = 1;       // we'll let m_ssOughgt catch up with the call to applyFourGuys().
      } // if(m_iOutsiz < 1)

      int iu = updateShrink(m_jgrSrc, m_bytesRequired, 16, m_pCommonInfo->lastScatter, m_iOutsiz, (m_iOutwid=0), (m_iOuthgt=0), (m_difficulty=-1.0), m_pCommonInfo->maxBits, m_pCommonInfo->vcBackRatEmb, m_twoGuys, m_anMT, m_colFacts);
     
      applyFourGuys();
   } // if(strcmp(cbuf, m_ssOutsiz.c_str()) != 0)
}


void EmbedDlg::OnSetfocusEdtOutwid()
{
   m_enterAction = VK_TAB;

   char cbuf[256];
   m_cEdt_outwid.GetWindowText(cbuf, 256);
   m_ssOutwid = cbuf;
}


void EmbedDlg::OnKillfocusEdtOutwid() {
   char cbuf[256];
   m_cEdt_outwid.GetWindowText(cbuf, 256);

   if(strcmp(cbuf, m_ssOutwid.c_str()) != 0) {
      // he didn't just tab through; he changed the box's contents.
      m_iOutwid  = atoi(cbuf);
      m_ssOutwid = cbuf;

      if(m_iOutwid < 1) {
         // arggh, that would fool updateShrink() into starting over.
         m_iOutwid = 1;       // we'll let m_ssOughgt catch up with the call to applyFourGuys().
      } // if(m_iOutwid < 1)

      int iu = updateShrink(m_jgrSrc, m_bytesRequired, 16, m_pCommonInfo->lastScatter, (m_iOutsiz=0), m_iOutwid, (m_iOuthgt=0), (m_difficulty=-1.0), m_pCommonInfo->maxBits, m_pCommonInfo->vcBackRatEmb, m_twoGuys, m_anMT, m_colFacts);
     
      applyFourGuys();
   } // if(strcmp(cbuf, m_ssOutwid.c_str()) != 0)
}


void EmbedDlg::OnSetfocusEdtOuthgt() {
   m_enterAction = VK_TAB;

   char cbuf[256];
   m_cEdt_outhgt.GetWindowText(cbuf, 256);
   m_ssOuthgt = cbuf;
}


void EmbedDlg::OnKillfocusEdtOuthgt() {
   char cbuf[256];
   m_cEdt_outhgt.GetWindowText(cbuf, 256);

   if(strcmp(cbuf, m_ssOuthgt.c_str()) != 0) {
      // he didn't just tab through; he changed the box's contents.
      m_iOuthgt  = atoi(cbuf);
      m_ssOuthgt = cbuf;

      if(m_iOuthgt < 1) {
         // arggh, that would fool updateShrink() into starting over.
         m_iOuthgt = 1;       // we'll let m_ssOughgt catch up with the call to applyFourGuys().
      } // if(m_iOuthgt < 1)

      int iu = updateShrink(m_jgrSrc, m_bytesRequired, 16, m_pCommonInfo->lastScatter, (m_iOutsiz=0), (m_iOutwid=0), m_iOuthgt, (m_difficulty=-1.0), m_pCommonInfo->maxBits, m_pCommonInfo->vcBackRatEmb, m_twoGuys, m_anMT, m_colFacts);
     
      applyFourGuys();
   } // if(strcmp(cbuf, m_ssOuthgt.c_str()) != 0)
}


void EmbedDlg::OnSetfocusEdtDifficulty() {
   m_enterAction = VK_TAB;

   char cbuf[256];
   m_cEdt_difficulty.GetWindowText(cbuf, 256);
   m_ssDifficulty = cbuf;
}


void EmbedDlg::OnKillfocusEdtDifficulty() {
   m_enterAction = VK_RETURN;

   char cbuf[256];
   m_cEdt_difficulty.GetWindowText(cbuf, 256);

   if(strcmp(cbuf, m_ssDifficulty.c_str()) != 0) {
      // he didn't just tab through; he changed the box's contents.
      m_difficulty= atof(cbuf);
      m_ssDifficulty = cbuf;

      if(m_difficulty < 0.0) {
         // arggh, that would fool updateShrink() into starting over.
         m_difficulty = 0.0;       // we'll let m_ssDifficulty catch up with the call to applyFourGuys().
      } // if(m_difficulty < 0.0)

      int iu = updateShrink(m_jgrSrc, m_bytesRequired, 16, m_pCommonInfo->lastScatter, (m_iOutsiz=0), (m_iOutwid=0), (m_iOuthgt=0), m_difficulty, m_pCommonInfo->maxBits, m_pCommonInfo->vcBackRatEmb, m_twoGuys, m_anMT, m_colFacts);
     
      applyFourGuys();
   } // if(strcmp(cbuf, m_ssDifficulty.c_str()) != 0)
}




void EmbedDlg::OnClickedButnTypeme()
{
   ShowtxtDlg dlgShow;
   dlgShow.m_ssBanner    = "Type or paste your message here...";
   dlgShow.m_pCommonInfo = m_pCommonInfo;
   // dlgShow.m_pcBigString = 
   dlgShow.m_ssBigString = adCr(m_ssTypedMessage);

   long long ill = dlgShow.DoModal();

   if(ill == IDOK) {
      m_ssTypedMessage = rmCr(dlgShow.m_ssBigString);
      zeroMe(dlgShow.m_ssBigString);

      JarqOne *pOne = m_myJrq.getIthOne(0);    // the dummy guy
      pOne->fillOne(m_ssTypedMessage, iFormat);

      recalcStuffVec(true);                    // true: do everything.

   } // if(ill == IDOK)
}





void EmbedDlg::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
{
    // TODO: Add your message handler code here and/or call default

    CDialogEx::OnHScroll(nSBCode, nPos, pScrollBar);
}


void EmbedDlg::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar) {
   int i = m_slySlider1.GetPos();
   m_difficulty = 1.01 * (double)(m_iHii - i) / 100.0;

#ifdef TEST_CODE
   if(m_difficulty <= 0.0) {
      int kkk = 72;
   } // if(m_difficulty <= 0.0)
#endif // TEST_CODE

   int iu = updateShrink(m_jgrSrc, m_bytesRequired, 16, m_pCommonInfo->lastScatter, (m_iOutsiz=0), (m_iOutwid=0), (m_iOuthgt=0), m_difficulty, m_pCommonInfo->maxBits, m_pCommonInfo->vcBackRatEmb, m_twoGuys, m_anMT, m_colFacts);

   applyFourGuys();

   CDialogEx::OnVScroll(nSBCode, nPos, pScrollBar);
}




void EmbedDlg::OnOK()
{
    // TODO: Add your specialized code here and/or call the base class
    zeroMe(m_ssTypedMessage);
    zeroMe(m_passwordSeedVector);
    zeroMe(m_vcToStuff);
    zeroVc(m_vcSsEmbedFiles);

    qprintf(fp_dbg, "EmbedDlg::OnOK() zeroed out m_ssTypedMessage.\n");

    CDialogEx::OnOK();
}




void EmbedDlg::OnCancel()
{
    // TODO: Add your specialized code here and/or call the base class
    zeroMe(m_ssTypedMessage);
    zeroMe(m_passwordSeedVector);
    zeroMe(m_vcToStuff);
    zeroVc(m_vcSsEmbedFiles);

    qprintf(fp_dbg, "EmbedDlg::OnCancel() zeroed out m_ssTypedMessage.\n");

    CDialogEx::OnCancel();
}




void EmbedDlg::OnClickedChkScatter()
{
    // TODO: Add your control notification handler code here
    m_pCommonInfo->lastScatter = m_chkScatter.GetCheck();

    if(m_pCommonInfo->lastScatter > 0) {
       m_bytesAvailable = (int)((bytesCanTakeScattered(m_jgrSrc, 1, 1, m_pCommonInfo->maxBits, NULL, NULL, NULL, m_colFacts) - 384.0) / 1.015);  // rough, conservative guess.
    } else {
       m_bytesAvailable = (int)((bytesCanTakeg3(m_jgrSrc, 1, 1, m_pCommonInfo->maxBits) - 384.0) / 1.015);  // rough, conservative guess.
    } // !if(m_pCommonInfo->lastScatter > 0)

    const int maxxie = 256;
    char ccomma[maxxie];
    comma_me(m_bytesAvailable, ccomma, maxxie);
    m_cEdt_available.SetWindowText(ccomma);
    
    int iu = updateShrink(m_jgrSrc, m_bytesRequired, 16, m_pCommonInfo->lastScatter, m_iOutsiz, (m_iOutwid=0), (m_iOuthgt=0), (m_difficulty=-1.0), m_pCommonInfo->maxBits, m_pCommonInfo->vcBackRatEmb, m_twoGuys, m_anMT, m_colFacts);
     
    applyFourGuys();
}




void EmbedDlg::OnClickedChkEmbFolder() {
   m_pCommonInfo->embFolder = m_chkEmbFolder.GetCheck();

   if(m_pCommonInfo->embFolder == 0) {
      GetDlgItem(IDC_STC_FILES_TO_EMBED)->ShowWindow(SW_SHOW);
      GetDlgItem(IDC_STC_FOLDR_TO_EMBED)->ShowWindow(SW_HIDE);
   } else {
      GetDlgItem(IDC_STC_FILES_TO_EMBED)->ShowWindow(SW_HIDE);
      GetDlgItem(IDC_STC_FOLDR_TO_EMBED)->ShowWindow(SW_SHOW);
   } // !if(m_pCommonInfo->embFolder == 0)
} // void EmbedDlg::OnClickedChkEmbFolder()





