Imports System.Diagnostics
Imports System.Data
Imports System.Data.SqlClient
Imports SharePrices.SharePricesUtils
Public Class DataAccessLayer
    Public Class PriceData
        Public DT As Int64
        Public Open As Double
        Public High As Double
        Public Low As Double
        Public Close As Double
        Public Volume As Int64
    End Class

    Public Shared Function GetInstruments() As String
        Dim c As SqlCommand = GetSQLCommand("usp_GetInstruments")
        Dim Instruments As String = DataReaderToJSONString(c.ExecuteReader())
        c = GetSQLCommand("usp_GetHoldings")
        Dim Holdings As String = DataReaderToJSONString(c.ExecuteReader())
        c = GetSQLCommand("usp_GetHoldingsHistory")
        Dim HoldingsHistory As String = DataReaderToJSONString(c.ExecuteReader())
        c = GetSQLCommand("usp_GetAccounts")
        Dim Accounts As String = DataReaderToJSONString(c.ExecuteReader())
        GetInstruments = "{""Instruments"": " + Instruments + ", ""Holdings"": " + Holdings + ", ""HoldingsHistory"": " + HoldingsHistory + ", ""Accounts"": " + Accounts + "}"
        DisposeSQLCommand(c)
    End Function

    Public Shared Function AddInstrument(Symbol As String, FullName As String) As String
        Dim c As SqlCommand = GetSQLCommand("usp_InsertInstrument")
        c.Parameters.AddWithValue("Symbol", Symbol)
        c.Parameters.AddWithValue("FullName", FullName)
        AddInstrument = DataReaderToJSONString(c.ExecuteReader())
        DisposeSQLCommand(c)
    End Function

    Public Shared Sub UpdateInstrument(Symbol As String, GMTOffset As Integer, Currency As String, CurrentPrice As Double, InstrumentType As String, TradeDayStart As DateTime, TradeDayEnd As DateTime)
        '@Symbol varchar(8), @GMTOffset int, @Currency varchar(3), @CurrentPrice money, @InstrumentType varchar(10)
        Dim c As SqlCommand = GetSQLCommand("usp_UpdateInstrument")
        c.Parameters.AddWithValue("Symbol", Symbol)
        c.Parameters.AddWithValue("GMTOffset", GMTOffset)
        c.Parameters.AddWithValue("Currency", Currency)
        c.Parameters.AddWithValue("CurrentPrice", CurrentPrice)
        c.Parameters.AddWithValue("InstrumentType", InstrumentType)
        c.Parameters.AddWithValue("TradeDayStart", TradeDayStart)
        c.Parameters.AddWithValue("TradeDayEnd", TradeDayEnd)
        c.ExecuteNonQuery()
        DisposeSQLCommand(c)
    End Sub

    Public Shared Function AddHolding(AccountName As String, Symbol As String, NoUnits As Double, PurchasePricePerUnit As Double, PurchaseDate As Int64, PurchaseCurrency As String, BookCostInPurchaseCurrency As Double) As String
        Dim c As SqlCommand = GetSQLCommand("usp_InsertHolding")
        c.Parameters.AddWithValue("Account", AccountName)
        c.Parameters.AddWithValue("Symbol", Symbol)
        c.Parameters.AddWithValue("NoUnits", NoUnits)
        c.Parameters.AddWithValue("PurchasePricePerUnit", PurchasePricePerUnit)
        c.Parameters.AddWithValue("PurchaseDate", FromEpochTime(PurchaseDate))
        c.Parameters.AddWithValue("PurchaseCurrency", PurchaseCurrency)
        c.Parameters.AddWithValue("BookCostInPurchaseCurrency", BookCostInPurchaseCurrency)
        AddHolding = DataReaderToJSONString(c.ExecuteReader())
        DisposeSQLCommand(c)
    End Function

    Public Shared Function GetDailyData(Symbol As String, StartDate As DateTime, EndDate As DateTime) As String
        Dim c As SqlCommand = GetSQLCommand("usp_GetDailyData")
        c.Parameters.AddWithValue("Symbol", Symbol)
        c.Parameters.AddWithValue("StartDate", StartDate)
        c.Parameters.AddWithValue("EndDate", EndDate)
        GetDailyData = DataReaderToJSONString(c.ExecuteReader())
        DisposeSQLCommand(c)
    End Function

    Public Shared Function GetAllDailyData(StartDate As DateTime, EndDate As DateTime) As String
        Dim result As String = ""
        Dim s As SqlCommand = GetSQLCommand("usp_GetInstruments")
        Dim r As SqlDataReader = s.ExecuteReader
        While r.Read
            result += ",{ ""Symbol"": """ + r("Symbol") + """, ""DailyData"": "

            Dim c As SqlCommand = GetSQLCommand("usp_GetDailyData")
            c.Parameters.AddWithValue("Symbol", r("Symbol"))
            c.Parameters.AddWithValue("StartDate", StartDate)
            c.Parameters.AddWithValue("EndDate", EndDate)
            Dim dd As String = DataReaderToJSONString(c.ExecuteReader())
            If dd = "" Then dd = "[]"
            result += dd + "}"
            DisposeSQLCommand(c)
        End While
        DisposeSQLCommand(s)
        result = "[" + result.Substring(1) + "]"
        Return result
    End Function

    Public Shared Function GetIntradayData(Symbol As String, StartDate As DateTime, EndDate As DateTime) As String
        Dim c As SqlCommand = GetSQLCommand("usp_GetIntradayData")
        c.Parameters.AddWithValue("Symbol", Symbol)
        c.Parameters.AddWithValue("StartDate", StartDate)
        c.Parameters.AddWithValue("EndDate", EndDate)
        GetIntradayData = DataReaderToJSONString(c.ExecuteReader())
        DisposeSQLCommand(c)
    End Function

    Public Shared Function GetAllIntradayData(StartDate As DateTime, EndDate As DateTime) As String
        Dim result As String = ""
        Dim s As SqlCommand = GetSQLCommand("usp_GetInstruments")
        Dim r As SqlDataReader = s.ExecuteReader
        While r.Read
            result += ",{ ""Symbol"": """ + r("Symbol") + """, ""IntradayData"": "

            Dim c As SqlCommand = GetSQLCommand("usp_GetIntradayData")
            c.Parameters.AddWithValue("Symbol", r("Symbol"))
            c.Parameters.AddWithValue("StartDate", StartDate)
            c.Parameters.AddWithValue("EndDate", EndDate)
            Dim id As String = DataReaderToJSONString(c.ExecuteReader())
            If id = "" Then id = "[]"
            result += id + "}"
            DisposeSQLCommand(c)
        End While
        DisposeSQLCommand(s)
        result = "[" + result.Substring(1) + "]"
        Return result
    End Function

    Public Shared Function InsertDailyData(Symbol As String, DailyPrices As List(Of PriceData)) As String
        Dim dt As New DataTable("DailyPrices")
        dt.Columns.Add(New DataColumn("PriceDT", System.Type.GetType("System.DateTime")))
        dt.Columns.Add(New DataColumn("OpenPrice", System.Type.GetType("System.Double")))
        dt.Columns.Add(New DataColumn("HighPrice", System.Type.GetType("System.Double")))
        dt.Columns.Add(New DataColumn("LowPrice", System.Type.GetType("System.Double")))
        dt.Columns.Add(New DataColumn("ClosePrice", System.Type.GetType("System.Double")))
        dt.Columns.Add(New DataColumn("Volume", System.Type.GetType("System.Int64")))
        For Each p As PriceData In DailyPrices
            Dim d As DateTime = FromEpochTime(p.DT)
            If d < New DateTime(1980, 1, 1) Or d > Now() Then
                Debug.Print("Bad date: " + d)
            Else
                dt.Rows.Add(FromEpochTime(p.DT), p.Open, p.High, p.Low, p.Close, p.Volume)
            End If
        Next

        Dim c As SqlCommand = GetSQLCommand("usp_InsertDailyData")
        c.Parameters.AddWithValue("Symbol", Symbol)
        c.Parameters.AddWithValue("PriceData", dt)
        Try
            InsertDailyData = DataReaderToJSONString(c.ExecuteReader())
        Catch ex As Exception
            InsertDailyData = "{""ErrorMSG"":'" + ex.ToString + "'}"
        End Try
        DisposeSQLCommand(c)
    End Function

    Public Shared Function InsertIntradayData(Symbol As String, DailyPrices As List(Of PriceData)) As String
        Dim dt As New DataTable("IntradayPrices")
        dt.Columns.Add(New DataColumn("PriceDT", System.Type.GetType("System.DateTime")))
        dt.Columns.Add(New DataColumn("OpenPrice", System.Type.GetType("System.Double")))
        dt.Columns.Add(New DataColumn("HighPrice", System.Type.GetType("System.Double")))
        dt.Columns.Add(New DataColumn("LowPrice", System.Type.GetType("System.Double")))
        dt.Columns.Add(New DataColumn("ClosePrice", System.Type.GetType("System.Double")))
        dt.Columns.Add(New DataColumn("Volume", System.Type.GetType("System.Int64")))
        For Each p As PriceData In DailyPrices
            Dim d As DateTime = FromEpochTime(p.DT)
            If d < New DateTime(1980, 1, 1) Or d > Now() Then
                Debug.Print("Bad date: " + d)
            Else
                dt.Rows.Add(FromEpochTime(p.DT), p.Open, p.High, p.Low, p.Close, p.Volume)
            End If
        Next

        Dim c As SqlCommand = GetSQLCommand("usp_InsertIntradayData")
        c.Parameters.AddWithValue("Symbol", Symbol)
        c.Parameters.AddWithValue("PriceData", dt)
        Try
            InsertIntradayData = DataReaderToJSONString(c.ExecuteReader())
        Catch ex As Exception
            InsertIntradayData = "{""ErrorMSG"":'" + ex.ToString + "'}"
        End Try
        DisposeSQLCommand(c)
    End Function

    'Public Shared Function DeleteHolding(HoldingID) As String
    '    Dim c As SqlCommand = GetSQLCommand("usp_DeleteHolding")
    '    c.Parameters.AddWithValue("HoldingID", HoldingID)
    '    DeleteHolding = DataReaderToJSONString(c.ExecuteReader())
    '    DisposeSQLCommand(c)
    'End Function
    Public Shared Function SoldHolding(HoldingID As Integer, SoldDate As DateTime, SoldCurrency As String, SoldProceeds As Double) As String
        Dim c As SqlCommand = GetSQLCommand("usp_SoldHolding")
        c.Parameters.AddWithValue("HoldingID", HoldingID)
        c.Parameters.AddWithValue("SoldDate", SoldDate)
        c.Parameters.AddWithValue("SoldCurrency", SoldCurrency)
        c.Parameters.AddWithValue("SoldProceeds", SoldProceeds)
        SoldHolding = DataReaderToJSONString(c.ExecuteReader())
        DisposeSQLCommand(c)
    End Function

    Public Shared Function SetAccountCashValue(AccountName As String, Currency As String, Value As Double) As String
        Dim c As SqlCommand = GetSQLCommand("usp_SetAccountCashValue")
        c.Parameters.AddWithValue("AccountName", AccountName)
        c.Parameters.AddWithValue("Currency", Currency)
        c.Parameters.AddWithValue("Value", Value)
        SetAccountCashValue = DataReaderToJSONString(c.ExecuteReader())
        DisposeSQLCommand(c)
    End Function

    Public Shared Function SwapInstrumentDisplayOrders(Symbol1 As String, Symbol2 As String) As String
        Dim c As SqlCommand = GetSQLCommand("usp_SwapDisplayOrder")
        c.Parameters.AddWithValue("Symbol1", Symbol1)
        c.Parameters.AddWithValue("Symbol2", Symbol2)
        SwapInstrumentDisplayOrders = DataReaderToJSONString(c.ExecuteReader())
        DisposeSQLCommand(c)
    End Function

    Public Shared Function SetTotalHoldingsValues(TotalValue As Double) As String
        Dim c As SqlCommand = GetSQLCommand("usp_SetTotalHoldingsValue")
        c.Parameters.AddWithValue("TotalValueGBP", TotalValue)
        SetTotalHoldingsValues = DataReaderToJSONString(c.ExecuteReader())
        DisposeSQLCommand(c)
    End Function

    Public Shared Function GetTotalHoldingsHistory() As String
        Dim c As SqlCommand = GetSQLCommand("usp_GetTotalHoldingsHistory")
        GetTotalHoldingsHistory = DataReaderToJSONString(c.ExecuteReader())
        DisposeSQLCommand(c)
    End Function

    Private Shared Function GetSQLConnection() As SqlConnection
        'Dim c As New SqlConnection("Server=OZHOST1\SQL2008;Database=SharePrices;Trusted_Connection=True;Application Name=Share Prices Web;")
        Dim c As New SqlConnection("Server=WinSrv1\INSTANCE1;Database=SharePrices;Trusted_Connection=True;Application Name=Share Prices Web;")
        c.Open()
        Return c
    End Function

    Private Shared Function GetSQLCommand(StoredProcedureName As String) As SqlCommand
        Dim c As New SqlCommand(StoredProcedureName, GetSQLConnection())
        c.CommandType = Data.CommandType.StoredProcedure
        Return c
    End Function

    Private Shared Sub DisposeSQLCommand(c As SqlCommand)
        c.Connection.Close()
        c.Connection.Dispose()
        c.Dispose()
    End Sub

    Private Shared Function DataReaderToJSONString(dr As SqlDataReader) As String
        Dim fieldNo As Integer
        Dim noRows As Integer = 0
        Dim result As String = ""
        Dim thisRow As String
        While dr.Read
            noRows += 1
            thisRow = ""
            For fieldNo = 0 To dr.FieldCount - 1
                'Debug.Print("  Field " + fieldNo.ToString + "(" + dr.GetName(fieldNo) + "): " + dr.GetDataTypeName(fieldNo))
                thisRow += ",""" + dr.GetName(fieldNo) + """:"
                If IsDBNull(dr(fieldNo)) Then
                    thisRow += "null"
                Else
                    Select Case dr.GetDataTypeName(fieldNo).ToUpper
                        Case "CHAR", "VARCHAR" : thisRow += """" + dr(fieldNo) + """"
                        Case "DATETIME", "SMALLDATETIME", "DATETIME2", "DATE" : thisRow += ToEpochTime(dr(fieldNo)).ToString()
                        Case Else : thisRow += dr(fieldNo).ToString()
                    End Select
                End If
            Next
            result += "," + "{" + thisRow.Substring(1) + "}"
        End While
        If result <> "" Then result = result.Substring(1)
        If noRows > 1 Then result = "[" + result + "]"
        'Debug.Print("    DataReaderToJSONString Result: " + result)
        Return result
    End Function
End Class
