/* Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved. */

// SearchDicomDlg.cpp : implementation file
//

#include "stdafx.h"
#include "clientUI.h"
#include "SearchDicomDlg.h"
#include "ListDicomDlg.h"


// SearchDicomDlg dialog

IMPLEMENT_DYNAMIC(SearchDicomDlg, CDialog)

SearchDicomDlg::SearchDicomDlg(DB_ENV *env, DICOM_DBS dm_dbs, 
    CWnd* pParent /*=NULL*/)
	: CDialog(SearchDicomDlg::IDD, pParent)
{
	int i;
	
	// Initialize bdb environment and database handles.
	m_dbs = dm_dbs;
	m_env = env;	

	// Initialize the arrays of queried attributes and their value.
	for (i = 0; i < ATTRIBUTENUM;i++) {
		m_selAtt[i] = false;
		m_selValue[i] = "";
	}
}

SearchDicomDlg::~SearchDicomDlg()
{

}

void SearchDicomDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
	DDX_Control(pDX, IDC_COMBO_ATTRIBUTES, pComboAttribute);
	DDX_Control(pDX, IDC_COMBO_VALUE, pComboValue);
	DDX_Control(pDX, IDC_EDIT_QUERY, pEditQuery);
}

BOOL SearchDicomDlg::OnInitDialog()
{
	LPWSTR name;
	int i;
	
	CDialog::OnInitDialog();

	// Insert wide strings of all attributes' name into the combo box  
	// of attributes' name.
	for (i = 0; i < ATTRIBUTENUM;i++) {
		name = *(convertCharToWchar(atts_name[i]));
		pComboAttribute.AddString(name);
		free(name);
	}
	
	return true;
}

BEGIN_MESSAGE_MAP(SearchDicomDlg, CDialog)
	ON_CBN_SELCHANGE(IDC_COMBO_ATTRIBUTES, 
	    &SearchDicomDlg::OnCbnSelchangeComboAttributes)
	ON_BN_CLICKED(IDC_BUTTON_ADD, &SearchDicomDlg::OnBnClickedButtonAdd)
	ON_BN_CLICKED(IDC_BUTTON_RESUME, 
	    &SearchDicomDlg::OnBnClickedButtonResume)
	ON_BN_CLICKED(IDC_BUTTON_SEARCH, 
	    &SearchDicomDlg::OnBnClickedButtonSearch)
END_MESSAGE_MAP()


// SearchDicomDlg message handlers

void SearchDicomDlg::OnCbnSelchangeComboAttributes()
{
	DBC *cursorp;      // Cursor on secondary index.
	DB_TXN *txn;       // Transaction to get keys in secondary index.
	CString selString; // String of selected attribute.
	LPWSTR value;      // Wide string of query.
	char **keyString;  // String array of query.       
	int i;             // Iterate over all values of the selected 
			   // attribute.
	int indexed;       // Whether selected attribute is indexed.
	int number;        // Number of values of the selected attribute.
	int selIndex;      // Index of selected attribute in all attributes.
	int ret;

	// Initialize members.
	cursorp = NULL;
	txn = NULL;
	indexed = 0;
	keyString = new char*[50];
	ret = 0;
	
	// Get index of selected attribute in all attributes.
	selIndex  = pComboAttribute.GetCurSel();

	// Get string of selected attribute.
	pComboAttribute.GetLBText(selIndex, selString);
	
	// Clean the text in combo box of attribute value.
	pComboValue.ResetContent();

	// If the selected attribute is indexed, list all values on the 
	// attribute, that is all keys in its corresponding secondary index.
	if ((selString == "Patient's Name") || (selString == "Modality") || 
	    (selString == "Acquisition Date")) {
		// The current attribute is indexed.
		indexed = 1;

		// Begin transaction. 
		ret = m_env->txn_begin(m_env, NULL, &txn, 0);
		if (ret != 0) {
			MessageBox(TEXT("Fail to begin transaction!"), NULL,
			    MB_ICONERROR | MB_OK);
			EndDialog(-1);
			return;
		}

		if (selString == "Patient's Name")
			ret = m_dbs.pn_sdbp->cursor(m_dbs.pn_sdbp, txn, 
			    &cursorp, 0); 
		else if (selString == "Modality") 
			ret = m_dbs.md_sdbp->cursor(m_dbs.md_sdbp, txn, 
			    &cursorp, 0); 
		else // (selString == "Acquisition Date")
			ret = m_dbs.ad_sdbp->cursor(m_dbs.ad_sdbp, txn, 
			    &cursorp, 0); 

		if (ret != 0) {
			MessageBox(TEXT(
			    "Fail to create cursor in secondary index!"), 
			    NULL, MB_ICONERROR | MB_OK);
			EndDialog(-1);
			txn->abort(txn);
			return;	
		}

		// Retrieve all keys in keyString array.
		ret = retrieve_key_with_cursor(m_env, cursorp, keyString,
		    &number);
		if (ret == 0) {
			// Add keys in the combo box of attribute value.
			for (i = 0; i < number;i++)  {
				// Convert the value to wide string.
				value = *(convertCharToWchar(keyString[i]));
			
				// Insert into the combo box.
				pComboValue.AddString(value);
			
				// Free memory of the wide string.
				free(value);
			}
			
			// Free memory of keys.
			for (i = 0; i < number; i++)
				free(keyString[i]);
		}

		ret = cursorp->close(cursorp);
		if (ret != 0) {
			MessageBox(TEXT("Fail to close cursor!"), 
			    NULL, MB_ICONERROR | MB_OK);
			txn->abort(txn);
			return;
		}

		txn->commit(txn, 0);
	}
	
}


void SearchDicomDlg::OnBnClickedButtonAdd()
{
	CString attString;    // Queried attribute and value.
	CString queryString;  // Combination of queried attribute and value.
	CString valString;    // Queried value.
	int i;
	int att_idx;          // Index of selected attribute in all 
			      // attributes.
	int index;            // Index of selected attribute in combo box.
	wchar_t attName[20];  // Wide string of queried attribute name.
	wchar_t attValue[50]; // Wide string of queried attribute value.
	extern char atts_name[ATTRIBUTENUM][40];  
	        	      // The name of all attributes.
	char *a;              // Char string of queried attribute.
	
	// Initialize the query string.
	queryString = "";                
	
	// Get the index of selected attribute.
	index = pComboAttribute.GetCurSel(); 

	// Either click on any attribute name in the combo box or input one.
	if (index < 0) {
		// Get the text in the combo box.	
		pComboAttribute.GetWindowTextW((LPTSTR)attName, 20); 
		
		// Convert the text to char string and find its index in 
		// all attributes.
		a = *convertWcharToChar(attName);
		att_idx = find_attributes_index(a);
		free(a);
		
		// If the input one is not a valid attribute name, give out 
		// warning and clear the combo box of attribute value.
		if (att_idx == -1) {
			MessageBox(TEXT("Sorry, no such attribute!"));
			pComboValue.ResetContent();
			return;
		}

		// If the input one is a valid attribute name, set the 
		// corresponding one in the boolean array to be true.
		m_selAtt[att_idx] = true;
	} else {
		// If any attribute in the combo box is being selected, get 
		// its name to get its index of all attributes and set the 
		// corresponding one in the boolean array to be true.
		pComboAttribute.GetLBText(index, attString);
		a = *convertWcharToChar(attString.GetBuffer());
		att_idx = find_attributes_index(a);
		m_selAtt[att_idx] = true;
		free(a);
	}

	// Either click on any attribute value in the combo box or input 
	// one.
	index = pComboValue.GetCurSel(); 
	if (index < 0) {
		pComboValue.GetWindowTextW((LPTSTR)attValue, 50);
		m_selValue[att_idx] = attValue;
	} else {
		pComboValue.GetLBText(index, valString);
		m_selValue[att_idx] = valString;
	}

	// Get query string of all queried attributes and their values.
	for (i = 0; i < ATTRIBUTENUM; i++) {
		if (m_selAtt[i] == true) {
			queryString += atts_name[i];
			queryString += " = \"";
			queryString += m_selValue[i];
			queryString += "\"\r\n";
		}
	}

	// Set the content in edit box to be the query string.
	pEditQuery.SetWindowTextW(queryString);
}

void SearchDicomDlg::OnBnClickedButtonResume()
{
	// Clear the combo box of attribute name.
	pComboAttribute.SetWindowTextW(TEXT(""));
	
	// Clear the combo box of attribute value.
	pComboValue.ResetContent();
	
	// Clear the edit box of query.
	pEditQuery.SetWindowTextW(TEXT(""));
	
	// Reset the arrays of selected attributes and their values.
	for (int i = 0; i < ATTRIBUTENUM;i++) {
		m_selAtt[i] = false;
		m_selValue[i] = "";
	}
}

void SearchDicomDlg::OnBnClickedButtonSearch()
{
	DBC *cursors[SEC_INDEX_NUM];
				// Cursors on queried indexed attributes.
	DB_TXN *txn;
	DICOM_IMAGE list[MAX_NUMBER] = {}; 
				// DICOM result set.
	char *mulQuery[ATTRIBUTENUM] = {};  
	        		// Queried strings.
	int i;			// Iterate over all attributes.   
	int index;		// The last attribute.
	int secIndex;		// The last indexed attribute.
	int number;		// The number of DICOMs in result set.
	int queriedNum;		// Number of queried attributes.
	int ret;

	// Initialize variables.
	index = ATTRIBUTENUM;
	secIndex = SEC_INDEX_NUM;
	ret = 0;

	// Begin transaction. 
	ret = m_env->txn_begin(m_env, NULL, &txn, 0);
	if (ret != 0) {
		MessageBox(TEXT("Fail to begin transaction!"), NULL,
		    MB_ICONERROR | MB_OK);
		EndDialog(-1);
		return;
	}

	// Iterate over all attributes to see how many attributes are 
	// queried. For every queried attribute, get char string from the 
	// with string of the queried attribute value.
	for (i = 0, queriedNum= 0; i < ATTRIBUTENUM; i++) {
		if (m_selAtt[i] == true) {
			index = i;
			switch(i) {
			case ACQUISITIONDATE:
				secIndex = S_ADOFFSET;
				ret = m_dbs.ad_sdbp->cursor(m_dbs.ad_sdbp, 
				    txn, &cursors[S_ADOFFSET], 0); 
				break;
			case MODALITY:
				secIndex = S_MDOFFSET;
				ret = m_dbs.md_sdbp->cursor(m_dbs.md_sdbp, 
				    txn, &cursors[S_MDOFFSET], 0); 
				break;
			case PATIENTNAME:
				secIndex = S_PNOFFSET;
				ret = m_dbs.pn_sdbp->cursor(m_dbs.pn_sdbp, 
				    txn, &cursors[S_PNOFFSET], 0);
				break;
			}

			if (ret != 0) {
				MessageBox(TEXT("Fail to create cursor!"));
				goto err;
			}

			queriedNum++;
			mulQuery[i] = *convertWcharToChar(
			    m_selValue[i].GetBuffer());	
		} 
	}

	// If non attribute is queried, give out the warning.
	if (queriedNum == 0) {
		MessageBox(TEXT("Please add query!"));
		return;
	}

	// If only one attribute is queried, see if it is indexed. If so, 
	// retrieve the DICOM in its corresponding secondary index. Unless,
	// retrieve it in primary database.
	if (queriedNum == 1) {	
		// If it is indexed, go through keys in its correponding 
		// secondary index to find the DICOM. Unless, search it 
		// in primary database.
		if (secIndex < SEC_INDEX_NUM)
			ret = retrieve_dicom_with_cursor(cursors[secIndex], 
			    mulQuery[index], list, &number);
		else 
			ret = retrieve_dicom_with_dbp(m_dbs.dicom_dbp, txn, 
			    atts_name[index], mulQuery[index], list, 
			    &number);	    
	} else {
		// If more than one attributes are queried, get cursors
		// ready and find all matching DICOMs in bdb. 
		ret = retrieve_dicom_with_multiple_attributes(m_env, 
		    m_dbs.dicom_dbp, cursors, m_selAtt, mulQuery, list, 
		    &number);
	}
	
	// If there is no error, show the list of DICOMs in another dialog.
	if (ret != 0) 
		MessageBox(TEXT("Error retrieving DICOM! Please retry. "));
	else {
		ListDicomDlg listDlg(list, number, m_dbs, m_env, false);
		listDlg.DoModal();
	}

	// Free memory of char string. 
	for (i = 0, queriedNum= 0; i < ATTRIBUTENUM; i++) {
		if (mulQuery[i] != NULL) 
			free(mulQuery[i]);
	}

err:
	// Close the cursor in patient's name secondary index.  
	for (int i = 0; i < SEC_INDEX_NUM; i++) {
		if (cursors[i] != NULL) {
			ret = cursors[i]->close(cursors[i]);
			if (ret != 0)
				MessageBox(TEXT("Fail to close cursor!"), 
				    NULL, MB_ICONERROR | MB_OK);
		}
	}

	// Commit the transaction.
        ret = txn->commit(txn, 0);
	if (ret != 0) 
		MessageBox(TEXT("Fail to commit after closing cursor!"), 
		    NULL, MB_ICONERROR | MB_OK);
}
