// File spell2.cpp
// Descrizione contiene la descrizione dei membri delle classi definite in spell2.h
#include <afx.h>
#include <afxdlgs.h>
#include <stdlib.h>
#include "spellvar.h"
#include "tables.h"
#include "resource.h"
#include "ddx_ext.h"
#include "spell2.h"
#include "ddx_ext.cpp"
//#include "tables.cpp"

#define RT	0		// Ricerca totale
#define RS	1		// Ricerca delle stringhe
#define RSALLSCHOOL	2	// ricerca delle stringhe su tutti i file.

#define NEUTRAL	-1
#define OR		0
#define AND		1
#define MAJOR	2
#define MINOR	3


// Funzioni per la classe CArgSearch

// mappe dei messaggi
BEGIN_MESSAGE_MAP(CArgSearch, CPropertyPage)
	ON_CBN_SELCHANGE(IDC_CBLevel1, OnCasterSet)
	ON_BN_CLICKED(IDC_BLevel2a, OnAllLevel)
	ON_BN_CLICKED(IDC_BLevel2b, OnClearLevel)
	ON_BN_CLICKED(IDC_BLevel3a, OnAllSchool)
	ON_BN_CLICKED(IDC_BLevel3b, OnClearSchool)
	ON_BN_CLICKED(IDC_CHLevel4, OnButtonChange)
	ON_LBN_SELCHANGE(IDC_LLevel2, OnSelChange)
	ON_LBN_SELCHANGE(IDC_LIST2, OnSelChange)
END_MESSAGE_MAP()

// funzioni private

void CArgSearch::ReadLevel(CListBox *lista, const char * locazione)
{
    CFileFind trova;
    BOOL found = trova.FindFile(locazione);
    while (found)
    {
        found = trova.FindNextFile();
		if (!trova.IsDots() && trova.IsDirectory()) // Scuola generica e x directori in caso di ricerca
		{
			CString tmp = trova.GetFileName();
			int pos = tmp.Find('.');
			if (pos!=-1)
				tmp=tmp.Left(pos);
			lista->AddString((LPCTSTR) tmp);
		}
    }
}

// Funzioni pubbliche

BOOL CArgSearch::OnInitDialog()
{

	CDialog::OnInitDialog();

	for(int cont=0; cont<m_CasterName->GetSize(); cont++)
		GetCast()->AddString((LPCTSTR) m_CasterName->GetAt(cont));

	if(!m_CasterSel.IsEmpty())
	{
		SetLevelSpell(m_CasterSel);
		SetSchoolSpell(m_CasterSel);
		GetButton(IDC_BLevel2a)->EnableWindow();
		GetButton(IDC_BLevel2b)->EnableWindow();
		GetButton(IDC_BLevel3a)->EnableWindow();
		GetButton(IDC_BLevel3b)->EnableWindow();
		UpdateData(FALSE);
	}
	
	return TRUE;
}

// Funzioni protette

void CArgSearch::DoDataExchange(CDataExchange* pDX)
{
	CPropertyPage::DoDataExchange(pDX);

	DDX_CBString(pDX, IDC_CBLevel1, m_CasterSel);
	DDX_Check(pDX, IDC_CHLevel4, m_reversibile);

//	//{{AFX_DATA_MAP(SArgSearch)
	DDX_MultiListIndex(pDX, IDC_LLevel2, &m_LevelSel);
	DDX_MultiListIndex(pDX, IDC_LIST2, &m_SchoolSel);
//	//}}AFX_DATA_MAP
}

void CArgSearch::OnCasterSet()
{
	CString Caster;
	int num=GetCast()->GetCurSel();
	if(num==CB_ERR)
		return;

	GetCast()->GetLBText(num, Caster);
	SetLevelSpell(Caster);
	SetSchoolSpell(Caster);
	GetButton(IDC_BLevel2a)->EnableWindow();
	GetButton(IDC_BLevel2b)->EnableWindow();
	GetButton(IDC_BLevel3a)->EnableWindow();
	GetButton(IDC_BLevel3b)->EnableWindow();
	SetModified();
}


void CArgSearch::OnAllLevel()
{
	CListBox * lista=GetList(IDC_LLevel2);
	lista->SelItemRange(TRUE, 0, lista->GetCount());
	SetModified();
}

void CArgSearch::OnClearLevel()
{
	CListBox * lista=GetList(IDC_LLevel2);
	lista->SelItemRange(FALSE, 0, lista->GetCount());
	SetModified();
}

void CArgSearch::OnAllSchool()
{
	CListBox * lista=GetList(IDC_LIST2);
	lista->SelItemRange(TRUE, 0, lista->GetCount());
	SetModified();
}

void CArgSearch::OnClearSchool()
{
	CListBox * lista=GetList(IDC_LIST2);
	lista->SelItemRange(FALSE, 0, lista->GetCount());
	SetModified();
}

void CArgSearch::OnSelChange()
{
	SetModified();
}

void CArgSearch::OnButtonChange()
{
	SetModified();
}

void CArgSearch::SetLevelSpell(CString cast)
{
	if(cast.IsEmpty())
		return;

	GetList(IDC_LLevel2)->ResetContent();
	CString str=cast+"\\*.*";
	ReadLevel(GetList(IDC_LLevel2), (LPCTSTR)str);
}

void CArgSearch::SetSchoolSpell(CString cast)
{
	if(cast.IsEmpty())
		return;

	GetList(IDC_LIST2)->ResetContent();

	int sel;
	if (AfxGetApp()->GetProfileInt("Options",cast,0))
		sel=0;
	else
		for (int cont=0; cont<m_CasterName->GetSize(); cont++)
			if (cast==m_CasterName->GetAt(cont))
			{
				sel=cont;
				break;
			}

	CStringArray * CSAptr = m_SchoolName->GetTable(sel, 0);
	int maxschool= CSAptr->GetSize();
	for (int cont=0;cont<maxschool;cont++)
		GetList(IDC_LIST2)->AddString(CSAptr->GetAt(cont));
}

// Funzioni per la classe CStringSearch

//definizione mappa messaggi
BEGIN_MESSAGE_MAP(CStringSearch, CPropertyPage)
	ON_EN_CHANGE(IDC_EString1, OnEditChange)
	ON_EN_CHANGE(IDC_EString2, OnEditChange)
	ON_EN_CHANGE(IDC_EString3, OnEditChange)
	ON_EN_CHANGE(IDC_EString4, OnEditChange)
	ON_EN_CHANGE(IDC_EString5, OnEditChange)
	ON_EN_CHANGE(IDC_EString6, OnEditChange)
	ON_EN_CHANGE(IDC_EString7, OnEditChange)
	ON_BN_CLICKED(IDC_BHELP, OnSintaxHelp)
END_MESSAGE_MAP()

// funzioni private
// funzioni pubbliche

// funzioni protette

void CStringSearch::DoDataExchange(CDataExchange * pDx)
{
	DDX_CBString(pDx, IDC_EString1, m_GeneralString);
	DDX_CBString(pDx, IDC_EString2, m_RangeString);
	DDX_CBString(pDx, IDC_EString3, m_ComponentString);
	DDX_CBString(pDx, IDC_EString4, m_DurataString);
	DDX_CBString(pDx, IDC_EString5, m_CastingString);
	DDX_CBString(pDx, IDC_EString6, m_AreaString);
	DDX_CBString(pDx, IDC_EString7, m_SavingString);
}

void CStringSearch::OnEditChange()
{
	SetModified();
}

void CStringSearch::OnSintaxHelp()
{
	AfxGetApp()->WinHelp((DWORD)"String_search_help", HELP_KEY);
}

// Funzioni per la classe CFoundSpell

// funzioni pubbliche

void CFoundSpell::AddString(CString elem)
{
	((CListBox *) GetDlgItem(IDC_LIST1))->AddString(elem);
	m_Number++;
	char tmp[6];
	CString label=_itoa(m_Number, tmp, 10);
	label+=" Spell found.";
	((CStatic *) GetDlgItem(IDC_SNUM))->SetWindowText(label);
}

// funzioni protette

void CFoundSpell::DoDataExchange(CDataExchange * pDx)
{
	DDX_LBString(pDx, IDC_LIST1, m_NameSel);
	DDX_MultiList(pDx, IDC_LIST1, m_AllName);
}

// Funzioni per la classe CSearchDialog

// mappa dei comandi
BEGIN_MESSAGE_MAP(CSearchDialog, CPropertySheet)
	ON_BN_CLICKED(ID_APPLY_NOW, OnApply)
END_MESSAGE_MAP()

// funzioni private

BOOL CSearchDialog::SetFoundFile()
{
	int modo;
	if(m_FirstPage.m_CasterSel.IsEmpty() || m_FirstPage.m_SchoolSel.GetSize()==0 || m_FirstPage.m_LevelSel.GetSize()==0)
		return FALSE;

	// calcolo modalitá ricerca (string 0 meno)
	if(m_FirstPage.GetList(IDC_LIST2)->GetCount()==m_FirstPage.m_SchoolSel.GetSize() &&
		!m_FirstPage.m_reversibile &&
		m_SecondPage.m_GeneralString.IsEmpty() &&
		m_SecondPage.m_RangeString.IsEmpty() &&
		m_SecondPage.m_ComponentString.IsEmpty() &&
		m_SecondPage.m_DurataString.IsEmpty() &&
		m_SecondPage.m_CastingString.IsEmpty() &&
		m_SecondPage.m_AreaString.IsEmpty() &&
		m_SecondPage.m_SavingString.IsEmpty())
		modo=RT;
	else
		if(m_FirstPage.GetList(IDC_LIST2)->GetCount()==m_FirstPage.m_SchoolSel.GetSize())
			modo=RSALLSCHOOL;
		else
			modo=RS;

	// richiamo della ricerca per ogni livello selezionato
	CString base=m_FirstPage.m_CasterSel+"\\";
	for(int cont=0; cont<m_FirstPage.m_LevelSel.GetSize(); cont++)
	{
		CString esponente;
		m_FirstPage.GetList(IDC_LLevel2)->GetText(m_FirstPage.m_LevelSel[cont], esponente);
		FillListFile(base+esponente, modo);
	}
	return TRUE;
}

void CSearchDialog::FillListFile(CString locazione, int modo)
{
	CFileFind FileToRead;
	BOOL found=FileToRead.FindFile(locazione+"\\*.txt");
	while(found)
	{
		found=FileToRead.FindNextFile();
		if(modo==RT)
			m_ThirdPage.AddString(FileToRead.GetFileTitle());
		else if (modo==RS || modo==RSALLSCHOOL)
		{
			CStdioFile FileToOpen;
			if(!FileToOpen.Open(locazione+"\\"+FileToRead.GetFileName(), CFile::modeRead))
				continue;
			if(SearchInFile(FileToOpen, modo))
				m_ThirdPage.AddString(FileToRead.GetFileTitle());
			FileToOpen.Close();
		}
	}
}

BOOL CSearchDialog::SearchInFile(CStdioFile & file, int modo)
{
	CString riga;
	BOOL check=FALSE;
//	file.SeekToBegin();
	file.ReadString(riga);		// leggi nome
	file.ReadString(riga);		// leggi scuola

	int cont1=0;

	if(modo==RSALLSCHOOL)
		check=TRUE;
	else
	{
		// cerco il caster
		int cast=0;
		for(int cont2=0; cont2<m_FirstPage.m_CasterName->GetSize(); cont2++)
			if(m_FirstPage.m_CasterName->GetAt(cont2)==m_FirstPage.m_CasterSel)
			{
				cast=cont2;
				break;
			}
		while(!check && cont1<m_FirstPage.m_SchoolSel.GetSize())
		{
			// ricerca della referenza della scuola nella tabella.
			m_FirstPage.m_SchoolName->SetTable(cast, 0);
			CString tmp;
			m_FirstPage.GetList(IDC_LIST2)->GetText(m_FirstPage.m_SchoolSel[cont1], tmp);
			int school=m_FirstPage.m_SchoolName->IsInTable(tmp);
			if (school==-1)
			{
				MessageBox("Errore nella ricerca della stringa di School Selections", "ERROR");
				break;
			}

			// ricerca
			for(cont2=0; cont2<m_FirstPage.m_SchoolName->GetNumberLanguage(); cont2++)
			{
				m_FirstPage.m_SchoolName->SetTable(cast,cont2);
				CString tmp=m_FirstPage.m_SchoolName->GetItem(school);
				int pos=tmp.Find('/');
				if (pos>0)
					tmp=tmp.Left(pos);
				if(SearchInRow(riga, tmp))
				{
					check=TRUE;
					break;
				}
			}
			cont1++;
		}
	}

	if(!check)
		return FALSE;

	if(!m_SecondPage.m_GeneralString.IsEmpty())
	{
		while(file.ReadString(riga))
			if(riga.Find(m_SecondPage.m_GeneralString)!=-1)
				return TRUE;

		return FALSE;
	}

	file.ReadString(riga);		// lettura reversibile (se presente)
	if(m_FirstPage.m_reversibile)
	{
		if(riga.Find("Reversible") ==-1 && riga.Find("Reversibile")== -1)  //da modificare
			return FALSE;
		file.ReadString(riga);
	}
	else
		if(!riga.IsEmpty())
			file.ReadString(riga);	// salta alla riga vuota

	file.ReadString(riga);			// posiziona a range
	if(!m_SecondPage.m_RangeString.IsEmpty())
		if(!SearchInRow(riga, m_SecondPage.m_RangeString))
			return FALSE;

	file.ReadString(riga);			// posiziona a Components
	if(!m_SecondPage.m_ComponentString.IsEmpty())
		if(!SearchInRow(riga, m_SecondPage.m_ComponentString))
			return FALSE;

	file.ReadString(riga);			// posiziona a durata
	if(!m_SecondPage.m_DurataString.IsEmpty())
		if(!SearchInRow(riga, m_SecondPage.m_DurataString))
			return FALSE;

	file.ReadString(riga);			// posiziona a casting time
	if(!m_SecondPage.m_CastingString.IsEmpty())
		if(!SearchInRow(riga, m_SecondPage.m_CastingString))
			return FALSE;

	file.ReadString(riga);			// posiziona a area di effetto
	if(!m_SecondPage.m_AreaString.IsEmpty())
		if(!SearchInRow(riga, m_SecondPage.m_AreaString))
			return FALSE;

	file.ReadString(riga);			// posiziona a saving throw
	if(!m_SecondPage.m_SavingString.IsEmpty())
		if(!SearchInRow(riga, m_SecondPage.m_SavingString))
			return FALSE;

	return TRUE;
}

BOOL CSearchDialog::SearchInRow(CString riga, CString dati)
{
	CStringArray chiave;
	int operat;
	dati.MakeLower();
	riga=riga.Right(riga.GetLength()-riga.Find(":")-1);
	riga.MakeLower();
	operat = SeparaChiavi(chiave, dati);
	BOOL result=FALSE;
	BOOL exit= FALSE;
	int maxpos=chiave.GetSize();
	int cont=0;

	switch(operat)
	{
	case NEUTRAL:
	case OR		:
	case AND	:	while(!exit && cont<maxpos)
					{
						if(riga.Find(chiave[cont])!=-1)
						{
							result=TRUE;
							if(operat==OR)
								exit=TRUE;
						}
						else 
							if(operat==AND)
							{
								result=FALSE;
								exit=TRUE;
							}
						cont++;
					}

					return result;
	case MAJOR:		riga.TrimLeft();
					riga=riga.SpanIncluding("1234567890");
					if(chiave[0]<riga)
						return TRUE;
					return FALSE;
	case MINOR:		riga.TrimLeft();
					riga=riga.SpanIncluding("1234567890");
					if(chiave[0]>riga)
						return TRUE;
					return FALSE;
	default: return FALSE;
	}
}

int CSearchDialog::SeparaChiavi(CStringArray& chiave, CString sorgente)
{
	CString tmp;
	CString delim="?";
	int operatore=NEUTRAL;

	if(sorgente.Find(";")!=-1)
	{
		operatore=OR;
		delim=";";
	}
	else
		if(sorgente.Find("+")!=-1)
		{
			operatore=AND;
			delim="+";
		}
	else
		if(sorgente.Find(">")!=-1)
		{
			operatore=MAJOR;
			delim=">";
			sorgente.TrimLeft();
			sorgente=sorgente.Left(sorgente.Find(">"));
		}
	else
		if(sorgente.Find("<")!=-1)
		{
			operatore=MINOR;
			delim="<";
			sorgente.TrimLeft();
			sorgente=sorgente.Left(sorgente.Find("<"));
		}

	int pos;
	tmp=sorgente;
	while((pos=tmp.Find(delim))!=-1)
	{
		chiave.Add(tmp.Left(pos));
		tmp=tmp.Right(tmp.GetLength()-pos-1);
	}
	chiave.Add(tmp);

	return operatore;
}
//Funzioni pubbliche
CSearchDialog::CSearchDialog(CWnd* pWnd):CPropertySheet("Spell search", pWnd)
{
	AddPage(&m_FirstPage);
	AddPage(&m_SecondPage);

	m_FirstPage.m_CasterSel="";
	m_FirstPage.m_reversibile=0;
	m_ThirdPageFlag=FALSE;
	m_ThirdPage.m_Number=0;
}

void CSearchDialog::OnApply()
{

	m_FirstPage.SetModified(FALSE);
	m_SecondPage.SetModified(FALSE);

	GetActivePage()->UpdateData (TRUE);

	if(m_ThirdPageFlag)
	{
		m_ThirdPage.m_Number=0;
		m_ThirdPage.m_AllName.RemoveAll();
		RemovePage(&m_ThirdPage);
	}
	AddPage(&m_ThirdPage);

	m_ThirdPageFlag=TRUE;
	SetActivePage(&m_ThirdPage);

	if(!SetFoundFile())
	{
		MessageBox("Non sono stati elencati parametri sufficienti per una ricerca", "Message", MB_OK|MB_ICONEXCLAMATION);
		RemovePage(&m_ThirdPage);
		m_ThirdPageFlag=FALSE;
		SetActivePage(&m_FirstPage);
	}
}