Imports System
Imports System.ComponentModel
Imports System.Collections.Generic
Imports System.Text
Imports System.Web
Imports System.Web.UI
Imports System.Web.UI.WebControls

''' <summary>
''' <para>This validator checks number of items checked in checked list box.</para>
''' <para>This is a dirrect conversion form the C# code avilable at <a href="http://aspnet.4guysfromrolla.com/articles/092006-1.aspx">4GuysFromRolla</a>.</para>
''' <para>Plus, added one more property for maximum number of selected items. If it is less than zero then it will not check for it.</para>
''' <para>NOTE: assign control to validate using code or you will have to type the name in ControlToValidate property. The check boxes lists do no appear in the drop down list.</para>
''' </summary>
''' <remarks>Thnaks to 4GuysFromRolla.</remarks>
Public Class CheckBoxListValidator
    Inherits BaseValidator

    ''' <summary>
    ''' Gets or sets the minimum number of selected check boxes.
    ''' </summary>
    ''' <value>The minimum number of selected check boxes.</value>
    <Description("The minimum number of CheckBoxes that must be checked to be considered valid."), Category("Behavior")> _
    Public Property MinimumNumberOfSelectedCheckBoxes() As Integer
        Get
            Dim o As Object = ViewState("MinimumNumberOfSelectedCheckBoxes")
            If o Is Nothing Then
                Return 1
            Else
                Return CInt(o)
            End If
        End Get
        Set(ByVal value As Integer)
            ViewState("MinimumNumberOfSelectedCheckBoxes") = value
        End Set
    End Property

    ''' <summary>
    ''' Gets or sets the maximum number of selected check boxes.
    ''' </summary>
    ''' <value>The maximum number of selected check boxes.</value>
    <Description("The maximum number of CheckBoxes that must be checked to be considered valid.")> _
    <Category("Behavior"), DefaultValue(-1)> _
    Public Property MaximumNumberOfSelectedCheckBoxes() As Integer
        Get
            Dim o As Object = ViewState("MaximumNumberOfSelectedCheckBoxes")
            If o Is Nothing Then
                Return -1
            Else
                Return CInt(o)
            End If
        End Get
        Set(ByVal value As Integer)
            ViewState("MaximumNumberOfSelectedCheckBoxes") = value
        End Set
    End Property

    Private _ctrlToValidate As CheckBoxList = Nothing
    Protected ReadOnly Property CheckBoxListToValidate() As CheckBoxList
        Get
            If _ctrlToValidate Is Nothing Then
                _ctrlToValidate = TryCast(FindControl(Me.ControlToValidate), CheckBoxList)
            End If

            Return _ctrlToValidate
        End Get
    End Property

    Protected Overrides Function ControlPropertiesValid() As Boolean
        ' Make sure ControlToValidate is set 
        If Me.ControlToValidate.Length = 0 Then
            Throw New HttpException(String.Format("The ControlToValidate property of '{0}' cannot be blank.", Me.ID))
        End If

        ' Ensure that the control being validated is a CheckBoxList 
        If CheckBoxListToValidate Is Nothing Then
            Throw New HttpException(String.Format("The CheckBoxListValidator can only validate controls of type CheckBoxList."))
        End If

        ' ... and that it has at least MinimumNumberOfSelectedCheckBoxes ListItems 
        If CheckBoxListToValidate.Items.Count < MinimumNumberOfSelectedCheckBoxes Then
            Throw New HttpException(String.Format("MinimumNumberOfSelectedCheckBoxes must be set to a value greater than or equal to the number of ListItems; MinimumNumberOfSelectedCheckBoxes is set to {0}, but there are only {1} ListItems in '{2}'", MinimumNumberOfSelectedCheckBoxes, CheckBoxListToValidate.Items.Count, CheckBoxListToValidate.ID))
        End If

        Return True
        ' if we reach here, everything checks out 
    End Function

    Protected Overrides Function EvaluateIsValid() As Boolean
        ' Make sure that the CheckBoxList has at least MinimumNumberOfSelectedCheckBoxes ListItems selected 
        Dim selectedItemCount As Integer = 0
        Dim valid As Boolean = False
        For Each cb As ListItem In CheckBoxListToValidate.Items
            If cb.Selected Then
                selectedItemCount += 1
            End If
        Next

        valid = (selectedItemCount >= MinimumNumberOfSelectedCheckBoxes) AndAlso (MaximumNumberOfSelectedCheckBoxes < 0 OrElse selectedItemCount <= MaximumNumberOfSelectedCheckBoxes)
        Return valid
    End Function

    Protected Overrides Sub AddAttributesToRender(ByVal writer As HtmlTextWriter)
        MyBase.AddAttributesToRender(writer)

        ' Add the client-side code (if needed) 
        If Me.RenderUplevel Then
            ' Indicate the mustBeChecked value and the client-side function to used for evaluation 
            ' Use AddAttribute if Helpers.EnableLegacyRendering is true; otherwise, use expando attributes 
            If Helpers.EnableLegacyRendering() Then
                writer.AddAttribute("evaluationfunction", "CheckBoxListValidatorEvaluateIsValid", False)
                writer.AddAttribute("minimumNumberOfSelectedCheckBoxes", MinimumNumberOfSelectedCheckBoxes.ToString(), False)
                writer.AddAttribute("maximumNumberOfSelectedCheckBoxes", MaximumNumberOfSelectedCheckBoxes.ToString(), False)
            Else
                Me.Page.ClientScript.RegisterExpandoAttribute(Me.ClientID, "evaluationfunction", "CheckBoxListValidatorEvaluateIsValid", False)
                Me.Page.ClientScript.RegisterExpandoAttribute(Me.ClientID, "minimumNumberOfSelectedCheckBoxes", MinimumNumberOfSelectedCheckBoxes.ToString(), False)
                Me.Page.ClientScript.RegisterExpandoAttribute(Me.ClientID, "maximumNumberOfSelectedCheckBoxes", MaximumNumberOfSelectedCheckBoxes.ToString(), False)
            End If
        End If
    End Sub

    Protected Overrides Sub OnPreRender(ByVal e As EventArgs)
        MyBase.OnPreRender(e)

        ' Register the client-side function using WebResource.axd (if needed) 
        ' see: http://aspnet.4guysfromrolla.com/articles/080906-1.aspx 
        If Me.RenderUplevel AndAlso Me.Page IsNot Nothing AndAlso Not Me.Page.ClientScript.IsClientScriptIncludeRegistered(Me.GetType, "skmValidators") Then
            Me.Page.ClientScript.RegisterClientScriptInclude(Me.GetType, "skmValidators", Me.Page.ClientScript.GetWebResourceUrl(Me.GetType, "Mitul.Web.skmValidators.js"))
        End If
    End Sub

End Class
