// StockPage.cpp : implementation file
//

#include "stdafx.h"
#include "ODBC_Stock.h"
#include "StockPage.h"

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

/////////////////////////////////////////////////////////////////////////////
// CStockPage dialog


CStockPage::CStockPage(CWnd* pParent /*=NULL*/)
	: CDialog(CStockPage::IDD, pParent)
{
	//{{AFX_DATA_INIT(CStockPage)
	m_Company = _T("");
	m_Exchange = _T("");
	m_Industry = _T("");
	m_Symbol = _T("");
	//}}AFX_DATA_INIT

	m_StockID = 0;
}


void CStockPage::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
	//{{AFX_DATA_MAP(CStockPage)
	DDX_Control(pDX, IDC_TRADE, m_TradeList);
	DDX_Text(pDX, IDC_COMPANY, m_Company);
	DDX_Text(pDX, IDC_EXCHANGE, m_Exchange);
	DDX_Text(pDX, IDC_INDUSTRY, m_Industry);
	DDX_Text(pDX, IDC_SYMBOL, m_Symbol);
	//}}AFX_DATA_MAP
}


BEGIN_MESSAGE_MAP(CStockPage, CDialog)
	//{{AFX_MSG_MAP(CStockPage)
	ON_BN_CLICKED(IDC_FETCH, OnFetch)
	ON_BN_CLICKED(IDC_NEW, OnNew)
	ON_BN_CLICKED(IDC_EDIT, OnEdit)
	ON_BN_CLICKED(IDC_DELETE, OnDelete)
	ON_BN_CLICKED(IDC_NEWTRADE, OnNewtrade)
	ON_BN_CLICKED(IDC_DELETETRADE, OnDeletetrade)
	ON_BN_CLICKED(IDC_ADDPORT, OnAddport)
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CStockPage message handlers

void CStockPage::OnFetch() 
{
	// Get values from on screen controls into mapped member variables
	UpdateData();

	if( m_Symbol.IsEmpty() )
		MessageBox("Please enter stock symbol to retrieve" );
	else
	{
		// Create a CStockset recordset, and search for the entered stock symbol
		CStockSet StockSet;
		StockSet.m_strFilter.Format( "symbol='%s'", (LPCSTR) m_Symbol );
		StockSet.Open();
		
		// If not found, tell the user, otherwise, populate the onscreen controls
		if( StockSet.IsEOF() )
			MessageBox( "No records found" );
		else
			PopulateControls( StockSet );
	}

}

void CStockPage::OnNew() 
{

	// User clicked button to add a new Stock record to the database
	// Use the CStockSet recordset and CStockDlg to do most of the work
	CStockSet StockSet;
	CStockDlg StockDlg;
	StockDlg.DoModal( StockSet, true );

	PopulateControls( StockSet );

}

void CStockPage::PopulateControls(CStockSet &StockSet)
{
	// Move data from recordsets into the onscreen controls
	m_Company = StockSet.m_Company;
	m_Exchange = StockSet.m_Exchange;
	m_Industry = StockSet.m_Industry;
	m_Symbol = StockSet.m_Symbol;
	UpdateData(FALSE);

	// Save the unique Stock ID (not symbol) for our purposes later
	if( StockSet.IsOpen() )
		m_StockID = StockSet.m_StockID;
	else
		m_StockID = 0;

	// Empty or populate the Trade ListView window with transactions
	// for the current stock
	if( m_StockID != 0 )
	{
		CTradeSet Trades;
		PopulateTradeList( Trades );
	}
	else
		m_TradeList.DeleteAllItems();
}

void CStockPage::OnEdit() 
{
	// User clicked the Edit stock button
	if( m_StockID==0 )
	{
		MessageBox( "Please fetch a stock to edit first" );
		return;
	}
	
	// Use the CStockSet recordset and CStockDlg to do most of the work
	CStockSet StockSet;
	CStockDlg StockDlg;
	
	// Set filter to retrieve the current stock
	StockSet.m_strFilter.Format( " StockID = %d ", m_StockID );
	
	// Invoke dialog to edit, and update, the selected stock
	StockDlg.DoModal( StockSet, false );
	
	// Populate controls with any changes
	PopulateControls( StockSet );
}

void CStockPage::OnDelete() 
{
	// User hit the Delete stock button
	if( m_StockID==0 )
	{
		MessageBox( "Please fetch a stock to delete first" );
		return;
	}

	if( MessageBox( "Are you sure you want to delete this stock and its transactions?", "Confirmation", MB_ICONQUESTION|MB_YESNO ) == IDYES )
	{
		// Create a recordset object, and locate the desired stock
		CStockSet Tmp;
		Tmp.m_strFilter.Format( "StockID=%d", m_StockID );
		Tmp.Open();

		// Delete Transactions (trades) for the stock
		CString strSQL;
		strSQL.Format( "delete from Trade where StockID=%d", m_StockID );
		Tmp.m_pDatabase->ExecuteSQL( strSQL );

		// Delete stock from portfolio (if it's there)
		strSQL.Format( "delete from Portfolio where StockID=%d", m_StockID );
		Tmp.m_pDatabase->ExecuteSQL( strSQL );

		// Delete this Stock record itself
		Tmp.Delete();

		// Populate the controls (should now clear out all the data from the screen)		
		Tmp.Close();
		Tmp.m_StockID=0;
		PopulateControls( Tmp );
	}
}

void CStockPage::OnNewtrade() 
{
	// User clicked button to add a new trade for the current stock
	if( m_StockID == 0 )
	{
		MessageBox( "Please fetch a stock first" );
		return;
	}

	// Create a Trade recordset and dialog, to do most of the work
	CTradeSet TradeSet;
	CTradeDlg TradeDlg;

	// Invoke the dialog, and if user added a new trade, then
	// update the trade ListView control with the new data
	if( TradeDlg.DoModal( TradeSet, true, m_StockID ) == IDOK )
		PopulateTradeList( TradeSet );
}

void CStockPage::OnDeletetrade() 
{
	// User clicked button to delete the current Trade
	int Index = m_TradeList.GetNextItem( -1, LVNI_SELECTED );
	if( Index < 0 )
	{
		MessageBox( "Please select a trade to delete first" );
		return;
	}
	if( MessageBox( "Are you sure you want to delete the selected trade transaction?", "Confirmation", MB_ICONQUESTION|MB_YESNO ) == IDYES )
	{
		// Create recordset, and search for record to delete
		CTradeSet TradeSet;
		TradeSet.m_strFilter.Format( "TradeID=%d", m_TradeList.GetItemData(Index) );
		TradeSet.Open();

		// Then delete the record
		TradeSet.Delete();

		// And refresh the Trade ListView control
		m_TradeList.DeleteItem( Index );
	}
}

int CStockPage::PopulateTradeList(CTradeSet &TradeSet)
{
	// Updates the trades in the Trade ListView control for the 
	// currently selected stock (if any)

	// Remove all items from the display first
	m_TradeList.DeleteAllItems();

	int Index, Count=0;

	// If there is a selected Stock ID, and there are trades for it
	if( m_StockID && TradeSet.Select( m_StockID ) )
	{
		// Iterate through the trade records, and put the data from
		// the table into the ListView control
		CString Text;
		while( !TradeSet.IsEOF() )
		{
			// Get Date and Time from Trade record of table, and put
			// into the Trade list on screen
			Text=TradeSet.m_TradeDate.Format("%m/%d/%Y %I:%M:%S %p");
			Index = m_TradeList.InsertItem( m_TradeList.GetItemCount(), Text );
			m_TradeList.SetItemData( Index, TradeSet.m_TradeID );

			// Get the trade price from the database table, and put
			// it into the Table list on screen
			if( TradeSet.IsFieldNull( &TradeSet.m_Price ) )
				Text = "N/A";
			else
				Text.Format( "$%.2f", TradeSet.m_Price );
			m_TradeList.SetItemText( Index, 1, Text );
			
			// Get the Trade change from the database table, and put
			// it into the Table list on screen
			if( TradeSet.IsFieldNull( &TradeSet.m_Change ) )
				Text = "N/A";
			else
			{
				if( TradeSet.m_Change > 0 )
					Text.Format( "+%.2f", TradeSet.m_Change );
				else
					Text.Format( "%.2f", TradeSet.m_Change );
			}
			m_TradeList.SetItemText( Index, 2, Text );
			
			// Move to next Trade
			TradeSet.MoveNext();

			Count++; // Keep track of how many trades there were
		}
	}
	return( Count );
}

BOOL CStockPage::OnInitDialog() 
{
	// Initialize the CStockPage so that the ListView control has the
	// correct column names and widths.
	
	// Remember: This dialog is really a child window of a tab control,
	// and is therefor a 'page' in that control
	CDialog::OnInitDialog();
	
	// TODO: Add extra initialization here
	m_TradeList.InsertColumn( 0, "Date" );
	m_TradeList.InsertColumn( 1, "Price" );
	m_TradeList.InsertColumn( 2, "Change" );
	CRect Rect;
	m_TradeList.GetClientRect( &Rect );
	m_TradeList.SetColumnWidth( 0, Rect.right / 3 );
	m_TradeList.SetColumnWidth( 1, Rect.right / 3 );
	m_TradeList.SetColumnWidth( 2, Rect.right / 3 );
	
	return TRUE;  // return TRUE unless you set the focus to a control
	              // EXCEPTION: OCX Property Pages should return FALSE
}

void CStockPage::OnCancel() 
{
	// Don't do anything if user hits Esc key
	// CDialog::OnCancel();
}

void CStockPage::OnAddport() 
{
	// User clicked button to add the current Stock to the Portfolio
	// table in the database
	if( m_StockID == 0 )
		MessageBox( "Please create or fetch a stock first");
	else
	{
		CSharesDlg Shares;

		// Popup the dialog to ask them how many shares
		if( Shares.DoModal() == IDCANCEL )
			return;

		// Create a Portfolio recordset object and a Stock recordset object
		CPortfolioSet Portfolio;
		CStockSet StockSet;

		// Open the portfolio recordset, and place it in 'Insert' mode
		Portfolio.Open();
		Portfolio.AddNew();
		
		// Get the next unique ID for the Portfolio record
		Portfolio.GetNextID();

		// Initialize the other fields of the Portfolio recordset
		Portfolio.m_StockID = m_StockID;
		Portfolio.m_PurchaseDate = CTime::GetCurrentTime();
		Portfolio.m_PurchasePrice = StockSet.GetLatestPrice( m_StockID );
		Portfolio.m_Shares = Shares.m_Shares;

		// Do an update, which actually adds the data to the Portfolio
		// database table
		Portfolio.Update();

	}
}

// These functions provide printing ability.  They are functions designed
// to mimick the functions that the view provides for printing, and in
// fact the view will call these functions to perform the actual print handling
BOOL CStockPage::OnPreparePrinting(CPrintInfo *pInfo)
{

	if( m_StockID == 0 )
	{
		MessageBox( "You must fetch a stock before you can print it." );
		return( FALSE );
	}
	

	return( TRUE );
}


void CStockPage::OnBeginPrinting(CDC *pDC, CPrintInfo *pInfo)
{
	pDC->SetMapMode( MM_HIENGLISH );

	// Create Fonts for report
	m_TitleFont.CreatePointFont( 140, "Arial", pDC );
	m_SubTitleFont.CreatePointFont( 110, "Arial", pDC );
	m_BodyFont.CreatePointFont( 90, "Arial", pDC );
	LOGFONT LogFont;
	m_BodyFont.GetLogFont( &LogFont );
	LogFont.lfWeight = FW_BOLD;
	m_HeaderFont.CreateFontIndirect( &LogFont );
	
	// Determine default margin setup
	CPageSetupDialog Tmp(PSD_RETURNDEFAULT|PSD_INTHOUSANDTHSOFINCHES);
	Tmp.DoModal();
	m_Left = Tmp.m_psd.rtMargin.left - Tmp.m_psd.rtMinMargin.left;
	m_Top = -(Tmp.m_psd.rtMargin.top - Tmp.m_psd.rtMinMargin.top);
	m_Right = Tmp.m_psd.ptPaperSize.x - Tmp.m_psd.rtMargin.right - Tmp.m_psd.rtMinMargin.left;
	m_Bottom = -(Tmp.m_psd.ptPaperSize.y - Tmp.m_psd.rtMargin.bottom - Tmp.m_psd.rtMinMargin.top);

	m_ReportTime = CTime::GetCurrentTime();

	// Save items to print in the m_lpUserData data member of pInfo
	pInfo->m_lpUserData = (void*)m_TradeList.GetItemCount();
}

void CStockPage::OnPrepareDC(CDC *pDC, CPrintInfo *pInfo)
{
	// Determine Lines per page
	CSize TextSize;
	CFont* pOldFont = pDC->SelectObject( &m_BodyFont );
	TextSize = pDC->GetTextExtent( "Hy" );
	int LineHeight = TextSize.cy;
	m_MaxLines = -((m_Bottom-m_Top) / LineHeight);
	m_MaxLines--;

	if( (pInfo->m_nCurPage-1) * m_MaxLines >= (unsigned)m_TradeList.GetItemCount() )
		pInfo->m_bContinuePrinting = FALSE;
	else
		pInfo->m_bContinuePrinting = TRUE;

	pDC->SelectObject( pOldFont );

}

void CStockPage::OnPrint(CDC *pDC, CPrintInfo *pInfo)
{
	int CurY=m_Top;
	CSize TextSize;
	CString Text;
	CFont* pOldFont;
	int CurIndex, Index=0, LineHeight;


	// Determine what item from TradeList is at top of this page
	CurIndex = (pInfo->m_nCurPage-1) * m_MaxLines;

	// Output the header
	pDC->SetMapMode( MM_HIENGLISH );
	
	// Print page header
	pDC->MoveTo( m_Left, CurY );
	pDC->LineTo( m_Right, CurY );

	pDC->SelectObject( &m_BodyFont );
	Text = m_ReportTime.Format( "%A, %B %d, %Y  %I:%M %p" );
	TextSize = pDC->GetTextExtent( Text );
	LineHeight = TextSize.cy;
	CurY += TextSize.cy+50;
	pDC->TextOut( m_Left, CurY, Text );

	Text.Format( "Page %d", pInfo->m_nCurPage );
	TextSize = pDC->GetTextExtent( Text );
	pDC->TextOut( m_Right-TextSize.cx, CurY, Text );
	
	Text= m_Industry;
	pDC->SelectObject( &m_SubTitleFont );
	TextSize = pDC->GetTextExtent( Text );
	CurY += TextSize.cy+50;
	pDC->TextOut( m_Left, CurY, Text );
	
	Text.Format( "%s (%s)", (LPCSTR)m_Company, (LPCSTR)m_Exchange );
	pDC->SelectObject( &m_TitleFont );
	TextSize = pDC->GetTextExtent( Text );
	CurY += TextSize.cy+50;
	pDC->TextOut( m_Left, CurY, Text );

	pOldFont = pDC->SelectObject( &m_BodyFont );
	CurY = m_Top - 50;

	// Print column headers
	pDC->SelectObject( &m_HeaderFont );
	pDC->TextOut( m_Left, CurY, "Date" );
	Text = m_TradeList.GetItemText( CurIndex+Index, 1 );
	pDC->TextOut( m_Left+2000, CurY, "Price" );
	Text = m_TradeList.GetItemText( CurIndex+Index, 2 );
	pDC->TextOut( m_Left+3000, CurY, "Change" );

	pDC->SelectObject( &m_BodyFont );
	CurY -= LineHeight;

	// Output the rows of data
	for( Index=0; Index < m_MaxLines; Index++ )
	{

		if( Index + CurIndex >= m_TradeList.GetItemCount() )
			break;

		// Print Column 1: Trade Date;
		Text = m_TradeList.GetItemText( CurIndex+Index, 0 );
		pDC->TextOut( m_Left, CurY, Text );

		// Print Column 2: Trade Price:
		Text = m_TradeList.GetItemText( CurIndex+Index, 1 );
		pDC->TextOut( m_Left+2000, CurY, Text );

		// Print Column 3: Trade Change:
		Text = m_TradeList.GetItemText( CurIndex+Index, 2 );
		pDC->TextOut( m_Left+3000, CurY, Text );


		CurY -= LineHeight;
	}


	pDC->SelectObject( pOldFont );

}

void CStockPage::OnEndPrinting(CDC *pDC, CPrintInfo *pInfo)
{
	m_TitleFont.DeleteObject();
	m_SubTitleFont.DeleteObject();
	m_BodyFont.DeleteObject();
	m_HeaderFont.DeleteObject();
}
