// StockPage.cpp : implementation file
//

#include "stdafx.h"
#include "ADO_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

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::OnFetch() 
{
	// Get values from on screen controls into mapped member variables
	UpdateData();

	if( m_Symbol.IsEmpty() )
		MessageBox("Please enter stock symbol to retrieve" );
	else
	{
		CPNADORecordset StockSet;

		CString Filter;
		Filter.Format( "symbol='%s'", (LPCSTR)m_Symbol );
		// Note the -> and the .
		StockSet->PutFilter( (LPCSTR)Filter );
		StockSet.PNOpen( "Stock" );

		if( StockSet->GetIsEOF() )
			MessageBox( "No records found" );
		else
			PopulateControls( StockSet );
	}

	
}

void CStockPage::PopulateControls(CPNADORecordset &StockSet)
{
	if( !(StockSet->GetState() & adStateOpen) || StockSet->GetIsEOF() )
	{
		m_Company.Empty();
		m_Exchange.Empty();
		m_Symbol.Empty();
		m_Industry.Empty();
		m_StockID=0;
		m_TradeList.DeleteAllItems();
		UpdateData( FALSE );
		return;
	}

	// Move data from recordsets into the onscreen controls
	StockSet.PNGetField( "Company", m_Company );
	StockSet.PNGetField( "Exchange", m_Exchange );
	StockSet.PNGetField( "Symbol", m_Symbol );
	StockSet.PNGetField( "Industry", m_Industry );

	UpdateData( FALSE );

	// Get Stock ID from recordset for current record data member (not displayed)
	StockSet.PNGetField( "StockID", m_StockID );

	// Empty or populate the Trade ListView window with transactions
	// for the current stock
	if( m_StockID != 0 )
		PopulateTradeList();


}

void CStockPage::OnNew() 
{
	// User clicked button to add a new Stock record to the database
	// Use the ADO classes and CStockDlg to do most of the work
	CPNADORecordset StockSet;
	CStockDlg StockDlg;
	if( StockDlg.DoModal( StockSet, true ) == IDOK )
		PopulateControls( StockSet );
}

void CStockPage::OnEdit() 
{
	// User clicked button to edit a Stock record in the database
	if( m_StockID==0 )
	{
		MessageBox( "Please fetch a stock to edit first" );
		return;
	}

	// Use the ADO classes and CStockDlg to do most of the work
	CPNADORecordset StockSet;
	CStockDlg StockDlg;
	if( StockDlg.DoModal( StockSet, false ) == IDOK )
		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 )
	{
		// Delete Transactions (trades) for the stock
		CString strSQL;
		strSQL.Format( "delete from Trade where StockID=%d", m_StockID );
		CPNADORecordset::PNExecute( strSQL );

		// Delete Portfolio records for the stock
		strSQL.Format( "delete from Portfolio where StockID=%d", m_StockID );
		CPNADORecordset::PNExecute( strSQL );

		// Delete Stock record
		strSQL.Format( "delete from Stock where StockID=%d", m_StockID );
		CPNADORecordset::PNExecute( strSQL );

		CPNADORecordset Tmp;
		PopulateControls( Tmp );
	}
	
}

int CStockPage::PopulateTradeList()
{
	CPNADORecordset 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
	CString TradeQuery;
	TradeQuery.Format( "Select * from Trade where StockID=%d Order by TradeDate", m_StockID );

	try
	{
		if( TradeSet.PNOpen( TradeQuery ) != S_OK )
		{
			MessageBox( "Unexpected error opening Trade table" );
			return(0);
		}
	}
	catch( _com_error* E )
	{
		
		MessageBox( E->Description() );
		return(0);
	}
	// Iterate through the trade records, and put the data from
	// the table into the ListView control
	CString Text;
	// Fields for record
	COleDateTime Date;
	int Num;
	double Dbl;

	while( !TradeSet->GetIsEOF() )
	{
		// Get Date and Time from Trade record of table, and put
		// into the Trade list on screen
		if( TradeSet.PNGetField( "TradeDate", Date ) )
			Text=Date.Format("%m/%d/%Y %I:%M:%S %p");
		else
			Text="N/A";
		Index = m_TradeList.InsertItem( m_TradeList.GetItemCount(), Text );

		// Store the Trade ID of the record in the list controls Item Data
		// value, for easy retrieval later.
		TradeSet.PNGetField( "TradeID", Num );
		m_TradeList.SetItemData( Index, Num );

		// Get the trade price from the database table, and put
		// it into the Table list on screen

		if( TradeSet.PNGetField( "Price", Dbl ) )
			Text.Format( "$%.2f", Dbl );
		else
			Text = "N/A";
		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.PNGetField( "Change", Dbl ) )
		{
			if( Dbl > 0 )
				Text.Format( "+%.2f", Dbl );
			else
				Text.Format( "%.2f", Dbl );
		}
		else
			Text = "N/A";
		m_TradeList.SetItemText( Index, 2, Text );
			
		// Move to next Trade
		TradeSet->MoveNext();

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

}

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 dialog and recordset, to do most of the work
	CPNADORecordset 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( );
	
}

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 )
	{
		// Delete the record using the PNExecute method of CPNADORecordset class
		// (as a SQL command)
		CString Command;
		Command.Format( "delete from Trade where TradeID = %d", m_TradeList.GetItemData(Index) );
		CPNADORecordset::PNExecute( Command );
		
		// And refresh the Trade ListView control
		m_TradeList.DeleteItem( Index );
	}
}

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
		CPNADORecordset Portfolio;
		CPNADORecordset TradeSet;

		// Open the portfolio recordset, and place it in 'Insert' mode
		Portfolio.PNOpen("Portfolio");
		Portfolio->AddNew();
		
		// Get the next unique ID for the Portfolio record
		Portfolio.PNSetField( "PortfolioID", Portfolio.PNGetNextID("Portfolio") );

		// Initialize the other fields of the Portfolio recordset
		double LatestPrice=0.0;
		CString LatestQry;
		LatestQry.Format( "select * from trade where StockID=%d Order by TradeDate DESC", m_StockID );
		TradeSet.PNOpen( LatestQry );
		if( !TradeSet->GetIsEOF() ) 
			TradeSet.PNGetField( "Price", LatestPrice );

		Portfolio.PNSetField( "StockID", m_StockID );
		Portfolio.PNSetField( "PurchaseDate", COleDateTime::GetCurrentTime() );
		Portfolio.PNSetField( "PurchasePrice",  LatestPrice );
		Portfolio.PNSetField( "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();
}
