// ExtractDlg.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 "ExtractDlg.h"
#include "PassDlg.h"
#include "stufpic.h"
#include "ShowtxtDlg.h"
#include <string>
#include <vector>
#include <direct.h>
#include "mmsystem.h"     // for timeGetTime()
#include "ssprint.h"

#pragma warning( disable : 4996 )



// ExtractDlg dialog

IMPLEMENT_DYNAMIC(ExtractDlg, CDialogEx)

ExtractDlg::ExtractDlg(CWnd* pParent /*=nullptr*/)
   : CDialogEx(IDD_EXTRACT, pParent)
{
   m_enterAction   = VK_TAB;
   m_bDidFileThing = false;
   m_pCommonInfo   = NULL;
}

ExtractDlg::~ExtractDlg()
{
}

void ExtractDlg::DoDataExchange(CDataExchange* pDX)
{
    CDialogEx::DoDataExchange(pDX);
    DDX_Control(pDX, IDC_EDT_STUFFED, m_cEdt_stuffed);
    // DDX_Control(pDX, IDC_EDT_TEST1, m_cEdt_test1);
}


BEGIN_MESSAGE_MAP(ExtractDlg, CDialogEx)
   ON_BN_CLICKED(IDC_BUTN_STUFFED, &ExtractDlg::OnClickedButnStuffed)
   ON_EN_SETFOCUS(IDC_EDT_STUFFED, &ExtractDlg::OnSetfocusEdtStuffed)
   ON_EN_KILLFOCUS(IDC_EDT_STUFFED, &ExtractDlg::OnKillfocusEdtStuffed)
   ON_BN_CLICKED(IDC_BUTN_GO, &ExtractDlg::OnClickedButnGo)
   ON_BN_CLICKED(IDC_BUTN_MSG, &ExtractDlg::OnClickedButnMsg)
END_MESSAGE_MAP()


// ExtractDlg message handlers


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

   return CDialogEx::PreTranslateMessage(pMsg);
}


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

   GetDlgItem(IDC_BUTN_MSG)->ShowWindow(SW_HIDE);

   m_cEdt_stuffed.SetWindowText("Click me");


   // xptl 05-27-24:
   PostMessage(WM_COMMAND, IDC_BUTN_STUFFED);

#ifdef DEAD_CODE
   m_cEdt_test1.SetWindowText("This is a test of\r\nwhether we can do multi-line things.\r\n"
   "This is a test of\r\nwhether we can do multi-line things.\r\n"
   "This is a test of\r\nwhether we can do multi-line things.\r\n"
   "This is a test of\r\nwhether we can do multi-line things.\r\n"
   "This is a test of\r\nwhether we can do multi-line things.\r\n"
   "This is a test of\r\nwhether we can do multi-line things.\r\n"
   "This is a test of\r\nwhether we can do multi-line things.\r\n"
   "This is a test of\r\nwhether we can do multi-line things.\r\n"
   "This is a test of\r\nwhether we can do multi-line things.\r\n"
   "This is a test of\r\nwhether we can do multi-line things.\r\n"
   "This is a test of\r\nwhether we can do multi-line things.\r\n"
   "This is a test of\r\nwhether we can do multi-line things.\r\n"
   "This is a test of\r\nwhether we can do multi-line things.\r\n"
   "This is a test of\r\nwhether we can do multi-line things.\r\n"
   "This is a test of\r\nwhether we can do multi-line things.\r\n"
   "This is a test of\r\nwhether we can do multi-line things.\r\n"
   "This is a test of\r\nwhether we can do multi-line things.\r\n"
   "This is a test of\r\nwhether we can do multi-line things.\r\n"
   "This is a test of\r\nwhether we can do multi-line things.\r\n"
                   
                   
                   
                   );
#endif // DEAD_CODE


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


void ExtractDlg::OnClickedButnStuffed()
{
   // TODO: Add your control notification handler code here
   // LPCTSTR pcFilter = _T("JPEG Files (*.jpg;*.jpeg)|*.jpg; *.jpeg|Bitmap Files (*.bmp)|*.bmp||");
   // LPCTSTR pcFilter = _T("Image Files (*.bmp)|*.bmp||");
   LPCTSTR pcFilter = _T("Image Files (*.png;*.bmp)|*.png; *.bmp||");
   // DWORD dwFlags = OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT;
   DWORD dwFlags = 0;

   CFileDialog dlgOpen(TRUE, NULL, NULL, dwFlags, pcFilter);
   // OPENFILENAME& ofn = dlgOpen.GetOFN();
   // ofn.Flags |= OFN_ALLOWMULTISELECT;
   dlgOpen.m_ofn.lpstrTitle       = "Select file to extract from:";

   if(m_pCommonInfo->ssExtractWarm.size() > 0) {
      dlgOpen.m_ofn.lpstrInitialDir  = m_pCommonInfo->ssExtractWarm.c_str();
   } else if(m_pCommonInfo->ssExtractCold.size() > 0) {
      dlgOpen.m_ofn.lpstrInitialDir  = m_pCommonInfo->ssExtractCold.c_str();
   } // if(m_pCommonInfo->ssExtractWarm.size() > 0) {

   long long il = dlgOpen.DoModal();

   if(il == IDOK) {
      CString csFileName = dlgOpen.GetFileName();
      m_ssFileName = (const char *)(LPCTSTR)csFileName;

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

      m_cEdt_stuffed.SetWindowText(csPathName);

      if(m_pCommonInfo->ssExtractWarm.size() == 0) {
         // we've come here before Embed; save this folder location
         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->ssExtractCold = pcDir;
      } else {
         // we've come here after Embed; don't save this folder location
      } // !if(m_pCommonInfo->ssExtractWarm.size() == 0)

      int i = m_jgrSrc.readFile(m_ssPathName.c_str());
      if(i != 0) {
         m_cEdt_stuffed.SetWindowText("Failed!");
         m_jgrSrc.clear();
         // qprintf(stderr, "Unable to read file %s.\n", fileIn);
         // qprintf(fp_dbg, "Unable to read file %s.\n", fileIn);
         // if(fp_db2 != stdout) qprintf(fp_db2, "Unable to read file %s.\n", fileIn);
         // exit(1);
      } else {
         PostMessage(WM_COMMAND, IDC_BUTN_GO);
      } // !if(i != 0)
   } // if(il == IDOK)

}


void ExtractDlg::OnSetfocusEdtStuffed() {
   m_enterAction = VK_TAB;

   if(!m_bDidFileThing) {
      m_bDidFileThing = true;
      m_cEdt_stuffed.SetWindowText("");
      PostMessage(WM_COMMAND, IDC_BUTN_STUFFED);
   } // if(!m_bDidWrapThing)

}


void ExtractDlg::OnKillfocusEdtStuffed() {
   m_enterAction = VK_RETURN;
}



void ExtractDlg::OnClickedButnGo() {
   // TODO: Add your control notification handler code here
   // too soon?
   if(m_jgrSrc.nHoriz() == 0)
      return;

#ifdef MOVED_INSIDE
   PassDlg dlgP;
   dlgP.m_pCommonInfo = m_pCommonInfo;
#endif // MOVED_INSIDE

   int ii(NADA);
   std::string ssBadDoggie;

   while(1) {
      // get 80-byte vector from password:

      PassDlg dlgP;
      dlgP.m_pCommonInfo = m_pCommonInfo;
      dlgP.m_ssBadPwd    = ssBadDoggie;

      long long il = dlgP.DoModal();

      if(il != IDOK) 
         return;

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

      CWaitCursor wait1;

      unsigned long tgt0(0), tgt1(0), tgtDelta(0);
      std::vector<unsigned long> vcDeltaTimes;
      for(int i=0; i<2; i++) {
         tgt0 = timeGetTime();
         unsigned long long ull0 = getProccyTime();

         ii = doExtract(m_jgrSrc, m_passwordSeedVector, ((i == 0) ? (m_pCommonInfo->vcBackRatOld) : (m_pCommonInfo->vcBackRatExt)), m_myJrq);

         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 = ((ii == 0) ? ("success") : ("FAIL"));

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

         tgt1 = timeGetTime();
         tgtDelta = tgt1 - tgt0;

         vcDeltaTimes.push_back(tgtDelta);

         if(ii == 0)
            break;     // we found it!

         if(i == 0) {
            // another try with crazified vector:
            int nCycle = 100000;
            tgt0 = timeGetTime();

            MT64::rescrambleVector(m_passwordSeedVector, nCycle);

            tgt1 = timeGetTime();
            tgtDelta = tgt1 - tgt0;
            vcDeltaTimes.push_back(tgtDelta);
         } // if(i == 0)

      } // for(int i=0; i<2; i++)

      qprintf(fp_dbg, "Delta times: ");
      for(int ib=0; ib<(int)vcDeltaTimes.size(); ib++)
         qprintf(fp_dbg, "%lld ", vcDeltaTimes[ib]);
      qprintf(fp_dbg, "\n");

      if(ii == 0)
         break;     // we found it!

      if(ii == NAD2) {
         // corrupted .bmp:
         m_myJrq.clear();
         AfxMessageBox("The wrapper image appears to have been corrupted.");
         break;
      } // if(ii == NAD2)

      if(ii == NAD3) {
         // sender has newer version of Stegmeister
         m_myJrq.clear();
         AfxMessageBox("The sender appears to have used a later version of Stegmeister");
         break;
      } // if(ii == NAD2)

//    dlgP.m_ssBadPwd = "Could not make that password work; try again?";  // worthless; goes out of scope.
      ssBadDoggie     = "Could not make that password work; try again?";
   } // while(1)

   if(m_myJrq.size() > 0) {
      char cbuf[256];

      // make a random name folder:
      std::vector<unsigned long long> aLongLongSeed;
      MT64::getAutoSeed(aLongLongSeed);

      MT64 anMT;
      anMT.init_by_array64(&(aLongLongSeed[0]), aLongLongSeed.size());

      SMARTA(pcDir, char, (m_ssPathName.size()+16), smaDir);
      SMARTA(pcFil, char, (m_ssPathName.size()+16), smaFil);
      SMARTA(pcNuu, char, (m_ssPathName.size()+16), smaNuu);

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

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

         sprintf(pcNuu, "%s\\%s", pcDir, ssSilly.c_str());

         if(!is_a_dir(pcNuu))
            break;

      } // while(1)

      int nFiles = m_myJrq.nSubstantial();    // size() minus any blank file name (vcContents).

      _getcwd(cbuf, 256);

      if(nFiles > 0) {
         mkdirWrap(pcNuu);
         _chdir(pcNuu);

         qprintf(fp_dbg, "Writing output file(s) to %s.\n", pcNuu);

         std::string ssTempy = pcNuu;
         ssAppend(ssTempy, "%c%s", SLASH, "blah.dbg");
         m_pCommonInfo->vcSsBlahNames.push_back(ssTempy);
      } // if(nFiles > 0)

      std::vector<std::string> vcErrsOut;

      int nWrit = m_myJrq.spitFiles(&m_vcVcContentsOut, NULL, &vcErrsOut);

      if(vcErrsOut.size() > 0) {
         // oh doggen-floggen.
         std::string ssContents;
         vcSsToSs(vcErrsOut, ssContents);

         ShowtxtDlg dlgShow;
         dlgShow.m_ssBanner    = "Error";
         dlgShow.m_pCommonInfo = m_pCommonInfo;
         dlgShow.m_ssBigString = adCr(ssContents);

         long long ill = dlgShow.DoModal();
      } // if(vcErrsOut.size() > 0)

      if(nFiles > 0)
         _chdir(cbuf);

      int isz = (int)m_vcVcContentsOut.size();
      if(isz > 0) {
         for(int i=0; i<(int)m_vcVcContentsOut.size(); i++) {
            int j = (i + isz - 1) % isz;
            std::vector<unsigned char> &vcThis = m_vcVcContentsOut[j];
            std::string ssContents;
            vcUcToSs(vcThis, ssContents);

            ShowtxtDlg dlgShow;
            dlgShow.m_ssBanner    = "Message received";
            dlgShow.m_pCommonInfo = m_pCommonInfo;
            dlgShow.m_ssBigString = adCr(ssContents);

            long long ill = dlgShow.DoModal();

            zeroMe(dlgShow.m_ssBigString);
            zeroMe(ssContents);
         } // for(int i=0; i<(int)m_vcVcContentsOut.size(); i++)

         GetDlgItem(IDC_BUTN_MSG)->ShowWindow(SW_SHOW);
      } else {
         GetDlgItem(IDC_BUTN_MSG)->ShowWindow(SW_HIDE);
      } // !if(isz > 0)

      if((nFiles > 0) && (nWrit == 0)) {
         rmdir(pcNuu);
      } else if(nWrit > 0) {
         if(nFiles > 0) {
            // we expected file(s) and made the new folder:
            m_pCommonInfo->ssName = pcNuu;
         } else {
            // should not happen!  We must've dumped file(s) in cwd:
            m_pCommonInfo->ssName = cbuf;
         } // !if(nFiles > 0)
      } // !if(nWrit == 0)
   } // if(m_myJrq.size() > 0)

   return;
}




void ExtractDlg::OnClickedButnMsg() {

   int isz = (int)m_vcVcContentsOut.size();
   if(isz > 0) {
      for(int i=0; i<(int)m_vcVcContentsOut.size(); i++) {
         int j = (i + isz - 1) % isz;
         std::vector<unsigned char> &vcThis = m_vcVcContentsOut[j];
         std::string ssContents;
         vcUcToSs(vcThis, ssContents);

         ShowtxtDlg dlgShow;
         dlgShow.m_ssBanner    = "Message received";
         dlgShow.m_pCommonInfo = m_pCommonInfo;
         dlgShow.m_ssBigString = adCr(ssContents);

         long long ill = dlgShow.DoModal();

         zeroMe(dlgShow.m_ssBigString);
         zeroMe(ssContents);
      } // for(int i=0; i<(int)m_vcVcContentsOut.size(); i++)

      GetDlgItem(IDC_BUTN_MSG)->ShowWindow(SW_SHOW);
   } else {
      GetDlgItem(IDC_BUTN_MSG)->ShowWindow(SW_HIDE);
   } // !if(isz > 0)

}




void ExtractDlg::OnOK()
{
    // TODO: Add your specialized code here and/or call the base class
#ifdef REPLACED_D
    for(int i=0; i<(int)m_vcVcContentsOut.size(); i++) {
       std::vector<unsigned char> &vcOne = m_vcVcContentsOut[i];
       zeroMe(vcOne);
    } // for(int i=0; i<(int)m_vcVcContentsOut.size(); i++)
#endif // REPLACED_D

    zeroVc(m_vcVcContentsOut);
    zeroMe(m_passwordSeedVector);

    CDialogEx::OnOK();
}




void ExtractDlg::OnCancel()
{
    // TODO: Add your specialized code here and/or call the base class
#ifdef REPLACED_D
    for(int i=0; i<(int)m_vcVcContentsOut.size(); i++) {
       std::vector<unsigned char> &vcOne = m_vcVcContentsOut[i];
       zeroMe(vcOne);
    } // for(int i=0; i<(int)m_vcVcContentsOut.size(); i++)
#endif // REPLACED_D

    zeroVc(m_vcVcContentsOut);
    zeroMe(m_passwordSeedVector);

    CDialogEx::OnCancel();
}




