// not UNIX
// Thread.cpp : implementation file
//

#include "stdafx.h"
#include "Strawberry.h"
#include "MainFrm.h"
#include "Thread.h"

#include "StrawberryDoc.h"
#include "New_Class.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// CThread

IMPLEMENT_DYNCREATE(CThread, CWinThread)

CThread::CThread()
{
}

CThread::~CThread()
{
}

BOOL CThread::InitInstance()
{
    // TODO:  perform and per-thread initialization here
    
    
    // Initialize OLE libraries
    if (!AfxOleInit()) //Angel
    {
        AfxMessageBox(IDP_OLE_INIT_FAILED);
        return FALSE;
    }
    return TRUE;
}

int CThread::ExitInstance()
{
    // TODO:  perform any per-thread cleanup here
    return CWinThread::ExitInstance();
}

BEGIN_MESSAGE_MAP(CThread, CWinThread)
    ON_THREAD_MESSAGE(WM_USER, OnRun)
    ON_THREAD_MESSAGE(WM_USER+1, OnKill)
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CThread message handlers
void CThread::OnKill(UINT wParam, LONG lParam)
{
  // close_all_objects
  for (DWORD k=0; k<ObjectStore_br; )
  {
    k+=ObjectStore[ObjectStore[k]+2]?ObjectStore[ObjectStore[k]+2]:
      (ObjectStore[k]?ObjectStore[k+2]:ObjectStore[k+1]);
    if (ObjectStore[k]!=0 && k<ObjectStore_br)
      close_object(k);
  }
  ObjectStore_br=0;

  AfxEndThread(0);
}
void CThread::OnRun(UINT wParam, LONG lParam)
{
  DWORD i;

  if (status_fl&64) // Run Directly
  {
    if (wParam==6) // Run Directly from exe
    {
      if (load_exe(lParam)==0)
        goto ET3;
    }
    else
      compile(0);
    if (error)
      goto ET3;
    status_fl|=2;
    if (pInfo2->m_Settings&8)
      srand(1);
    else
    {
      SYSTEMTIME LokTime;
      GetLocalTime(&LokTime);
      srand(LokTime.wHour + LokTime.wMinute + LokTime.wSecond + LokTime.wMilliseconds);
    }
    ret_fl=call(0);
    if (ret_fl>1 || Wait==0)
    {  
ET3:  pMainFrame->PostMessage(WM_USER+1, ret_fl, 0);
      AfxEndThread(0);
    }
    return;
  }
  if ((Environment&32) && pActivePj) // ExecOnlyPj
    pActive=pActivePj;
  else if (pActiveFile)
    pActive=pActiveFile;
  else
    return;
  if (pActive->m_FileType==4) // exe
  {
    if (wParam==3) // run
      WinExec(make_short(pActive->GetPathName()), SW_SHOW);
    else
    {
      MitiText("You cannot do this operation on an EXE file.\r\n", &cf_red);
      MessageBeep(0);
    }
    return;
  }
  if (pActive->m_FileType==7) // spex
  {
    if (wParam==3) // run
    {
      _TCHAR PrologDir[2*_MAX_PATH];
      GetModuleFileName(NULL, PrologDir, _MAX_PATH);
	    my_strcat(PrologDir,_T(" /x \""));
	    my_strcat(PrologDir,pActive->GetPathName());
	    my_strcat(PrologDir,_T("\""));
	    WinExec(make_short(PrologDir), SW_SHOW);   
    }
    else
    {
      MitiText("You cannot do this operation on a SPEX file.\r\n", &cf_red);
      MessageBeep(0);
    }
    return;
  }
  pActiveCtrl=&(pActive->GetView()->GetRichEditCtrl());
  my_strcpy(namef, pActive->GetPathName());
  pInfo2=pActive->m_pInfo;
#if PROF
  if ((pInfo2->m_Settings&2048) && wParam!=5) // Execute the EXE file on run
#else
  if (pInfo2->m_Settings&(2048|512)) // Execute the EXE file on run | Not with Light
#endif
  {
    if (wParam==3) // run
    {
      CFileStatus rStatus;

      my_strcpy(string3, pActive->GetPathName());
      for (i=my_strlen(string3); string3[i]!='.' && i>0; i--);
      if (i==0)
        i=my_strlen(string3);
      my_strcpy(string3+i, _T(".exe"));
      if (CFile::GetStatus( string3, rStatus))
        WinExec(make_short(string3), SW_SHOW);
      else
      {
        MitiText("There is not an EXE file with the name:\r\n", &cf_red);
        MitiText(make_utf8(string3));
        MitiText("\r\n");
        MessageBeep(0);
      }
    }
    else
    {
      MitiText("You have right only to run this program as an EXE file.\r\n", &cf_red);
      MessageBeep(0);
    }
    return;
  }
  switch(wParam)
  {
    case 0: //ID_DEBUG_NEXT
      if (status_fl&1)
      {
        Trace=1;
        pMainFrame->SetWindowText(_T("StrPolog is TRACING."));
        goto RUN2;
      }
      else if (Environment&8) // Next is always active
        goto RUN1;
      else
        break;
    case 1: //ID_RUN_NEXT
      if (status_fl&1)         // Can do Next
      {
        Trace=0;
        pMainFrame->SetWindowText(pActive->GetTitle()+_T(" is running!"));
RUN2:   status_fl|=2;
        //pMainFrame->m_wndToolBar.OnUpdateCmdUI( pMainFrame, TRUE);
        ret_fl=call(1);
        goto RUN4;
      }
      else if (Environment&8) // Next is always active
        goto RUN1;
      else
        break;
    case 2: //ID_FIRST_STEP
    case 3: //ID_RUN_RUN
    case 4: //ID_RUN_COMPILE
    case 5: //ID_RUN_BUILD_EXE
RUN1: if ( my_strcmp(namef, _T(""))==0) // Untitled
      {
        if (IDYES==::MessageBoxA( m_pMainWnd->m_hWnd, 
           "To run a program you have to save it as a file. Do you want to save it now?",
               "Warning", MB_ICONQUESTION | MB_YESNO) )
        {
          pActive->GetView()->SendMessage(WM_COMMAND, ID_FILE_SAVE_AS);
          my_strcpy(namef, pActive->GetPathName());
        }
        if ( my_strcmp(namef, _T(""))==0) // Untitled
        {
          MitiText("\r\nCan not compile.\r\n");
          return;
        }
      }
      ch_set=(pActive->m_pInfo->m_Settings&0x7e0000)/0x20000;
      default_char=(pActive->m_pInfo->m_Settings&0x10000)?'#':'?';

      if (ch_set!=(pActive->m_CharSet&63))
      {
        CString ch_set_str;
        if (pActive->m_FileType==1)
          ch_set_str+=_T("The new char set is:\n");
        else
          ch_set_str+=_T("The default char set is:\n");
        ch_set_str+=Char_Sets[ch_set];
        ch_set_str+=_T("\n\nDo you want to use it instead of the char set:\n");
        ch_set_str+=Char_Sets[pActive->m_CharSet&63];
        if (pActive->m_FileType!=1)
          ch_set_str+=_T("\n\n(If you save this file as a project (*.SPJ) then it will remember its char set.)");
        if (IDOK==pMainFrame->MessageBox(ch_set_str, _T("Compilation - The char set is different"), MB_ICONQUESTION | MB_OKCANCEL))
        {
          pActive->m_CharSet&=0xffffff80;
          pActive->m_CharSet|=ch_set+64*(default_char=='#');
        }
        else
        {
          MitiText("\r\nCompilation is stopped.\r\n");
          return;
        }
      }
      if (pActive->IsModified() || ch_set!=(pActive->m_CharSet&63))
      {
        pActive->m_CharSet&=0xffffff80;
        pActive->m_CharSet|=ch_set+64*(default_char=='#');
        MitiText("\r\nSaving.\r\n");
        pActive->GetView()->SendMessage(WM_COMMAND, ID_FILE_SAVE);
        compile(wParam==5);
        pActive->m_Star=2;
      }  
      else if (pCompiled!=pActive || error || wParam>3 || !(pInfo2->m_Settings&256) || pActive->m_Star==3)
      {
        compile(wParam==5);
        pActive->m_Star=2;
      }
      if (error==0 && wParam!=4 && wParam!=5)
      {
        if (wParam!=2 && wParam!=0)  
        {
          pMainFrame->SetWindowText(pActive->GetTitle()+_T(" is running!"));
          Trace=0;
        }
        else  
        {
          pMainFrame->SetWindowText(_T("StrProlog is TRACING."));
          Trace=1;
        }
        status_fl|=2;
        //pMainFrame->m_wndToolBar.OnUpdateCmdUI( pMainFrame, FALSE);
        if (pInfo2->m_Settings&8)
          srand(1);
        else
        {
          SYSTEMTIME LokTime;
          GetLocalTime(&LokTime);
          srand(LokTime.wHour + LokTime.wMinute + LokTime.wSecond + LokTime.wMilliseconds);
        }
        MitiText("\r\n");
        my_strcpy(string3, namef);
        for (i=my_strlen(string3); i && string3[--i]!='\\'; );
        string3[i]=0;
        SetCurrentDirectory(string3);
        ret_fl=call(0);
RUN4:   if (ret_fl<2 && Wait)
        {
          pMainFrame->SetWindowText(_T("StrProlog is Waiting"));
          status_fl|=4;
        }
        else
          pMainFrame->PostMessage(WM_USER+1, ret_fl, 0); // OnEnd
      }
#if PROF==2
      else if (error==0 && wParam==5)
      {
        MakeExe(lParam);
      }
#endif
      break;
  }
}

int load_exe(int SPEX)
{
  BYTE ch_warn, ch_ver, num_int, num_str;
  WORD st_ver1, st_ver2;
  DWORD Head, i, sv_c2, sv_v2, MEMORY_C_Temp, inc;
  CString ExeName, ExeFrom, ExeProdID, ExeComments;
  CFile file;

  // ASSERT(FALSE); // stop for debug
  
  if (file.Open(ProgramPath+_T("Standard_2_92.sys"), CFile::modeRead)==0)
  {
    MessageBoxA(NULL, "Cannot open the Standard_2_92.sys file", "Error", MB_OK | MB_ICONSTOP);
    return 0;
  }

  CArchive ar(&file, CArchive::load);
  ar>>sv_c_old;
  ar>>sv_v_old;
  ar>>sv_sub_old;
  ar>>program_br1;
  ar>>MEMORY_C_Temp;

  ar.Read(Ufil_c1, 4*sv_c_old);
  ar.Read(Ufil_c2, 4*sv_c_old);
  ar.Read(Chfil_c, sv_c_old);
  ar.Read(Ufil_c1+MEMORY_C, 4*sv_v_old);
  ar.Read(Ufil_c2+MEMORY_C, 4*sv_v_old);
  ar.Read(Chfil_c+MEMORY_C, sv_v_old);
  ar.Read(Ufil_vs, 4*sv_v_old);
  ar.Read(Chfil_v, 2*sv_v_old);
  ar.Read(Substi, 2*sv_sub_old);
  ar.Read(Program, 4*program_br1);
  ar.Read(Prog_Obj, 4*program_br1);
  ar.Read(Definition, 4*DEFINITIONS);
  ar.Close();
  file.Close();
  
  for (i=0; file.Open(namef, CFile::modeRead)==0 && i<5000; i++ );
  if (i==5000)
  {
    my_sprintf(string3,_T("Cannot open the EXE file: %s"), namef);
    MessageBox(NULL,string3,_T("Error"),MB_OK | MB_ICONHAND);
    return 0;
  }
  
  if (SPEX==0)
    file.Seek(-4, CFile::end);
  else
    file.Seek(-8, CFile::end);
  file.Read(&Head, 4);
  file.Seek(Head, CFile::begin);
  {
  CArchive ar(&file, CArchive::load);
  ar>>i;
  if (i!=0x9e56f78a)
    goto E4;
  ar>>ExeName;
  ar>>ExeFrom;
  ar>>ExeProdID;
  my_sscanf(ExeProdID.Mid(13, 5), _T("%d"), &i);
  if (ExeProdID.GetLength()!=18)
  {
E4: MessageBoxA(NULL, "This EXE file is not written on Strawberry Prolog or it is corrupt.", "Error", MB_OK | MB_ICONSTOP);
    goto E2;
  }
  ar>>ExeComments;

  ar>>ch_warn;
  ar>>ch_ver;
  if (ch_ver==7)
  {
    if (ch_warn>1)        // ch_warn  - starts from 1
      MessageBoxA(NULL, "Warning: This Exe file is made on a newer version of Strawberry Prolog.", "Strawberry Prolog - version 2.92", MB_OK | MB_ICONEXCLAMATION);
    //else if (ch_warn<1)   // ch_warn  - starts from 1
    //  MessageBoxA(NULL, "Warning: This Exe file is made on a older version of Strawberry Prolog.", "Strawberry Prolog - version 2.92", MB_OK | MB_ICONEXCLAMATION);
  }
  else
  {
    if (ch_ver<7)
      MessageBoxA(NULL, "Error: EXE files compiled for versions smaller than 2.92 are not supported anymore.", "Strawberry Prolog - version 2.92", MB_OK | MB_ICONSTOP); // 2.91
    else
      MessageBoxA(NULL, "Error: This EXE file cannot be open. It is made on a newer version of Strawberry Prolog.", "Strawberry Prolog - version 2.92", MB_OK | MB_ICONSTOP);
    goto E2;
  }
  ar>>num_int;
  ar>>num_str;
  ar>>st_ver1;
  ar>>st_ver2; // x1000

  ar>>sv_c2;
  ar>>sv_v2;
  ar>>sv_sub;
  ar>>global_br2;
  ar>>program_br2;
  ar>>program_br;
  ar>>sv_NewObj;
  ar>>sv_StStore;
  ar>>oper_br;
  ar>>pInfo2->m_Settings;
  pInfo2->m_Settings&=M1^6; // Active Break Point and St. is full as fail
  ar>>pInfo2->STACK_start;
  ar>>pInfo2->STACK_max;
  ar>>pInfo2->BUDA_start;
  ar>>pInfo2->BUDA_max;
  ar>>pInfo2->BUDA_S_start;
  ar>>pInfo2->BUDA_S_max;
  status_fl|=(256|512);
  if (pInfo2->m_Settings&0x2000) // Add the Standard.add
  {
    ar>>sv_c_old;
    ar>>sv_v_old;
    ar>>sv_sub_old;
    ar>>program_br1;
    ar>>MEMORY_C_Temp;
  }
  else
  {
    ar>>i; if(i!=sv_c_old) goto E5;
    ar>>i; if(i!=sv_v_old) goto E5;
    ar>>i; if(i!=sv_sub_old) goto E5;
    ar>>i; if(i!=program_br1)  goto E5;
    if(MEMORY_C_Temp!=MEMORY_C)
    {
E5:   MessageBoxA(NULL, "Problem with Standard files", "Error", MB_OK | MB_ICONSTOP);
      goto E2;
    }
    ar>>MEMORY_C_Temp;
  }
  for ( ; num_int-->21; ar>>i);
  {for ( CStringA st; num_str-->0; ar>>st);}

  if (sv_v2>=MEMORY_V)
  {
    for (; MEMORY_V+1024<sv_v2; MEMORY_V+=1024); 
    if ( correct_MEM_V() )
      goto E1;
  }
  if (MEMORY_C!=MEMORY_C_Temp)
  {
    inc=MEMORY_C_Temp-MEMORY_C;
    MEMORY_c256=MEMORY_C_Temp+TT_START-INCREASE_C;
    if ( correct_MEM_C() ) // use status_fl&256
    {
E1:   MessageBoxA(NULL, "Error: Cannot allocate enough memory.", "Strawberry Prolog", MB_OK | MB_ICONSTOP);
E2:   ar.Close();
      file.Close();
      return 0;
    }
    if (!(pInfo2->m_Settings&0x2000)) // Not add the Standard.add
    {
      for (i=MEMORY_C+sv_v2; i-->MEMORY_C; )
      {
        Chfil_c[i+inc]=Chfil_c[i];
        Ufil_c1[i+inc]=(Ufil_c1[i]>=MEMORY_C+TT_START)?(Ufil_c1[i]+inc):Ufil_c1[i];
        Ufil_c2[i+inc]=(Ufil_c2[i]>=MEMORY_C+TT_START)?(Ufil_c2[i]+inc):Ufil_c2[i];
      }
      for (i=0; i<program_br1; i++)
        if (Program[i]>=MEMORY_C+TT_START)
          Program[i]+=inc;
    }
    MEMORY_C=MEMORY_C_Temp;
    MEMORY_c256=MEMORY_C_Temp+TT_START;
  }
  if (sv_sub>=MEMORY_S)
  {
    for (; MEMORY_S+512<sv_sub; MEMORY_S+=512); 
    if ( correct_MEM_S() )
      goto E1;
  }
  if (global_br2>=GLOBAL_max)
  {
    for (; GLOBAL_max+256<global_br2; GLOBAL_max+=256); 
    if ( correct_GLOB_max() )
      goto E1;
  }
  if (program_br>=PROGRAM_L && correct_PROG_L() )
    goto E1;
  if (sv_NewObj>=NEW_OBJ)
  {
    for (; NEW_OBJ+512<sv_NewObj; NEW_OBJ+=512); 
    if ( correct_NEW_OBJ() )
      goto E1;
  }
  if (sv_StStore>=STRING_STORE && correct_STR_ST() )
    goto E1;
  if (pInfo2->m_Settings&0x2000) // Add the Standard.add
  {
    ar.Read(Ufil_c1, 4*sv_c_old);
    ar.Read(Ufil_c2, 4*sv_c_old);
    ar.Read(Chfil_c, sv_c_old);
    ar.Read(Ufil_c1+MEMORY_C, 4*sv_v_old);
    ar.Read(Ufil_c2+MEMORY_C, 4*sv_v_old);
    ar.Read(Chfil_c+MEMORY_C, sv_v_old);
    ar.Read(Ufil_vs, 4*sv_v_old);
    ar.Read(Chfil_v, 2*sv_v_old);
    ar.Read(Substi, 2*sv_sub_old);
    ar.Read(Program, 4*program_br1);
    ar.Read(Prog_Obj, 4*program_br1);
    ar.Read(Definition, 4*DEFINITIONS);
  }
  ar.Read(Ufil_c1+sv_c_old, 4*(sv_c2-sv_c_old));
  ar.Read(Ufil_c2+sv_c_old, 4*(sv_c2-sv_c_old));
  ar.Read(Chfil_c+sv_c_old, sv_c2-sv_c_old);
  ar.Read(Ufil_c1+MEMORY_C+sv_v_old, 4*(sv_v2-sv_v_old));
  ar.Read(Ufil_c2+MEMORY_C+sv_v_old, 4*(sv_v2-sv_v_old));
  ar.Read(Chfil_c+MEMORY_C+sv_v_old, sv_v2-sv_v_old);
  ar.Read(Ufil_vs+sv_v_old, 4*(sv_v2-sv_v_old));
  ar.Read(Chfil_v+sv_v_old, 2*(sv_v2-sv_v_old));
  ar.Read(Substi+sv_sub_old, 2*(sv_sub-sv_sub_old));
  ar.Read(global, 4*global_br2);
  ar.Read(Program+program_br2, 4*(program_br-program_br2));
  ar.Read(Prog_Obj+program_br2, 4*(program_br-program_br2));
  ar.Read(NewObj, 4*sv_NewObj);
  ar.Read(NewObj1, sv_NewObj);
  ar.Read(NewObj2, 2*sv_NewObj);
  ar.Read(StringStore+512, sv_StStore-512);
  ar.Read(Oper, 4*(oper_br+1));
  ar.Read(OpPr, 4*(oper_br+1));
  ar.Read(OpType, 4*(oper_br+1));
  ar.Read(OpMin, 4*(oper_br+1));

  ar.Close();
  file.Close();

  global_br=global_br2;
  //for (i=0; i<global_br2; global2[i]=i, i++); // this is repeated
  for (i=0; i<=program_br1; Program2[i++]=0);
  for (i=program_br2; i<=program_br; Program2[i++]=0);

  Mtree[0][1]=Mtree[0][2]=Mtree[0][3]=MASKA; // make agein
  br_buf1=sv_blocks2=0; sv_blocks=1024;
  sv_tr=1;
  
  for (i=sv_c=0; i<sv_c2; i++)
    creat_p(Chfil_c[i], Ufil_c1[i], Ufil_c2[i], 1, 1);
  sv_v2+=1+MEMORY_C;
  for (i=1+MEMORY_C, sv_v=1, sv_sub=0; i<sv_v2; i++)
    creat_p(Chfil_c[i], Ufil_c1[i], Ufil_c2[i], 1, 1); // use status_fl&256
  status_fl&=M1^256;
  compile(2);
  }
  return 1;
}
