Imports System.Collections.Generic
Imports CharterDotCom.CommonEntities.Library.Enumerations
Imports System.Web

<Serializable()> _
Public Class BLShoppingCart
    Implements ICart

    'Public Delegate Sub Notify(ByVal n As ICart.INotification) 

    Private m_cartItems As Dictionary(Of String, ICartItem)
    Private m_oneTimeTotal As Decimal
    Private m_oneTimeCharges As Dictionary(Of String, Decimal)
    Public m_undo As Boolean = False
    Private m_submitted As Boolean

    Public Sub New()
        m_cartItems = New Dictionary(Of String, ICartItem)
        ' m_message = New Notification()
        m_submitted = False
        m_oneTimeTotal = 0
    End Sub

    Public ReadOnly Property CartItems() As Dictionary(Of String, ICartItem) Implements ICart.CartItems
        Get
            Return m_cartItems
        End Get
    End Property

    Public ReadOnly Property CanUndo() As Boolean Implements ICart.CanUndo
        Get
            Return m_undo
        End Get
    End Property

    Public ReadOnly Property MonthlyTotal() As Decimal Implements ICart.MonthlyTotal
        Get
            Dim m_monthlyTotal As Decimal = 0
            Try
                For Each item As ICartItem In m_cartItems.Values
                    If item.Type = ItemType.Bundle Then
                        Dim b As BLBundle = DirectCast(item, BLBundle)
                        'b.Price = 0
                        m_monthlyTotal += b.Price
                        For Each sp As BLServicePlan In item.Children.Values
                            '  sp.Price = sp.ListPrice
                            m_monthlyTotal += TotalServicePlanPrice(sp)
                            'b.Price += sp.Price
                        Next
                    Else
                        ' service plan
                        Dim sp As BLServicePlan = DirectCast(item, BLServicePlan)
                        ' sp.Price = sp.ListPrice
                        m_monthlyTotal += sp.Price
                        m_monthlyTotal += TotalServicePlanPrice(sp)
                    End If
                Next
                Return m_monthlyTotal
            Catch ex As Exception
                Throw ex
            End Try
        End Get
    End Property

    Public ReadOnly Property OneTimeTotal() As Decimal Implements ICart.OneTimeTotal
        Get
            m_oneTimeCharges = GetOneTimeChargeItems()
            Return m_oneTimeTotal
        End Get
    End Property

    Public ReadOnly Property GrandTotal() As Decimal Implements ICart.GrandTotal
        Get
            Return MonthlyTotal + OneTimeTotal
        End Get
    End Property

    Public ReadOnly Property OneTimeChargeItems() As Dictionary(Of String, Decimal) Implements ICart.OneTimeChargeItems
        Get
            Return m_oneTimeCharges
        End Get
    End Property

    Private Function GetOneTimeChargeItems() As Dictionary(Of String, Decimal)
        Dim list As New Dictionary(Of String, Decimal)
        m_oneTimeTotal = 0
        Try
            If Not (m_cartItems Is Nothing OrElse m_cartItems.Count = 0) Then
                For Each item As ICartItem In m_cartItems.Values
                    ' add installation price
                    If Not item.InstallPrice = 0 Then
                        m_oneTimeTotal += item.InstallPrice
                        list.Add(item.InstallDescription, item.InstallPrice)
                    End If

                    If item.Type = ItemType.Bundle Then
                        For Each sp As BLServicePlan In item.Children.Values
                            CalculateOneTimeCharge(sp, list)
                        Next
                    Else ' service plan
                        Dim sp As BLServicePlan = DirectCast(item, BLServicePlan)
                        CalculateOneTimeCharge(sp, list)
                    End If
                Next
            End If
            Return list
        Catch ex As Exception
            Throw ex
        End Try
    End Function

    Public ReadOnly Property Submitted() As Boolean Implements ICart.Submitted
        Get
            Return m_submitted
        End Get
    End Property

    Public Property OrderSubmitted() As Boolean
        Get
            Return m_submitted
        End Get
        Set(ByVal value As Boolean)
            m_submitted = value
        End Set
    End Property

    ' calculates one time charge for a serviceplan 
    Private Sub CalculateOneTimeCharge(ByVal sp As BLServicePlan, ByVal list As Dictionary(Of String, Decimal))
        Try
            For Each f As BLFeature In sp.Features.Values
                If f.ISSelected Then
                    If f.Choices.Count > 0 Then
                        For Each c As BLFeature In f.Choices.Values
                            If c.ISSelected AndAlso c.PriceFrequency = PriceFrequency.OneTime Then
                                '10/1/2007 Brad Miller - add check for duplicate key values
                                If Not list.ContainsKey(c.Name) Then
                                    list.Add(c.Name, c.Price)
                                    m_oneTimeTotal += c.Price
                                End If
                            End If
                        Next
                    ElseIf f.PriceFrequency = PriceFrequency.OneTime Then
                        '10/1/2007 Brad Miller - add check for duplicate key values
                        If Not list.ContainsKey(f.Name) Then
                            list.Add(f.Name, (f.Price * f.QuantitySelected))
                            m_oneTimeTotal += (f.Price * f.QuantitySelected)
                        End If
                    End If
                End If
            Next
        Catch ex As Exception
            Throw New ApplicationException("Cannot calculate One time charges", ex)
        End Try
    End Sub

    Private Function TotalServicePlanPrice(ByVal sp As BLServicePlan) As Decimal
        Dim price As Decimal = 0
        For Each f As BLFeature In sp.Features.Values
            If f.Choices Is Nothing OrElse f.Choices.Count = 0 Then
                If f.ISSelected AndAlso Not f.FeatureType = FeatureType.IsIncluded Then
                    If f.InputType = InputType.Number Then
                        If f.PriceFrequency = BLPriceFrequency.Monthly Then
                            price = price + (f.Price * f.QuantitySelected)
                        End If
                    Else
                        price += f.Price
                    End If

                End If
            Else
                For Each c As BLFeature In f.Choices.Values
                    If c.ISSelected AndAlso Not c.PriceFrequency = PriceFrequency.OneTime Then
                        If c.FeatureType = FeatureType.IsCustomization Then
                            price += c.Price
                        Else
                            If c.FeatureType = FeatureType.IsPlaceholder Then
                                Select Case c.FeatureCategory
                                    Case FeatureCategory.DataEquipment, FeatureCategory.Installation, FeatureCategory.VideoEquipment, FeatureCategory.VoiceEquipment
                                        price += c.Price
                                End Select
                                If c.ID = CStr(HttpContext.Current.Application(Common.m_TOTALVIEWID)) Or c.ID = CStr(HttpContext.Current.Application(Common.m_DIGITALVIEWID)) Then
                                    price += c.Price
                                End If
                            End If
                        End If
                    End If
                Next
            End If
        Next
        Return price
    End Function

    ' this is the notification as a result of an action on cart
    'Public ReadOnly Property Message() As ICart.INotification Implements ICart.Message
    '  Get
    '    If m_message.ResultCode = String.Empty OrElse m_message.ResultItem = String.Empty Then
    '      ClearMessage()
    '    End If
    '    Return m_message
    '  End Get
    'End Property

    Public Sub AddCartItem(ByVal item As ICartItem)
        If m_cartItems Is Nothing Then
            m_cartItems = New Dictionary(Of String, ICartItem)
        End If
        If Not ContainsThisKey(item.ID) Then
            If item.Type = ItemType.Bundle Then
                Dim bundle As BLBundle = DirectCast(item, BLBundle)
                bundle.IsSelected = True
                bundle.IsAvailable = False
                Dim b As ICartItem = bundle
                m_cartItems.Add(item.ID, b)
            ElseIf item.Type = ItemType.ServicePlan Then
                Dim sp As BLServicePlan = DirectCast(item, BLServicePlan)
                sp.IsSelected = True
                sp.IsAvailable = False
                m_cartItems.Add(item.ID, sp)
            End If
        End If
    End Sub

    Public Sub RemoveCartItem(ByVal ID As String)
        m_cartItems.Remove(ID)
    End Sub

    Public Function FindPlaceholder(ByVal ID As String) As BLFeature
        Try
            For Each item As ICartItem In m_cartItems.Values
                If item.Type = ItemType.Bundle Then
                    For Each sp As BLServicePlan In item.Children.Values
                        For Each f As BLFeature In sp.Features.Values
                            For Each c As BLFeature In f.Choices.Values
                                If c.ID = ID Then Return f
                            Next
                        Next
                    Next
                Else
                    If item.Type = ItemType.ServicePlan Then
                        For Each f As BLFeature In item.Children.Values
                            For Each c As BLFeature In f.Choices.Values
                                If c.ID = ID Then Return f
                            Next
                        Next
                    End If
                End If
            Next
            Return Nothing
        Catch ex As Exception
            Throw New ApplicationException("Error finding customization for the give choice", ex)
        End Try
    End Function

    Public Function ContainsThisKey(ByVal ID As String) As Boolean
        For Each ci As ICartItem In m_cartItems.Values
            If ci.ID = ID Then
                Return True
            Else
                For Each si As ISubCartItem In ci.Children.Values
                    If si.ID = ID Then Return True
                Next
            End If
        Next
        Return False
    End Function

    Public Function ContainsThisFeature(ByVal ID As String) As BLFeature
        Try
            For Each ci As ICartItem In m_cartItems.Values
                If ci.Type = ItemType.Bundle Then
                    For Each sp As ISubCartItem In ci.Children.Values
                        For Each f As BLFeature In sp.Children.Values
                            If Not f.Choices Is Nothing AndAlso f.Choices.Count > 0 Then
                                For Each choice As BLFeature In f.Choices.Values
                                    If choice.ID = ID Then
                                        Return choice
                                    End If
                                Next
                            Else
                                If f.ID = ID Then
                                    Return f
                                End If
                            End If
                        Next
                    Next

                Else
                    ' service plan
                    For Each f As BLFeature In ci.Children.Values
                        If Not f.Choices Is Nothing AndAlso f.Choices.Count > 0 Then
                            For Each choice As BLFeature In f.Choices.Values
                                If choice.ID = ID Then
                                    Return choice
                                End If
                            Next
                        Else
                            If f.ID = ID Then
                                Return f
                            End If
                        End If
                    Next
                End If
            Next
            Return Nothing
        Catch ex As Exception
            Throw New ApplicationException("Error finding the feature in cart", ex)
        End Try
    End Function

    Public Function GetParentFeature(ByVal ID As String, Optional ByVal parentid As String = Nothing) As ISubCartItem
        Try
            For Each ci As ICartItem In m_cartItems.Values
                If ci.Type = ItemType.Bundle Then
                    For Each sp As ISubCartItem In ci.Children.Values
                        For Each si As ISubCartItem In sp.Children.Values
                            If Not si.Children Is Nothing AndAlso si.Children.Count > 0 Then
                                For Each choice As ISubCartItem In si.Children.Values
                                    If choice.ID = ID Then
                                        If parentid IsNot Nothing Then
                                            If si.ID = parentid Then
                                                Return si
                                            End If
                                        Else
                                            Return si
                                        End If
                                    End If
                                Next
                            Else
                                If si.ID = ID Then
                                    Return si
                                End If
                            End If
                        Next
                    Next

                Else
                    For Each si As ISubCartItem In ci.Children.Values
                        If Not si.Children Is Nothing AndAlso si.Children.Count > 0 Then
                            For Each choice As ISubCartItem In si.Children.Values
                                If choice.ID = ID Then
                                    If parentid IsNot Nothing Then
                                        If si.ID = parentid Then
                                            Return si
                                        End If
                                    Else
                                        Return si
                                    End If
                                End If
                            Next
                        Else
                            If si.ID = ID Then
                                Return si
                            End If
                        End If
                    Next
                End If
            Next
            Return Nothing
        Catch ex As Exception
            Throw New ApplicationException("Error finding Customization for the given choice", ex)
        End Try
    End Function

    ' updates bundles and service plans prices by adding placeholder selection price
    Public Sub UpdateCartItemsPrice()
        'Try
        '  For Each item As ICartItem In m_cartItems.Values
        '    If item.Type = ItemType.Bundle Then
        '      Dim b As BLBundle = DirectCast(item, BLBundle)
        '      b.Price = 0
        '      For Each sp As BLServicePlan In item.Children.Values
        '        sp.Price = sp.ListPrice
        '        UpdateServicePlanPrice(sp)
        '        b.Price += sp.Price
        '      Next
        '    Else
        '      ' service plan
        '      Dim sp As BLServicePlan = DirectCast(item, BLServicePlan)
        '      sp.Price = sp.ListPrice
        '      UpdateServicePlanPrice(sp)
        '    End If
        '  Next
        'Catch ex As Exception
        '  Throw New ApplicationException("Cannot calculate cart price", ex)
        'End Try
    End Sub

    'Private Sub UpdateServicePlanPrice(ByVal sp As BLServicePlan)
    '  For Each f As BLFeature In sp.Features.Values
    '    If f.Choices Is Nothing AndAlso f.Choices.Count = 0 Then
    '      If f.ISSelected AndAlso f.FeatureType = FeatureType.IsCustomization Then sp.Price += f.Price
    '    Else
    '      For Each c As BLFeature In f.Choices.Values
    '        If c.ISSelected AndAlso Not c.PriceFrequency = PriceFrequency.OneTime Then
    '          If c.FeatureType = FeatureType.IsCustomization Then
    '            sp.Price += c.Price
    '          Else
    '            If c.FeatureType = FeatureType.IsPlaceholder Then
    '              Select Case c.FeatureCategory
    '                Case FeatureCategory.DataEquipment, FeatureCategory.Installation, FeatureCategory.VideoEquipment, FeatureCategory.VoiceEquipment
    '                  sp.Price += c.Price
    '              End Select
    '            End If
    '          End If
    '        End If
    '      Next
    '    End If
    '  Next
    'End Sub

    ' as of now, this method should be used only to get category for a service plan
    Public Function GetCartItemCategory(ByVal id As String) As Category
        Try
            For Each ci As ICartItem In m_cartItems.Values
                If ci.Type = ItemType.Bundle Then
                    If ci.ID = id Then Return Category.UnSpecified
                    For Each sp As ISubCartItem In ci.Children.Values
                        If sp.ID = id Then Return sp.Category
                    Next
                Else
                    If ci.ID = id Then Return ci.Category
                End If
            Next
            Return Nothing
        Catch ex As Exception
            Throw New ApplicationException("Cannot find item Category", ex)
        End Try
    End Function

    ' clears the cart
    Public Sub Clear()
        m_cartItems.Clear()
        m_undo = False
        m_oneTimeTotal = 0
    End Sub

End Class

<Serializable()> _
Public Structure CartSelections

    Private m_category As Category
    Private m_fType As FeatureType

    Public Property Category() As Category
        Get
            Return m_category
        End Get
        Set(ByVal value As Category)
            m_category = value
        End Set
    End Property

    Public Property FeatureType() As FeatureType
        Get
            Return m_fType
        End Get
        Set(ByVal value As FeatureType)
            m_fType = value
        End Set
    End Property

End Structure
