Imports System
Imports System.Collections
Imports System.Data
Imports System.Text
Imports System.Web.UI.WebControls
Imports ASPNET.StarterKit.TimeTracker.BusinessLogicLayer

Namespace ASPNET.StarterKit.TimeTracker.Web

    '*********************************************************
    '
    ' Main page of the Application, for users to enter time entries.
    '
    '*********************************************************

    Public Class TimeEntry
        Inherits System.Web.UI.Page
        'Use Time Entry component to capture user's input during edit mode
        Protected _userInput As New BusinessLogicLayer.TimeEntry(0, 0, 0, 0, DateTime.MinValue, Nothing, -1D)
        Protected _dayListTable As DataTable = Nothing

        Protected WithEvents AddEntry As System.Web.UI.WebControls.Button
        Protected CompareValidator1 As System.Web.UI.WebControls.CompareValidator
        Protected WithEvents Cancel As System.Web.UI.WebControls.Button
        Protected CategoryList As System.Web.UI.WebControls.DropDownList
        Protected Days As System.Web.UI.WebControls.DropDownList
        Protected Description As System.Web.UI.WebControls.TextBox
        Protected Hours As System.Web.UI.WebControls.TextBox
        Protected WithEvents ProjectList As System.Web.UI.WebControls.DropDownList
        Protected RangeValidator1 As System.Web.UI.WebControls.RangeValidator
        Protected Requiredfieldvalidator1 As System.Web.UI.WebControls.RequiredFieldValidator
        Protected RequiredFieldValidator2 As System.Web.UI.WebControls.RequiredFieldValidator
        Protected WithEvents TimeEntryGrid As System.Web.UI.WebControls.DataGrid
        Protected TimeGraph As System.Web.UI.WebControls.Image
        Protected WithEvents UserList As System.Web.UI.WebControls.DropDownList
        Protected WithEvents WeekEnding As System.Web.UI.WebControls.TextBox

        Private _user As TTUser
        Private _weekEndingDate As DateTime = DateTime.Today
        Private _weekStartingDate As DateTime = DateTime.Today

        '*******************************************************
        '
        ' The Page_Load server event handler on this page is used
        ' to populate information fields on this page
        '
        '*******************************************************

        Private Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles MyBase.Load
            _user = New TTUser(TTSecurity.GetUserID(), User.Identity.Name, TTSecurity.GetName(), TTSecurity.GetUserRole())

            If Not Page.IsPostBack Then
                ' If page is loaded for the first time, select the current week.
                BusinessLogicLayer.TimeEntry.FillCorrectStartEndDates(DateTime.Today, _weekStartingDate, _weekEndingDate)
                WeekEnding.Text = _weekEndingDate.ToShortDateString()

                BindUserList()
                BindEntryFields()
                BindTimeSheet(_user.UserID, _weekStartingDate, _weekEndingDate)
            Else
                ' Selects the weekending date, corresponding to week user selected.
                BusinessLogicLayer.TimeEntry.FillCorrectStartEndDates(Convert.ToDateTime(WeekEnding.Text), _weekStartingDate, _weekEndingDate)
                _dayListTable = BusinessLogicLayer.TimeEntry.GetWeek(Convert.ToDateTime(WeekEnding.Text))
            End If
        End Sub 'Page_Load

        '*******************************************************
        '
        ' BindCategoryList method databinds data to CategoryList dropdown.
        '
        '*******************************************************

        Private Sub BindCategoryList()
            If Not (ProjectList.SelectedItem Is Nothing) Then
                ' CategoryList is different for each project, Project.GetCategories gets a list of 
                ' categories based on the project.
                CategoryList.DataSource = Project.GetCategories(Convert.ToInt32(ProjectList.SelectedItem.Value))
                CategoryList.DataValueField = "CategoryID"
                CategoryList.DataTextField = "Abbreviation"
                CategoryList.DataBind()
            End If
        End Sub 'BindCategoryList

        '*******************************************************
        '
        ' BindDates method populates the DropDownList Days to show each day of the week
        '
        '*******************************************************

        Private Sub BindDates()
            _dayListTable = BusinessLogicLayer.TimeEntry.GetWeek(Convert.ToDateTime(WeekEnding.Text))
            Days.DataSource = _dayListTable
            Days.DataValueField = "Date"
            Days.DataTextField = "Day"
            Days.DataBind()
            Days.Items.FindByText(Convert.ToDateTime(DateTime.Today).ToString("ddd")).Selected = True
        End Sub 'BindDates

        '*******************************************************
        '
        ' BindEntryFields calls methods that populate the drop down lists with data.
        '
        '*******************************************************

        Private Sub BindEntryFields()
            BindDates()
            BindProjectList()
            BindCategoryList()
        End Sub 'BindEntryFields

        '*******************************************************
        '
        ' BindProjectList method populates the DropDownList ProjectList to show
        ' list of projects that belongs to the user.
        '
        '*******************************************************

        Private Sub BindProjectList()
            ' Preserve the selected value so information is still there after postback.
            If Not (ProjectList.SelectedItem Is Nothing) Then
                _userInput.ProjectID = Convert.ToInt32(ProjectList.SelectedItem.Value)
            End If
            ProjectList.DataSource = ListUserProjects()
            ProjectList.DataTextField = "Name"
            ProjectList.DataValueField = "ProjectID"
            ProjectList.DataBind()

            ' Select the correct item from ProjectList.
            If Not (ProjectList.Items.FindByValue(_userInput.ProjectID.ToString()) Is Nothing) Then
                ProjectList.Items.FindByValue(_userInput.ProjectID.ToString()).Selected = True
            End If
        End Sub 'BindProjectList

        '*******************************************************
        '
        ' An overload of BindTimeSheet method
        ' this is called when the logged on user in querying time entry about themself.
        '
        '*******************************************************

        Private Overloads Sub BindTimeSheet(ByVal userID As Integer, ByVal start As DateTime, ByVal [end] As DateTime)
            BindTimeSheet(userID, userID, start, [end])
        End Sub 'BindTimeSheet

        '*******************************************************
        '
        ' BindTimeSheet method databinds the TimeEntryGrid based on the user
        ' currently logged in and user which is being queried.
        '
        '*******************************************************

        Private Overloads Sub BindTimeSheet(ByVal queryUserID As Integer, ByVal userID As Integer, ByVal start As DateTime, ByVal [end] As DateTime)
            Dim entryList As TimeEntriesCollection = BusinessLogicLayer.TimeEntry.GetEntries(queryUserID, userID, start, [end])

            ' Sort datagrid if it is not empty.
            If Not (entryList Is Nothing) Then
                SortGridData(entryList, SortField, SortAscending)
            End If
            ' Draw time graph with new dataset.
            DrawTimeGraph(entryList, _dayListTable)

            TimeEntryGrid.DataSource = entryList
            TimeEntryGrid.DataBind()
        End Sub 'BindTimeSheet

        '*******************************************************
        '
        ' BindUserList method databinds a list of users to the UserList;
        ' This is based on the user currently logged in.
        '
        '*******************************************************

        Private Sub BindUserList()
            UserList.DataSource = TTUser.GetUsers(_user.UserID, _user.Role)
            UserList.DataBind()

            'Select User Drop Down to the correct value.
            UserList.Items.FindByValue(_user.UserID.ToString()).Selected = True
        End Sub 'BindUserList

        '*******************************************************
        '
        ' ClearEntryFields method clears all the entry fields on this page.
        '
        '*******************************************************

        Private Sub ClearEntryFields()
            BindEntryFields()

            ' Make sure that no items appear in edit mode in the TimeEntryGrid.
            TimeEntryGrid.EditItemIndex = -1

            BindTimeSheet(_user.UserID, Convert.ToInt32(UserList.SelectedItem.Value), _weekStartingDate, _weekEndingDate)
            Description.Text = String.Empty
            Hours.Text = String.Empty
        End Sub 'ClearEntryFields

        '*******************************************************
        '
        ' DrawTimeGraph method creates the bar graph on the fly.
        ' Binds accordingly to number hours in each day of the week.
        '
        '*******************************************************

        Private Sub DrawTimeGraph(ByVal chartData As TimeEntriesCollection, ByVal dtWeek As DataTable)
            ' Assume dtWeek is already in the correct order according to FirstDayOfWeek Setting.
            Dim htWeekSummary As New Hashtable(7) '7 days of data - key: EntryDate | value: Duration.
            ' x & y values holder
            Dim xValues As New StringBuilder()
            Dim yValues As New StringBuilder()

            'Initialize htWeekSummary to start with first day of week setting.
            Dim row As DataRow
            For Each row In dtWeek.Rows
                htWeekSummary.Add(Convert.ToDateTime(row("Date")).ToShortDateString(), 0D)
            Next row

            ' Summarize data from grid Group By Days of Week.
            Dim time As BusinessLogicLayer.TimeEntry
            For Each time In chartData
                Dim key As String = time.EntryDate.ToShortDateString()
                Dim dayDuration As [Decimal] = Convert.ToDecimal(htWeekSummary(key))
                dayDuration += time.Duration
                htWeekSummary(key) = dayDuration
            Next time

            'Build x & y values for graph.
            Dim index As Integer = 1
            Dim thisRow As DataRow
            For Each thisRow In dtWeek.Rows
                Dim key As String = Convert.ToDateTime(thisRow("Date")).ToShortDateString()
                Dim currentDay As String = Convert.ToDateTime(key).ToString("ddd")
                Dim currentHour As String = Convert.ToString(htWeekSummary(key))

                currentDay = currentDay.Replace("星期一", "Mon")
                currentDay = currentDay.Replace("星期二", "Tue")
                currentDay = currentDay.Replace("星期三", "Wed")
                currentDay = currentDay.Replace("星期四", "Thu")
                currentDay = currentDay.Replace("星期五", "Fri")
                currentDay = currentDay.Replace("星期六", "Sat")
                currentDay = currentDay.Replace("星期日", "Sun")
                xValues.Append(currentDay)
                yValues.Append(currentHour)

                'Don't append separator if this is the last item.
                If index <> dtWeek.Rows.Count Then
                    xValues.Append("|")
                    yValues.Append("|")
                End If
                index += 1
            Next thisRow

            'Attach image generator to image.
            TimeGraph.ImageUrl = "TimeEntryBarChart.aspx?" + "xValues=" + xValues.ToString() + "&yValues=" + yValues.ToString()
        End Sub 'DrawTimeGraph

        '*******************************************************
        '
        ' ListGridCategories method returns a List of categories based on the projectID.
        '
        '*******************************************************
        Protected Function ListGridCategories(ByVal projectID As Integer) As CategoriesCollection
            Return Project.GetCategories(projectID)
        End Function 'ListGridCategories

        '*******************************************************
        '
        ' ListUserProjects method returns a ArrayList of available projects.
        '
        '*******************************************************

        Protected Function ListUserProjects() As ProjectsCollection
            Return BusinessLogicLayer.Project.GetProjects(_user.UserID, Convert.ToInt32(UserList.SelectedItem.Value))
        End Function 'ListUserProjects

        '*******************************************************
        '
        ' SortGridData methods sorts the TimeEntryGrid based on which
        ' sort field is being selected.  Also does reverse sorting based on the boolean.
        '
        '*******************************************************

        Private Sub SortGridData(ByVal list As TimeEntriesCollection, ByVal sortField As String, ByVal asc As Boolean)
            Dim sortCol As TimeEntriesCollection.TimeEntryFields = TimeEntriesCollection.TimeEntryFields.InitValue

            Select Case sortField
                Case "EntryDate"
                    sortCol = TimeEntriesCollection.TimeEntryFields.Day
                Case "ProjectName"
                    sortCol = TimeEntriesCollection.TimeEntryFields.Project
                Case "CategoryName"
                    sortCol = TimeEntriesCollection.TimeEntryFields.Category
                Case "Duration"
                    sortCol = TimeEntriesCollection.TimeEntryFields.Hours
                Case "Description"
                    sortCol = TimeEntriesCollection.TimeEntryFields.Description
                Case Else
            End Select

            list.Sort(sortCol, asc)
        End Sub 'SortGridData

        '*******************************************************
        '
        ' AddEntry_Click server event handler on this page is used to 
        ' saves a time entry and adds it to the system.
        '
        '*******************************************************

        Private Sub AddEntry_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles AddEntry.Click
            ' check validation.
            Requiredfieldvalidator1.Validate()
            RequiredFieldValidator2.Validate()
            RangeValidator1.Validate()
            CompareValidator1.Validate()

            ' proceeds if data is valid then create an obejct and save it.
            If Requiredfieldvalidator1.IsValid And RequiredFieldValidator2.IsValid And CompareValidator1.IsValid And RangeValidator1.IsValid Then
                Dim te As New BusinessLogicLayer.TimeEntry(0, Convert.ToInt32(UserList.SelectedItem.Value), Convert.ToInt32(ProjectList.SelectedItem.Value), Convert.ToInt32(CategoryList.SelectedItem.Value), Convert.ToDateTime(Days.SelectedItem.Value), TTSecurity.CleanStringRegex(Description.Text), Convert.ToDecimal(Hours.Text))
                te.Save()

                ClearEntryFields()
            End If
        End Sub 'AddEntry_Click

        '*******************************************************
        '
        ' Cancel_Click server event handler on this page is used to
        ' clear all entry fields on page.
        '
        '*******************************************************
        Private Sub Cancel_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Cancel.Click
            ClearEntryFields()
        End Sub 'Cancel_Click

        '*******************************************************
        '
        ' ProjectList_SelectedIndexChanged server event handler on this page is used to 
        ' update the CategoryList dropdown when a different project is selected
        '
        '*******************************************************

        Private Sub ProjectList_SelectedIndexChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ProjectList.SelectedIndexChanged
            BindCategoryList()
        End Sub 'ProjectList_SelectedIndexChanged

        '*******************************************************
        '
        ' TimeEntryGrid_Itembound server event handler on this page is used
        ' during TimeEntryGrid databind
        '
        '*******************************************************

        Private Sub TimeEntryGrid_Itembound(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.DataGridItemEventArgs) Handles TimeEntryGrid.ItemDataBound
            ' During in-line-editing mode this selects corresponding items for dropdowns and text boxes.
            ' The _userInput object is created in TimeEntryGrid_OnEdit().
            If e.Item.ItemType = ListItemType.EditItem Then
                Dim currentCbo As DropDownList = CType(e.Item.FindControl("EntryDays"), DropDownList)
                currentCbo.SelectedIndex = currentCbo.Items.IndexOf(currentCbo.Items.FindByText(_userInput.Day))

                currentCbo = CType(e.Item.FindControl("EntryProjects"), DropDownList)
                currentCbo.SelectedIndex = currentCbo.Items.IndexOf(currentCbo.Items.FindByText(_userInput.ProjectName))

                currentCbo = CType(e.Item.FindControl("EntryCategories"), DropDownList)
                currentCbo.SelectedIndex = currentCbo.Items.IndexOf(currentCbo.Items.FindByText(_userInput.CategoryName))
            End If
        End Sub 'TimeEntryGrid_Itembound

        '*******************************************************
        '
        ' TimeEntryGrid_OnCancel server event handler on this page is used to 
        ' quit in-line-editing mode. and Undo all changes
        '
        '*******************************************************

        Protected Sub TimeEntryGrid_OnCancel(ByVal sender As [Object], ByVal e As DataGridCommandEventArgs) Handles TimeEntryGrid.CancelCommand
            TimeEntryGrid.EditItemIndex = -1
            BindTimeSheet(_user.UserID, Convert.ToInt32(UserList.SelectedItem.Value), _weekStartingDate, _weekEndingDate)
        End Sub 'TimeEntryGrid_OnCancel

        '*******************************************************
        '
        ' TimeEntryGrid_OnDelete server event handler on this page is used to 
        ' delete a item from the database.
        '
        '*******************************************************

        Protected Sub TimeEntryGrid_OnDelete(ByVal sender As [Object], ByVal e As DataGridCommandEventArgs) Handles TimeEntryGrid.DeleteCommand
            Dim entryLogID As Integer = Convert.ToInt32(TimeEntryGrid.DataKeys(CInt(e.Item.ItemIndex)))
            BusinessLogicLayer.TimeEntry.Remove(entryLogID)
            BindTimeSheet(_user.UserID, Convert.ToInt32(UserList.SelectedItem.Value), _weekStartingDate, _weekEndingDate)
        End Sub 'TimeEntryGrid_OnDelete

        '*******************************************************
        '
        ' TimeEntryGrid_OnEdit server event handler on this page is used to
        ' start in-line-editing mode for TimeEntryGrid.
        '
        '*******************************************************

        Protected Sub TimeEntryGrid_OnEdit(ByVal sender As [Object], ByVal e As DataGridCommandEventArgs) Handles TimeEntryGrid.EditCommand
            TimeEntryGrid.EditItemIndex = e.Item.ItemIndex

            ' Saves current info on temporary, use later in TimeEntryGrid_Itembound()
            _userInput.Day = CType(e.Item.FindControl("EntryDay"), Label).Text
            _userInput.ProjectName = CType(e.Item.FindControl("EntryProject"), Label).Text.Trim()
            _userInput.ProjectID = Convert.ToInt32(CType(e.Item.FindControl("EntryProjectID"), Label).Text)
            _userInput.CategoryName = CType(e.Item.FindControl("EntryCategory"), Label).Text.Trim()
            _userInput.Duration = Convert.ToDecimal(CType(e.Item.FindControl("EntryDuration"), Label).Text)
            _userInput.Description = CType(e.Item.FindControl("GridDescription"), Label).Text.Trim()
            BindTimeSheet(_user.UserID, Convert.ToInt32(UserList.SelectedItem.Value), _weekStartingDate, _weekEndingDate)
        End Sub 'TimeEntryGrid_OnEdit

        '*******************************************************
        '
        ' TimeEntryGrid_OnUpdate server event handler on this page is used to
        ' update the changes made from in-line-editing.
        '
        '*******************************************************

        Protected Sub TimeEntryGrid_OnUpdate(ByVal sender As [Object], ByVal e As DataGridCommandEventArgs) Handles TimeEntryGrid.UpdateCommand
            Dim item As DataGridItem = TimeEntryGrid.Items(TimeEntryGrid.EditItemIndex)

            Dim required As RequiredFieldValidator = CType(item.FindControl("RequiredFieldValidatorGridHours"), RequiredFieldValidator)
            Dim comparer As CompareValidator = CType(item.FindControl("CompareValidatorGridHours"), CompareValidator)

            required.Validate()
            comparer.Validate()

            ' Check for validation, if all valid, update the object to data entered and save it.
            If required.IsValid And comparer.IsValid Then
                Dim entryLogID As Integer
                Dim userID As Integer
                Dim projectID As Integer
                Dim categoryID As Integer
                Dim taskDate As DateTime
                Dim description As String
                Dim duration As Decimal
                Dim te As BusinessLogicLayer.TimeEntry = Nothing

                ' Fill in properties for TimeEntry object.
                entryLogID = Convert.ToInt32(TimeEntryGrid.DataKeys(CInt(e.Item.ItemIndex)))
                userID = Convert.ToInt32(UserList.SelectedItem.Value)
                projectID = Convert.ToInt32(CType(e.Item.FindControl("EntryProjects"), DropDownList).SelectedItem.Value)
                categoryID = Convert.ToInt32(CType(e.Item.FindControl("EntryCategories"), DropDownList).SelectedItem.Value)
                taskDate = Convert.ToDateTime(CType(e.Item.FindControl("EntryDays"), DropDownList).SelectedItem.Value)
                description = TTSecurity.CleanStringRegex(CType(e.Item.FindControl("EntryDescription"), TextBox).Text)
                duration = Convert.ToDecimal(CType(e.Item.FindControl("EntryHours"), TextBox).Text)

                ' Save the TimeEntry object.
                te = New BusinessLogicLayer.TimeEntry(entryLogID, userID, projectID, categoryID, taskDate, description, duration)
                te.Save()

                ' Quit in-line-editing mode.
                TimeEntryGrid.EditItemIndex = -1
                BindTimeSheet(_user.UserID, Convert.ToInt32(UserList.SelectedItem.Value), _weekStartingDate, _weekEndingDate)
            End If
        End Sub 'TimeEntryGrid_OnUpdate

        '*******************************************************
        '
        ' TimeEntryGrid_Sort server event handler on this page is used to
        ' sorts the TimeEntryGrid according to the sort field
        ' being selected.
        '
        '*******************************************************

        Private Sub TimeEntryGrid_Sort(ByVal [source] As Object, ByVal e As System.Web.UI.WebControls.DataGridSortCommandEventArgs) Handles TimeEntryGrid.SortCommand
            TimeEntryGrid.EditItemIndex = -1
            SortField = e.SortExpression
            BindTimeSheet(_user.UserID, Convert.ToInt32(UserList.SelectedItem.Value), _weekStartingDate, _weekEndingDate)
        End Sub 'TimeEntryGrid_Sort

        '*******************************************************
        '
        ' UserProjects_OnChange server event handler on this page is called when user makes
        ' a seletion change from project dropdown within in-line-editing, is used to 
        ' update the category dropdown items according to the project selected
        '
        '*******************************************************

        Protected Sub UserProjects_OnChange(ByVal sender As Object, ByVal e As System.EventArgs)
            Dim item As DataGridItem = TimeEntryGrid.Items(TimeEntryGrid.EditItemIndex)

            ' Save temporary inputs so that data would be still there when user makes a Project selection
            ' and cause postback.
            If Not (item Is Nothing) Then
                Dim txt As TextBox = CType(item.FindControl("EntryHours"), TextBox)
                _userInput.Duration = Convert.ToDecimal(txt.Text)

                Dim txtDesc As TextBox = CType(item.FindControl("EntryDescription"), TextBox)
                _userInput.Description = txtDesc.Text

                Dim EntryDays As DropDownList = CType(item.FindControl("EntryDays"), DropDownList)
                _userInput.EntryDate = Convert.ToDateTime(EntryDays.SelectedItem.Value)
                _userInput.Day = EntryDays.SelectedItem.Text
            End If
            Dim EntryProjects As DropDownList = CType(sender, DropDownList)
            _userInput.ProjectID = Convert.ToInt32(EntryProjects.SelectedItem.Value)
            _userInput.ProjectName = EntryProjects.SelectedItem.Text
            BindTimeSheet(_user.UserID, Convert.ToInt32(UserList.SelectedItem.Value), _weekStartingDate, _weekEndingDate)
        End Sub 'UserProjects_OnChange

        '*******************************************************
        '
        ' UserList_OnChange server event handler on this page is used
        ' when a selection is changed in UserList DropDown
        ' UserList items are limited to Role of the current user logged on the system.
        '
        '*******************************************************

        Private Sub UserList_OnChange(ByVal sender As Object, ByVal e As System.EventArgs) Handles UserList.SelectedIndexChanged
            TimeEntryGrid.EditItemIndex = -1
            BindTimeSheet(_user.UserID, Convert.ToInt32(UserList.SelectedItem.Value), _weekStartingDate, _weekEndingDate)
            BindEntryFields()
        End Sub 'UserList_OnChange

        '*******************************************************
        '
        ' WeekEnding_TextChanged server event handler on this page is used to
        ' select the correct week starting date and week ending date
        ' it gets called when user makes a selection change on calendar.
        '
        '*******************************************************

        Private Sub WeekEnding_TextChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles WeekEnding.TextChanged
            TimeEntryGrid.EditItemIndex = -1
            BusinessLogicLayer.TimeEntry.FillCorrectStartEndDates(Convert.ToDateTime(WeekEnding.Text), _weekStartingDate, _weekEndingDate)
            WeekEnding.Text = _weekEndingDate.ToShortDateString()
            BindEntryFields()
            BindTimeSheet(_user.UserID, Convert.ToInt32(UserList.SelectedItem.Value), _weekStartingDate, _weekEndingDate)
        End Sub 'WeekEnding_TextChanged

        Property SortField() As String
            Get
                Dim o As Object = ViewState("SortField")
                If o Is Nothing Then
                    Return [String].Empty
                End If
                Return CStr(o)
            End Get

            Set(ByVal Value As String)
                If Value = SortField Then
                    ' same as current sort file, toggle sort direction
                    SortAscending = Not SortAscending
                End If
                ViewState("SortField") = Value
            End Set
        End Property

        '*********************************************************************
        '
        ' SortAscending property is tracked in ViewState
        '
        '*********************************************************************

        Property SortAscending() As Boolean
            Get
                Dim o As Object = ViewState("SortAscending")
                If o Is Nothing Then
                    Return True
                End If
                Return CBool(o)
            End Get

            Set(ByVal Value As Boolean)
                ViewState("SortAscending") = Value
            End Set
        End Property

        Private Sub InitializeComponent()

        End Sub
    End Class 'TimeEntry 
End Namespace 'ASPNET.StarterKit.TimeTracker.Web