// InGodsTimeDlg.cpp : implementation file
//

#include "stdafx.h"

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

/////////////////////////////////////////////////////////////////////////////
typedef struct {BYTE lo,hi;} BYTE_BYTE;
typedef struct {WORD lo,hi;} WORD_WORD;
typedef struct {BYTE b0,b1,b2,b3;} FOUR_BYTES;
typedef union {BYTE_BYTE b; WORD w;} BYTE_WORD;
typedef union {WORD_WORD w; DWORD d; int i; FOUR_BYTES b;} WORD_LONG;

/////////////////////////////////////////////////////////////////////////////
#define ct_GetTickCount 0
#define ct_high_performance 1
#define ct_multimedia 2 //Not yet implemented

int counter_type=ct_GetTickCount;
double high_performance_counter_frequency;

void init_counter()
{
LARGE_INTEGER freq;
if (QueryPerformanceFrequency(&freq)) {
high_performance_counter_frequency=freq.LowPart+
freq.HighPart65536.065536.0;
counter_type=ct_high_performance;
} else
counter_type=ct_GetTickCount;
}

/////////////////////////////////////////////////////////////////////////////
// CAboutDlg dialog used for App About

class CAboutDlg : public CDialog
{
public:
CAboutDlg();

// Dialog Data
//{{AFX_DATA(CAboutDlg)
enum { IDD = IDD_ABOUTBOX };
//}}AFX_DATA

// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CAboutDlg)
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
//}}AFX_VIRTUAL

// Implementation
protected:
//{{AFX_MSG(CAboutDlg)
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};

CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD)
{
//{{AFX_DATA_INIT(CAboutDlg)
//}}AFX_DATA_INIT
}

void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CAboutDlg)
//}}AFX_DATA_MAP
}

BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)
//{{AFX_MSG_MAP(CAboutDlg)
// No message handlers
//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CInGodsTimeDlg dialog

CInGodsTimeDlg::CInGodsTimeDlg(CWnd* pParent /=NULL/)
: CDialog(CInGodsTimeDlg::IDD, pParent)
{
//{{AFX_DATA_INIT(CInGodsTimeDlg)
m_main = _T("");
m_max = 100109;
m_max_changed=false;
//}}AFX_DATA_INIT
// Note that LoadIcon does not require a subsequent DestroyIcon in Win32
m_num=1;
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}

void CInGodsTimeDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CInGodsTimeDlg)

DDX_Text(pDX, IDC_MAIN, m_main);
DDX_Text(pDX, IDC_MAX, m_max);
DDX_Text(pDX, IDC_NUMB, m_num);
//}}AFX_DATA_MAP
}

BEGIN_MESSAGE_MAP(CInGodsTimeDlg, CDialog)
//{{AFX_MSG_MAP(CInGodsTimeDlg)
ON_WM_SYSCOMMAND()
ON_WM_PAINT()
ON_WM_QUERYDRAGICON()
ON_BN_CLICKED(IDC_STOP, OnStop)
ON_BN_CLICKED(IDC_CHOICE_WORDS, OnChoiceWords)
ON_BN_CLICKED(IDC_CHOICE_NUMBERS, OnChoiceNumbers)
ON_BN_CLICKED(IDC_SELECT_WORDS, OnSelectWords)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CInGodsTimeDlg message handlers

BOOL CInGodsTimeDlg::OnInitDialog()
{
CDialog::OnInitDialog();

// Add "About..." menu item to system menu.

// IDM_ABOUTBOX must be in the system command range.
ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
ASSERT(IDM_ABOUTBOX < 0xF000);

CMenu* pSysMenu = GetSystemMenu(FALSE);
if (pSysMenu != NULL)
{
CString strAboutMenu;
strAboutMenu.LoadString(IDS_ABOUTBOX);
if (!strAboutMenu.IsEmpty())
{
pSysMenu->AppendMenu(MF_SEPARATOR);
pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
}
}

// Set the icon for this dialog. The framework does this automatically
// when the application's main window is not a dialog
SetIcon(m_hIcon, TRUE);	// Set big icon
SetIcon(m_hIcon, FALSE);	// Set small icon

// TODO: Add extra initialization here

init_counter();
m_max=1448;
return TRUE; // return TRUE unless you set the focus to a control

}

void CInGodsTimeDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
if ((nID & 0xFFF0) == IDM_ABOUTBOX)
{
CAboutDlg dlgAbout;
dlgAbout.DoModal();
}
else
{
CDialog::OnSysCommand(nID, lParam);
}
}

// If you add a minimize button to your dialog, you will need the code below
// to draw the icon. For MFC applications using the document/view model,
// this is automatically done for you by the framework.

void CInGodsTimeDlg::OnPaint()
{
if (IsIconic())
{
CPaintDC dc(this); // device context for painting

SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0);

// Center icon in client rectangle
int cxIcon = GetSystemMetrics(SM_CXICON);
int cyIcon = GetSystemMetrics(SM_CYICON);
CRect rect;
GetClientRect(&rect);
int x = (rect.Width() - cxIcon + 1) / 2;
int y = (rect.Height() - cyIcon + 1) / 2;

// Draw the icon
dc.DrawIcon(x, y, m_hIcon);
}
else
{
CDialog::OnPaint();
}

}

// The system calls this to obtain the cursor to display while the user drags
// the minimized window.
HCURSOR CInGodsTimeDlg::OnQueryDragIcon()
{
return (HCURSOR) m_hIcon;
}

//
long fsize(FILE f)
{
long result,original=ftell(f);
fseek(f,0,SEEK_END);
result=ftell(f);
fseek(f,original,SEEK_SET);
return result;
}

WORD hash_string(const char src)
{
BYTE_WORD sum;
sum.w =0;
while (src) {
sum.w += ((src++));
sum.w <<=1;
}
sum.w += sum.b.hi;
return sum.w;
}

char malloc_string(const char src)
{
int len=strlen(src);
char result=(char )malloc(len+1);
strcpy(result,src);
return result;
}

#define pm_numbers 0
#define pm_words 1
int pick_mode=pm_numbers;

class hash_entry
{
public:
hash_entry next;
char body;
};
typedef hash_entry hash_ptr;

#define hash_table_size 4096
bool hash_initialized=false;
int num_hash_entries=0;
hash_ptr hash_table[hash_table_size];
int start_word,end_word;
char word_list=NULL;

void generate_word_list()
{
int i,j=0;
hash_ptr temph;
if (word_list) {
free(word_list);
}
word_list=(char )malloc(sizeof(char )num_hash_entries);
for (i=0;i<num_hash_entries;i++)
word_list[i]=NULL;
for (i=0;i<hash_table_size;i++) {
temph=hash_table[i];
while (temph) {
word_list[j++]=temph->body;
temph=temph->next;
}
}
}

void process_word(char st)
{
// char src=st;
int i;
hash_ptr temph,temph1;
// while (src) {
// src=toupper(src);
// src++;
// }
i=hash_string(st) & (hash_table_size-1);
temph=hash_table[i];
while (temph) {
if (!strcmp(temph->body,st))
return;
temph=temph->next;
}
temph1=new hash_entry;
temph1->body=malloc_string(st);
temph1->next=hash_table[i];
hash_table[i]=temph1;
num_hash_entries++;
}

void process_file(char buf,int len)
{
int i,j;
if (!hash_initialized) {
for (i=0;i<hash_table_size;i++)
hash_table[i]=NULL;
hash_initialized=true;
}
for (i=0;i<len;) {
while (!(buf[i]>='A' && buf[i]<='Z' || buf[i]>='a' && buf[i]<='z' || buf[i]>='0' && buf[i]<='9' || buf[i]=='^' || buf[i]=='=' ||
buf[i]=='+' || buf[i]=='-' || buf[i]=='/' || buf[i]=='' || buf[i]=='_' || buf[i]=='\'') && i<len)
i++;
j=i;
while (i<len)
if (!(buf[i]>='A' && buf[i]<='Z' || buf[i]>='a' && buf[i]<='z' || buf[i]>='0' && buf[i]<='9' || buf[i]=='^' || buf[i]=='=' ||
buf[i]=='+' || buf[i]=='-' || buf[i]=='/' || buf[i]=='' || buf[i]=='_' || buf[i]=='\'')) {
buf[i]=0;
break;
} else
i++;
if (j<i) {
process_word(buf+j);
i++;
}
}
generate_word_list();
}

void CInGodsTimeDlg::OnSelectWords()
{
int file_size;
FILE in_file;
char buf,cur_dir[MAX_PATH+32];
CFileDialog d(TRUE,"Txt","",OFN_HIDEREADONLY | OFN_FILEMUSTEXIST,
"Text Files (.Txt)|.Txt|All Files (.)|.||");

GetCurrentDirectory(MAX_PATH,cur_dir);
strcat(cur_dir,"\\*.TXT");
d.GetOFN().lpstrFile=cur_dir;

if (d.DoModal()==IDCANCEL)
return;
in_file=fopen(d.GetPathName(),"rb");

UpdateData();

/*
if (m_main.GetLength())
m_main+="\r\n\r\n";
m_main+=d.GetPathName();
m_main+="\r\n\r\n";
/
UpdateData(FALSE);

file_size=fsize(in_file);
buf=(char *) malloc(fsize(in_file)+1);
fread(buf,file_size,1,in_file);
buf[file_size]=0;
fclose(in_file);
process_file(buf,file_size);
free(buf);
OnChoiceWords();

}

#define DIVISOR	1

void CInGodsTimeDlg::OnStop()
{
int l,col;
LARGE_INTEGER count;
// char buf[128];

QueryPerformanceCounter(&count);
UpdateData();
switch (pick_mode) {
case pm_numbers:
m_num=(count.LowPart/DIVISOR)% m_max+1;
break;
case pm_words:
if (num_hash_entries) {
l=m_main.GetLength();
col=l-1;
while (col>0 && l!=0)
if (m_main.GetAt(col)==13)
break;
else
col--;
if (l-col>55)
m_main+="\r\n";

//	sprintf(buf,"\r\n%010u ",count.LowPart/DIVISOR);
//	m_main+=buf;
m_num=(count.LowPart/DIVISOR)% num_hash_entries;
m_main+=word_list[m_num];
m_main+=" ";
m_num=1;
}
break;
}
UpdateData(FALSE);
}

void CInGodsTimeDlg::OnChoiceWords()
{
UpdateData();
pick_mode=pm_words;
m_num=1;
UpdateData(FALSE);
}

void CInGodsTimeDlg::OnChoiceNumbers()
{
UpdateData();
pick_mode=pm_numbers;
m_num=1;
UpdateData(FALSE);
}