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

    namespace ASPNET.StarterKit.TimeTracker.Web
    {
        //*********************************************************
        //
        // Main page of the Application, for users to enter time entries.
        //
        //*********************************************************

        public class TimeEntry : System.Web.UI.Page
        {
            //Use Time Entry component to capture user's input during edit mode
            protected BusinessLogicLayer.TimeEntry    _userInput = new BusinessLogicLayer.TimeEntry(0, 0, 0, 0, DateTime.MinValue, null, -1M);
            protected DataTable                        _dayListTable = null;

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

            private TTUser     _user;
            private DateTime _weekEndingDate = DateTime.Today;
            private DateTime _weekStartingDate = DateTime.Today;

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

            private void Page_Load(object sender, System.EventArgs e)
            {
                _user = new TTUser(
                    TTSecurity.GetUserID(),
                    User.Identity.Name,
                    TTSecurity.GetName(),
                    TTSecurity.GetUserRole());

                if (!Page.IsPostBack)
                {
                    // If page is loaded for the first time, select the current week.
                    BusinessLogicLayer.TimeEntry.FillCorrectStartEndDates(DateTime.Today,
                        ref _weekStartingDate, ref _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),
                        ref _weekStartingDate, ref _weekEndingDate);
                    _dayListTable = BusinessLogicLayer.TimeEntry.GetWeek(Convert.ToDateTime(WeekEnding.Text));
                }
            }

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

            private void BindCategoryList()
            {
                if (ProjectList.SelectedItem != null)
                {
                    // 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();
                }
            }

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

            private void 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;
            }

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

            private void BindEntryFields()
            {
                BindDates();
                BindProjectList();
                BindCategoryList();
            }

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

            private void BindProjectList()
            {
                // Preserve the selected value so information is still there after postback.
                if (ProjectList.SelectedItem != null)
                    _userInput.ProjectID = Convert.ToInt32(ProjectList.SelectedItem.Value);

                ProjectList.DataSource = ListUserProjects();
                ProjectList.DataTextField = "Name";
                ProjectList.DataValueField = "ProjectID";
                ProjectList.DataBind();

                // Select the correct item from ProjectList.
                if (ProjectList.Items.FindByValue(_userInput.ProjectID.ToString()) != null)
                    ProjectList.Items.FindByValue(_userInput.ProjectID.ToString()).Selected = true;
            }

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

            private void BindTimeSheet(int userID, DateTime start, DateTime end)
            {
                BindTimeSheet(userID, userID, start, end);
            }

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

            private void BindTimeSheet(int queryUserID, int userID, DateTime start, DateTime end)
            {
                TimeEntriesCollection entryList = BusinessLogicLayer.TimeEntry.GetEntries(queryUserID, userID, start, end);

                // Sort datagrid if it is not empty.
                if (entryList != null)
                {
                    SortGridData(entryList, SortField, SortAscending);
                }
                // Draw time graph with new dataset.
                DrawTimeGraph(entryList, _dayListTable);

                TimeEntryGrid.DataSource = entryList;
                TimeEntryGrid.DataBind();

            }

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

            private void 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;
            }

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

            private void 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;
            }

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

            private void DrawTimeGraph(TimeEntriesCollection chartData, DataTable dtWeek)
            {
                // Assume dtWeek is already in the correct order according to FirstDayOfWeek Setting.
                Hashtable htWeekSummary = new Hashtable(7);    //7 days of data - key: EntryDate | value: Duration.

                // x & y values holder
                StringBuilder xValues = new StringBuilder();
                StringBuilder yValues = new StringBuilder();

                //Initialize htWeekSummary to start with first day of week setting.
                foreach (DataRow row in dtWeek.Rows)
                {
                    htWeekSummary.Add(Convert.ToDateTime(row["Date"]).ToShortDateString(), 0m);
                }

                // Summarize data from grid Group By Days of Week.
                foreach (BusinessLogicLayer.TimeEntry time in chartData)
                {
                    string key = time.EntryDate.ToShortDateString();
                    Decimal dayDuration = Convert.ToDecimal(htWeekSummary[key]);
                    dayDuration += time.Duration;
                    htWeekSummary[key] = dayDuration;
                }

                //Build x & y values for graph.
                int index = 1;
                foreach (DataRow row in dtWeek.Rows)
                {
                    string key = Convert.ToDateTime(row["Date"]).ToShortDateString();
                    string currentDay = Convert.ToDateTime(key).ToString("ddd");
                    string currentHour = Convert.ToString(htWeekSummary[key]);

                    xValues.Append(currentDay);
                    yValues.Append(currentHour);

                    //Don't append separator if this is the last item.
                    if (index != dtWeek.Rows.Count)
                    {
                        xValues.Append("|");
                        yValues.Append("|");
                    }
                    index++;
                }

                //Attach image generator to image.
                TimeGraph.ImageUrl = "TimeEntryBarChart.aspx?" +
                    "xValues=" + xValues.ToString() +
                    "&yValues=" + yValues.ToString();
            }

            //*******************************************************
            //
            // ListGridCategories method returns a List of categories based on the projectID.
            //
            //*******************************************************

            protected CategoriesCollection ListGridCategories(int projectID)
            {
                return Project.GetCategories(projectID);
            }

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

            protected ProjectsCollection ListUserProjects()
            {
                return BusinessLogicLayer.Project.GetProjects(_user.UserID, Convert.ToInt32(UserList.SelectedItem.Value));
            }

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

            private void SortGridData(TimeEntriesCollection list, string sortField, bool asc)
            {
                TimeEntriesCollection.TimeEntryFields sortCol = TimeEntriesCollection.TimeEntryFields.InitValue;

                switch(sortField)
                {
                    case "EntryDate":
                        sortCol = TimeEntriesCollection.TimeEntryFields.Day;
                        break;
                    case "ProjectName":
                        sortCol = TimeEntriesCollection.TimeEntryFields.Project;
                        break;
                    case "CategoryName":
                        sortCol = TimeEntriesCollection.TimeEntryFields.Category;
                        break;
                    case "Duration":
                        sortCol = TimeEntriesCollection.TimeEntryFields.Hours;
                        break;
                    case "Description":
                        sortCol = TimeEntriesCollection.TimeEntryFields.Description;
                        break;
                    default:
                        break;
                }

                list.Sort(sortCol, asc);
            }

            #region Web Form Designer generated code
            override protected void OnInit(EventArgs e)
            {
                //
                // CODEGEN: This call is required by the ASP.NET Web Form Designer.
                //
                InitializeComponent();
                base.OnInit(e);
            }

            ///
            ///    Required method for Designer support - do not modify
            ///    the contents of this method with the code editor.
            ///
            private void InitializeComponent()
            {
                this.WeekEnding.TextChanged += new System.EventHandler(this.WeekEnding_TextChanged);
                this.ProjectList.SelectedIndexChanged += new System.EventHandler(this.ProjectList_SelectedIndexChanged);
                this.AddEntry.Click += new System.EventHandler(this.AddEntry_Click);
                this.Cancel.Click += new System.EventHandler(this.Cancel_Click);
                this.UserList.SelectedIndexChanged += new System.EventHandler(this.UserList_OnChange);
                this.TimeEntryGrid.CancelCommand += new System.Web.UI.WebControls.DataGridCommandEventHandler(this.TimeEntryGrid_OnCancel);
                this.TimeEntryGrid.EditCommand += new System.Web.UI.WebControls.DataGridCommandEventHandler(this.TimeEntryGrid_OnEdit);
                this.TimeEntryGrid.SortCommand += new System.Web.UI.WebControls.DataGridSortCommandEventHandler(this.TimeEntryGrid_Sort);
                this.TimeEntryGrid.UpdateCommand += new System.Web.UI.WebControls.DataGridCommandEventHandler(this.TimeEntryGrid_OnUpdate);
                this.TimeEntryGrid.DeleteCommand += new System.Web.UI.WebControls.DataGridCommandEventHandler(this.TimeEntryGrid_OnDelete);
                this.TimeEntryGrid.ItemDataBound += new System.Web.UI.WebControls.DataGridItemEventHandler(this.TimeEntryGrid_Itembound);
                this.Load += new System.EventHandler(this.Page_Load);

            }
            #endregion

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

            private void AddEntry_Click(object sender, System.EventArgs e)
            {
                // 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 && RequiredFieldValidator2.IsValid && CompareValidator1.IsValid && RangeValidator1.IsValid)
                {
                    BusinessLogicLayer.TimeEntry te = 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();
                }
            }

            //*******************************************************
            //
            // Cancel_Click server event handler on this page is used to
            // clear all entry fields on page.
            //
            //*******************************************************

            private void Cancel_Click(object sender, System.EventArgs e)
            {
                ClearEntryFields();
            }

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

            private void ProjectList_SelectedIndexChanged(object sender, System.EventArgs e)
            {
                BindCategoryList();
            }

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

            private void TimeEntryGrid_Itembound(object sender, System.Web.UI.WebControls.DataGridItemEventArgs e)
            {
                // 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)
                {
                    DropDownList currentCbo = (DropDownList) e.Item.FindControl("EntryDays");
                    currentCbo.SelectedIndex = currentCbo.Items.IndexOf(currentCbo.Items.FindByText(_userInput.Day));

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

                    currentCbo = (DropDownList) e.Item.FindControl("EntryCategories");
                    currentCbo.SelectedIndex = currentCbo.Items.IndexOf(currentCbo.Items.FindByText(_userInput.CategoryName));
                }
            }

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

            protected void TimeEntryGrid_OnCancel(Object sender, DataGridCommandEventArgs e)
            {
                TimeEntryGrid.EditItemIndex = -1;
                BindTimeSheet(_user.UserID, Convert.ToInt32(UserList.SelectedItem.Value), _weekStartingDate, _weekEndingDate);
            }

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

            protected void TimeEntryGrid_OnDelete(Object sender, DataGridCommandEventArgs e)
            {
                int entryLogID = Convert.ToInt32(TimeEntryGrid.DataKeys[(int)e.Item.ItemIndex]);
                BusinessLogicLayer.TimeEntry.Remove(entryLogID);
                BindTimeSheet(_user.UserID, Convert.ToInt32(UserList.SelectedItem.Value), _weekStartingDate, _weekEndingDate);
            }

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

            protected void TimeEntryGrid_OnEdit(Object sender, DataGridCommandEventArgs e)
            {
                TimeEntryGrid.EditItemIndex = e.Item.ItemIndex;

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

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

            protected void TimeEntryGrid_OnUpdate(Object sender, DataGridCommandEventArgs e)
            {
                DataGridItem item = TimeEntryGrid.Items[TimeEntryGrid.EditItemIndex];

                RequiredFieldValidator required = (RequiredFieldValidator) item.FindControl("RequiredFieldValidatorGridHours");
                CompareValidator comparer = (CompareValidator) item.FindControl("CompareValidatorGridHours");

                required.Validate();
                comparer.Validate();

                // Check for validation, if all valid, update the object to data entered and save it.
                if (required.IsValid && comparer.IsValid)
                {
                    int entryLogID;
                    int userID;
                    int projectID;
                    int categoryID;
                    DateTime taskDate;
                    string description;
                    decimal duration;
                    BusinessLogicLayer.TimeEntry te = null;

                    // Fill in properties for TimeEntry object.
                    entryLogID = Convert.ToInt32(TimeEntryGrid.DataKeys[(int)e.Item.ItemIndex]);
                    userID = Convert.ToInt32(UserList.SelectedItem.Value);
                    projectID = Convert.ToInt32(((DropDownList) e.Item.FindControl("EntryProjects")).SelectedItem.Value);
                    categoryID = Convert.ToInt32(((DropDownList) e.Item.FindControl("EntryCategories")).SelectedItem.Value);
                    taskDate = Convert.ToDateTime(((DropDownList) e.Item.FindControl("EntryDays")).SelectedItem.Value);
                    description = TTSecurity.CleanStringRegex(((TextBox) e.Item.FindControl("EntryDescription")).Text);
                    duration = Convert.ToDecimal(((TextBox) e.Item.FindControl("EntryHours")).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);
                }
            }

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

            private void TimeEntryGrid_Sort(object source, System.Web.UI.WebControls.DataGridSortCommandEventArgs e)
            {
                SortField = e.SortExpression;
                BindTimeSheet(_user.UserID, Convert.ToInt32(UserList.SelectedItem.Value), _weekStartingDate, _weekEndingDate);
            }

            //*******************************************************
            //
            // 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 void UserProjects_OnChange(object sender, System.EventArgs e)
            {
                DataGridItem item = TimeEntryGrid.Items[TimeEntryGrid.EditItemIndex];

                // Save temporary inputs so that data would be still there when user makes a Project selection
                // and cause postback.
                if (item != null)
                {
                    TextBox txt = (TextBox) item.FindControl("EntryHours");
                    _userInput.Duration = Convert.ToDecimal(txt.Text);

                    TextBox txtDesc = (TextBox) item.FindControl("EntryDescription");
                    _userInput.Description = txtDesc.Text;

                    DropDownList EntryDays = (DropDownList)item.FindControl("EntryDays");
                    _userInput.EntryDate = Convert.ToDateTime(EntryDays.SelectedItem.Value);
                    _userInput.Day = EntryDays.SelectedItem.Text;

                }
                DropDownList EntryProjects = (DropDownList) sender;
                _userInput.ProjectID = Convert.ToInt32(EntryProjects.SelectedItem.Value);
                _userInput.ProjectName = EntryProjects.SelectedItem.Text;
                BindTimeSheet(_user.UserID, Convert.ToInt32(UserList.SelectedItem.Value), _weekStartingDate, _weekEndingDate);
            }

            //*******************************************************
            //
            // 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 void UserList_OnChange(object sender, System.EventArgs e)
            {
                TimeEntryGrid.EditItemIndex = -1;
                BindTimeSheet(_user.UserID, Convert.ToInt32(UserList.SelectedItem.Value), _weekStartingDate, _weekEndingDate);
                BindEntryFields();
            }

            //*******************************************************
            //
            // 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 void WeekEnding_TextChanged(object sender, System.EventArgs e)
            {
                TimeEntryGrid.EditItemIndex = -1;
                BusinessLogicLayer.TimeEntry.FillCorrectStartEndDates(Convert.ToDateTime(WeekEnding.Text),
                    ref _weekStartingDate, ref _weekEndingDate);
                WeekEnding.Text = _weekEndingDate.ToShortDateString();
                BindEntryFields();
                BindTimeSheet(_user.UserID, Convert.ToInt32(UserList.SelectedItem.Value), _weekStartingDate, _weekEndingDate);
            }

            string SortField
            {
                get
                {
                    object o = ViewState["SortField"];
                    if (o == null)
                    {
                        return String.Empty;
                    }
                    return (string)o;
                }

                set
                {
                    if (value == SortField)
                    {
                        // same as current sort file, toggle sort direction
                        SortAscending = !SortAscending;
                    }
                    ViewState["SortField"] = value;
                }
            }

            //*********************************************************************
            //
            // SortAscending property is tracked in ViewState
            //
            //*********************************************************************

            bool SortAscending
            {
                get
                {
                    object o = ViewState["SortAscending"];
                    if (o == null)
                    {
                        return true;
                    }
                    return (bool)o;
                }

                set
                {
                    ViewState["SortAscending"] = value;
                }
            }

        }
    }