Option Strict Off
Option Explicit On
Imports System.Linq
Imports System.Collections.Generic
Namespace FMStocks_Bus
   Public Class Broker
   Private Const m_modName As String = "FMStocks_Bus.Broker"
   Private Const m_errInsufficentFunds As Integer = -2147217900
   Private Const m_Commission As Decimal = 9.95
   ' returns 0 on nothing to do, -1 on error, otherwise the TxID
   Public Function BuyStock(ByVal AccountID As Integer,ByVal Ticker As String,ByVal Shares As Integer) As Integer
      BuyStock = 0

      Dim objTX As FMStocks_DB.Tx = Nothing
      Dim objTicker As FMStocks_DB.Ticker = Nothing
      Dim objbroker As FMStocks_DB.Broker = Nothing
      Dim objTXNew As FMStocks_DB.TxNew = Nothing
      Dim lngTXID As Integer = 0
      Try
         gmRTL.Core.GlobalException.ClearErrorObject()

         Dim lngErr As Integer = 0
         Dim lngPositionID As Integer = 0
         Dim lngPrice As Integer = 0


         objTX = New FMStocks_DB.Tx
         objTicker = New FMStocks_DB.Ticker
         objbroker = New FMStocks_DB.Broker

         ' first log the transaction
         lngTXID = objTX.AddBuyOrder(AccountID,Ticker,Shares)

         '
         'Get the current price
         lngPrice = CInt(objTicker.GetPrice(Ticker)) ' price in pennies

         gmRTL.Core.ErrorHandling.ResumeNext(Sub()
            lngPositionID = objbroker.Buy(lngTXID,AccountID,Ticker,Shares,lngPrice,m_Commission)
            lngErr = Err.Number                ' the next line resets Err.Number to 0, so we need to cache it
         End Sub)
         '' UPGRADE_TODO: On Error Goto errorHandler

         If (lngPositionID = 0 And lngErr = m_errInsufficentFunds) Then
            ' It's common that the user doesn't have enough funds.
            ' Set the TransactionTypeID = 5 indicating insufficient funds
            '
            ' This guy runs as a separate transaction
            objTXNew = New FMStocks_DB.TxNew
            objTXNew.SetTxType(lngTXID,CInt(FMStocks_DB.Helpers.FMStocks_TransactionType.Insufficient_Funds))

            GoTo InsufficientFundsHandler
         ElseIf (lngPositionID = 0) Then
            Throw New System.Exception()       ' some other error was thrown that we can't handle
         Else
            BuyStock = lngTXID                 ' The trade was handled
         End If

         objTX = Nothing
         objbroker = Nothing
         objTXNew = Nothing
         objTicker = Nothing


         Exit Function

      InsufficientFundsHandler:
         BuyStock = 0                       ' Signify that we handled this error.
         ' The caller should be aware that when this is returned,
         ' the transaction has been aborted, the object deactivated.
         ' An error isn't raised here (SP2) to be consistent with
         ' prior versions.

         objTX = Nothing
         objTicker = Nothing
         objbroker = Nothing
         objTXNew = Nothing


         Exit Function

      Catch exc As System.Exception
         gmRTL.Core.GlobalException.SetErrorObject(exc)
         BuyStock = -1
         objTX = Nothing
         objTicker = Nothing
         objbroker = Nothing
         objTXNew = Nothing


         FMStocks_DB.Helpers.RaiseError(m_modName,"BuyStock(" & AccountID & "," & Ticker & "," & Shares & ")",String.Empty,0,False)

      End Try
   End Function
   ' returns 0 on nothing to do, -1 on error, otherwise the TxID
   Public Function SellStock(ByVal AccountID As Integer,ByVal Ticker As String,ByVal Shares As Integer) As Integer
      SellStock = 0

      Dim objTX As FMStocks_DB.Tx = Nothing
      Dim objbroker As FMStocks_DB.Broker = Nothing
      Dim objTXNew As FMStocks_DB.TxNew = Nothing
      Dim objTicker As FMStocks_DB.Ticker = Nothing
      Try
         gmRTL.Core.GlobalException.ClearErrorObject()

         Dim price As Decimal = 0.00
         Dim txid As Integer = 0
         Dim bSellretval As Boolean = False


         objTX = New FMStocks_DB.Tx
         objbroker = New FMStocks_DB.Broker
         objTicker = New FMStocks_DB.Ticker

         txid = objTX.AddSellOrder(AccountID,Ticker,Shares)
         objTX = Nothing

         'Get the current price
         price = objTicker.GetPrice(Ticker) ' price in pennies

         gmRTL.Core.ErrorHandling.ResumeNext(Sub()
            'ignore errors on this.
            bSellretval = objbroker.Sell(txid,price,m_Commission)

         End Sub)
         '' UPGRADE_TODO: On Error Goto errorHandler

         If (Not bSellretval) Then
            ' This runs as a separate transaction
            objTXNew = New FMStocks_DB.TxNew

            ' User tried to sell shares they didn't own
            objTXNew.SetTxType(txid,CInt(FMStocks_DB.Helpers.FMStocks_TransactionType.Not_Enough_Shares))

            GoTo NotEnoughSharesHandler
         Else
            ' We're responsible for removing the appropriate shares from their positions
            AdjustPositions(AccountID,Ticker,Shares)
            SellStock = txid
         End If

         objTX = Nothing
         objbroker = Nothing
         objTXNew = Nothing
         objTicker = Nothing


         Exit Function

      NotEnoughSharesHandler:
         SellStock = 0                      ' Signify that we handled this error.
         ' The caller should be aware that when this is returned,
         ' the transaction has been aborted, the object deactivated.
         ' An error isn't raised here (SP2) to be consistent with
         ' prior versions.

         objTX = Nothing
         objbroker = Nothing
         objTXNew = Nothing
         objTicker = Nothing


         Exit Function

      Catch exc As System.Exception
         gmRTL.Core.GlobalException.SetErrorObject(exc)
         SellStock = -1
         objTX = Nothing
         objbroker = Nothing
         objTXNew = Nothing
         objTicker = Nothing


         FMStocks_DB.Helpers.RaiseError(m_modName,"SellStock(" & AccountID & "," & Ticker & "," & Shares & ")",String.Empty,0,False)
      End Try
   End Function
   ' no longer in used by buy or sell stocks
   ' Used by ExecuteTrade program.
   ' Returns 0 on nothing to do, -1 on error, otherwise the TxID
   Public Function ExecuteTransaction(ByVal txid As Integer) As Integer
      ExecuteTransaction = 0
      '' UPGRADE_TODO: On Error Goto errorHandler

      Dim rs As gmRTL.DataLib.SqlClient.Recordset = Nothing
      Dim objTX As FMStocks_DB.Tx = Nothing
      Dim objTicker As FMStocks_DB.Ticker = Nothing
      Dim objbroker As FMStocks_DB.Broker = Nothing
      Dim o As FMStocks_DB.TxNew = Nothing

      objTX = New FMStocks_DB.Tx
      objTicker = New FMStocks_DB.Ticker
      objbroker = New FMStocks_DB.Broker

      'information about the current transaction
      Dim AccountID As Integer = 0
      Dim Ticker As String = ""
      Dim PositionID As Integer = 0
      Dim price As Decimal = 0.00
      Dim retval As Boolean = False

      Dim lerr As Integer = 0

      '
      ' Get the Tx details
      rs = objTX.GetByID(txid)

      If (rs.EOF And rs.BOF) Then
         Exit Function
      End If

      AccountID = CInt(rs.Fields("AccountID").Value)
      Ticker = Strings.RTrim(rs.Fields("Ticker").Value)

      ' Only execute buy or sell orders
      If (rs.Fields("TransactionTypeID").Value <> 1 And rs.Fields("TransactionTypeID").Value <> 2) Then
         ExecuteTransaction = 0

         Exit Function
      End If

      'Get the current price
      price = objTicker.GetPrice(Ticker) ' price in pennies

      'Execute the trade
      If (rs.Fields("TransactionTypeID").Value = 1) Then
         ' Buy order

         gmRTL.Core.ErrorHandling.ResumeNext(Sub()
            PositionID = objbroker.Buy(txid,AccountID,Ticker,CInt(rs.Fields("shares").Value),price,m_Commission)
            lerr = Err.Number                  ' the next line resets Err.Number to 0, so we need to cache it
         End Sub)
         '' UPGRADE_TODO: On Error Goto errorHandler

         If (PositionID = 0 And lerr = m_errInsufficentFunds) Then
            ' It's common that the user doesn't have enough funds.
            ' Set the TransactionTypeID = 5 indicating insufficient funds
            '
            ' This guy runs as a separate transaction
            o = New FMStocks_DB.TxNew
            o.SetTxType(txid,CInt(FMStocks_DB.Helpers.FMStocks_TransactionType.Insufficient_Funds))
            o = Nothing

            GoTo InsufficientFundsHandler
         ElseIf (PositionID = 0) Then
            GoTo errorHandler                  ' some other error was thrown that we can't handle
         Else
            ExecuteTransaction = txid          ' The trade was handled
         End If
      Else
         ' Sell order

         gmRTL.Core.ErrorHandling.ResumeNext(Sub()
            retval = objbroker.Sell(txid,price,m_Commission)
            lerr = Err.Number                  ' the next line resets Err.Number to 0, so we need to cache it
         End Sub)
         '' UPGRADE_TODO: On Error Goto errorHandler

         If (Not retval) Then
            Err.Clear

            ' This runs as a separate transaction
            o = New FMStocks_DB.TxNew
            o.SetTxType(txid,CInt(FMStocks_DB.Helpers.FMStocks_TransactionType.Not_Enough_Shares)) ' User tried to sell shares they didn't own
            o = Nothing

            GoTo NotEnoughSharesHandler
         Else
            ' We're responsible for removing the appropriate shares from their positions
            AdjustPositions(AccountID,Ticker,CInt(rs.Fields("shares").Value))
            ExecuteTransaction = txid
         End If

      End If


      Exit Function

   InsufficientFundsHandler:
   NotEnoughSharesHandler:
      ExecuteTransaction = 0             ' Signify that we handled this error.
      ' The caller should be aware that when this is returned,
      ' the transaction has been aborted, the object deactivated.
      ' An error isn't raised here (SP2) to be consistent with
      ' prior versions.

      objTX = Nothing
      objTicker = Nothing
      objbroker = Nothing
      rs = Nothing


      Exit Function

   errorHandler:
      ExecuteTransaction = -1            'an invalid TransactionID used to flag an error.
      objTX = Nothing
      objTicker = Nothing
      objbroker = Nothing
      rs = Nothing
      o = Nothing


      FMStocks_DB.Helpers.RaiseError(m_modName,"ExecuteTransaction(" & txid & ")",String.Empty,0,False)

   End Function
   'all errors are handled by the caller, ExecuteTransaction
   Private Sub AdjustPositions(ByVal AccountID As Integer,ByVal Ticker As String,ByVal Shares As Integer)
      Dim objPosition As FMStocks_DB.Position = Nothing
      objPosition = New FMStocks_DB.Position

      Dim rs As gmRTL.DataLib.SqlClient.Recordset = Nothing
      Dim posShares As Integer = 0       ' number of shares for the current position
      Dim origShares As Integer = 0      'number of shares before sell
      Dim boolAdjusted As Boolean = False

      boolAdjusted = False

      rs = objPosition.ListForAdjustment(AccountID,Ticker)
      Do While Not rs.EOF And Shares > 0
         posShares = CInt(rs.Fields("shares").Value)
         boolAdjusted = True
         If (posShares <= Shares) Then
            ' we can delete this whole record
            rs.Delete()
            Shares = Shares - posShares
         Else
            rs.Fields("shares").Value = posShares - Shares ' decrement current share amount by amount sold
            Shares = 0
         End If
         rs.MoveNext()
      Loop
      rs.UpdateBatch(gmRTL.DataLib.AffectEnum.adAffectAll)
      rs.Close()
      rs = Nothing
   End Sub
   End Class
End Namespace
