// StockCGI.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include "StockCGI.h"

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

/////////////////////////////////////////////////////////////////////////////
// The one and only application object

CWinApp theApp;

using namespace std;

char InputData[4096];

void PNGetAllParams()
{
	// Determing if was a POST or GET method
	if( getenv( "REQUEST_METHOD" ) == 0 )
	{
		cout << "No REQUEST_METHOD, must be running in DOS mode" << endl;
		return;
	}
	if( strcmp( getenv("REQUEST_METHOD"), "POST" ) == 0 )
	{
		// If POST, then get data from
		int InputLength = atoi( getenv("CONTENT_LENGTH") ); 
		cin.read( InputData, InputLength );
	}
	else
		strcpy( InputData, getenv( "QUERY_STRING" ) );
}

int PNGetParam( const char * Name, CString& Dest, const char* Default )
{
	Dest.Empty();

	// Helper macro to convert two-character hex strings to character value
#define ToHex(Y) (Y>='0'&&Y<='9'?Y-'0':Y-'A'+10)
	// Search for the desired parameter name in InputData
	char* pArg = strstr( InputData, Name );
	if( pArg ) // If found
	{
		// Go to the start of the parameter
		pArg += strlen(Name);
		if( *pArg == '=' )  // Make sure there is an '=' where we expect it
		{
			pArg++;
			// Loop until we hit the end of this parameter value
			while( *pArg && *pArg != '&' )
			{
				// If the character is a '%', that means 2-character hex value follows
				if( *pArg == '%' )
				{
					// Convert it to a single ASCII character and store at our destination
					Dest += (char)ToHex(pArg[1]) * 16 + ToHex(pArg[2]);
					pArg += 3;
				}
				else
					if( *pArg=='+' ) // If it's a '+', store a space at our destination
					{
						Dest += ' ';
						pArg++;
					}
					else
						Dest += *pArg++; // Otherwise, just store the character at our destination
			}
			return(1);
		}
	}
	Dest = Default; // If param not found, then use default parameter
	return(0);
}

void ListStocks()
{

	try
	{
		// Create the CDatabase object and connect it to the database
		CDatabase Db;
		Db.Open( NULL, FALSE, FALSE, "ODBC;DSN=PNStocks", FALSE );
		
		// Create CRecordset object, and pass the CDatabase to its constructor
		CRecordset Rs( &Db );

		// Open the SQL query with the CRecordset (Read only mode)
		Rs.Open(AFX_DB_USE_DEFAULT_TYPE, "select Symbol, Company from Stock order by Company" );

		CString Symbol, Company;
		cout << "Symbols and companies:<BR>" << endl;

		// Loop through list of all the Stock records found
		while( !Rs.IsEOF() )
		{
			// Get the Stock symbol and company name from the recordset
			Rs.GetFieldValue( (short)0, Symbol );
			Rs.GetFieldValue( (short)1, Company );

			// And output in HTML format
			cout << (LPCSTR)Symbol << "&nbsp;&nbsp;&nbsp;&nbsp;";
			cout << (LPCSTR)Company << "<BR>" << endl;
			Rs.MoveNext(); // Move to next record
		}

	}
	catch( CDBException* pE )
	{
		// Report any errors
		char Tmp[512];
		pE->GetErrorMessage( Tmp, sizeof(Tmp) );
		cout << "Error: " << Tmp << "<BR>" << endl;
	}

}

void ListTrades( const char* Symbol)
{
	
	try
	{
		// Create the CDatabase object and connect it to the database
		CDatabase Db;
		Db.Open( NULL, FALSE, FALSE, "ODBC;DSN=PNStocks", FALSE );

		// Create CRecordset object, and pass the CDatabase to its constructor
		CRecordset Rs( &Db );

		// Build Query string with the stock symbol, and open the Trade and Stock table with it
		CString Query;
		Query = "select Trade.TradeDate, Trade.Price from Trade,Stock ";
		Query += " where Stock.Symbol='";
		Query += Symbol;
		Query += "' and Stock.StockID=Trade.StockID ";
		Query += " order by Trade.TradeDate DESC";

		Rs.Open(AFX_DB_USE_DEFAULT_TYPE, Query);

		CString TradeDate, Price;
		if( Rs.IsEOF() )
			cout << "No trades found for " << Symbol << "<BR>" << endl;
		else
		{
			// Loop through all the Trade records for the specific stock symbol
			cout << "Trades for " << Symbol << ":<BR>" << endl;
			while( !Rs.IsEOF() )
			{
				// Retrieve the TradeDate and Price field values from the query
				Rs.GetFieldValue( (short)0, TradeDate );
				Rs.GetFieldValue( (short)1, Price );

				// Output in HTML format
				cout << (LPCSTR)TradeDate << "&nbsp;&nbsp;&nbsp;&nbsp;";
				cout << (LPCSTR)Price << "<BR>" << endl;
				Rs.MoveNext(); // Move to next record
			}
		}

	}
	catch( CDBException* pE )
	{
		// Report any errors in HTML format
		char Tmp[512];
		pE->GetErrorMessage( Tmp, sizeof(Tmp) );
		cout << "Error: " << Tmp << "<BR>" << endl;
	}


}

int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
{
	int nRetCode = 0;

	// Output standard HTML CGI header
	cout << "Content-type: text/html\n\n";
	cout << "<HTML><BODY>" << endl;

	// initialize MFC and print and error on failure
	if (!AfxWinInit(::GetModuleHandle(NULL), NULL, ::GetCommandLine(), 0))
	{
		// TODO: change error code to suit your needs
		cerr << "Fatal Error: MFC initialization failed<P>" << endl;
	}
	else
	{
		// TODO: code your application's behavior here.
		PNGetAllParams();
		CString Stock;
		PNGetParam( "Stock", Stock, "" );
		if( Stock.IsEmpty() )
			ListStocks();
		else
			ListTrades( Stock );
	}

	// Output standard HTML CGI footer
	cout << "</HTML></BODY>" << endl;

	return nRetCode;
}


