//////////////////////////////////////////////////////////////////////////////////////////////////
//Custom User Control: Poll.ascx
//
//This is a custom UserControl to obtain votes and display the result.
//It will be dynamicly loaded in the boxes of the main page.
//
//Use this control as the the view layer of the simple PollSystem. It comunicates with
//the other components of the PollSystem such as PollSubjectInfoManagement, PollOptionInfoManagement,
//and use PollOptionInfo, PollRecordInfo, PollSubjectInfo to represent and transform data 
//between these components.
//
//

using System;
using System.Data;
using System.Configuration;
using System.Collections;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using digioz.PollSystem;
using System.Collections.Generic;

/// <summary>
/// The Poll.ascx
/// </summary>
public partial class controls_Poll : System.Web.UI.UserControl
{
    ///<summary>
    ///Use this enum type to specify the specific states of this UserControl:                 
    ///VOTING, means to show the voting view in the MultiView control                           
    ///RESULT, the result of the poll                                                           
    ///REFUSED, if the vistor has not logged in, or some other reasons to prevent this poll     
    ///         from others.                                                                    
    ///NODATA, there is no such a poll subject or options for this pool subject in the datebase 
    ///</summary>
    public enum PollState
    {
        VOTING = 0,
        RESULT,
        REFUSED,
        NODATA
    }

    public Boolean Sorting
    {
        get 
        {
            object sorting = ViewState["Sorting"];
            if (sorting == null)
            {
                return false;
            }
            else
            {
                return (bool)sorting;
            }
        }
        set 
        {
            ViewState["Sorting"] = value;
        }
    }
    //private int _poll_subject_id = -1;
    //private PollSubjectInfo _poll_subject_info = null;

    /// <summary>
    /// Use this property to store the subject_id
    /// </summary>
    public int PollSubjecID
    {
        get
        {
            object pollSubjectID = ViewState["PollSubjecID"];
            return ((pollSubjectID == null) ? -1 : (int)pollSubjectID);
        }
        set
        {
            ViewState["PollSubjecID"] = value;
        }
    }

    /// <summary>
    /// Use this property to store full informations about this poll subject
    /// </summary>
    public PollSubjectInfo PollSubject
    {
        get
        {
            PollSubjectInfo pollSubject = (PollSubjectInfo)ViewState["PollSubject"];
            return pollSubject;
        }
        set
        {
            ViewState["PollSubject"] = value;
        }
    }

    ///<summary>
    ///The state of the poll control
    ///Use the MultiView control's ActiveViewIndex property to store this UserControl's 
    ///state via the ViewState
    /// </summary>
    public PollState State
    {
        get
        {
            return (PollState)mlvPoll.ActiveViewIndex;
        }
        set
        {
            //If the state changed, render it before presenting
            if (value == PollState.VOTING)
            {
                if (!PollSubjectInfoManagement.IsOutOfDate(this.PollSubject))
                { 
                    // Control initialization should be done only on first load
                    if (!IsPostBack)
                    {
                        UpdateVotingView();
                    }
                }
                else
                {
                    this.State = PollState.RESULT;
                    return;
                }
            }
            else if (value == PollState.RESULT)
            {
                // TODO: Use a datagrid or datalist instead and 
                //       initialize only on first load.
                UpdateResultView();
            }

            mlvPoll.ActiveViewIndex = (int)value;
        }
    }

    /// <summary>
    /// Initialization logic
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    protected void Page_Load(object sender, EventArgs e)
    {
        Initialize();
    }

    ///<summary>
    ///Initialize this custom usercontrol:
    ///1.Get PollSubjecID from eviroment or datebase
    ///2.Initialize the PollSubjectInfo property PollSubject
    ///3.Show the appropriate view according to the actual situation
    ///</summary>
    public void Initialize()
    {
        //try to get PollSubjectID from the query string

        PollSubjecID = Convert.ToInt16(Request.QueryString["pollsubject"]);
        if (PollSubjecID < 1)
        {
            //Get the newest Poll Subject to show
            PollSubjecID = PollSubjectInfoManagement.GetLatestOpenPollSubjectID();
        }
        
        // Get the poll_subject information based on the poll subject Id
        PollSubject = PollSubjectInfoManagement.GetPollSubjectInfo(PollSubjecID);

        //Initial the "Polls" link in the left-down corner of the control
        string csURLEncryptionKey = ConfigurationManager.AppSettings["URLEncryptKey"];
        string url = "Default.aspx?page=" + Server.UrlEncode(digioz.Encryption64.Encrypt("Poll List", csURLEncryptionKey));
        lbPolls.Text = "<a href=\""+url+"\">Polls</a>";

        // Determine which view to display based on the user sign on status
        // and whether or not the user has already voted.
        // This is also where the control are initialized. 
        // But the initializayion should be done only on first load,
        // not on post back. (See State property)
        if (PollSubject != null)
        {
            //Set the control title to be the subject name
            lbTitle.Text = PollSubject.SubjectName;

            //If the user has logged in
            if (Session["UserID"] != null)
            {
                //If this visitor has already submited 
                if (!PollSubjectInfoManagement.HaveSubmit(GetUserID(), PollSubjecID))
                {
                    //Display the options
                    this.Show(PollState.VOTING);
                }
                else
                {
                    //show result of the poll
                    this.Show(PollState.RESULT);
                }
            }
            else
            {
                // Show result of the latest poll
                this.Show(PollState.RESULT);
            }
        }
        else
        {
            //show no data warning
            this.Show( PollState.NODATA);
        } 
    }

    /// <summary>
    /// show one of the views in the mlvPoll
    /// </summary>
    /// <param name="state"></param>
    public void Show(PollState state)
    {
        this.State = state;
    }

    
    /// <summary>
    ///Update the controls in view vwResult
    /// </summary>
    private void UpdateResultView()
    {
        int total = 0, count = 0;
        string[] optionName;
        int[] votes;
        string[] percent;

        //Get the Options of this subject from database
        PollOptionInfoList options = PollOptionInfoManagement.GetPollOptionInfoList(PollSubject.ID);

        count = options.Count;
        optionName = new string[count];
        votes = new int[count];
        percent = new string[count];

        for (int i = 0; i < count; i++)
        {
            optionName[i] = options[i].OptionName;
            votes[i] = options[i].OptionVotes;
            total += votes[i];
        }

        //sorting the result
        if (this.Sorting)
        {
            Array.Sort(votes, optionName);
        }

        if (total == 0)
        {
            for (int i = 0; i < count; i++)
            {
                percent[i] = string.Format("{0:#0.00}", 0F);
            }
        }
        else
        {
            for (int i = 0; i < count; i++)
            {
                percent[i] = string.Format("{0:#0.00}", ((float)votes[i] / (float)total) * 100.0);
            }
        }


        //Remove all the old items
        htmltbResult.Rows.Clear();
        //render the Result View
        for (int i = 0; i < count; i++)
        {
            
            HtmlTableRow row;
            HtmlTableCell cell;

            row = new HtmlTableRow();
            cell = new HtmlTableCell();
            cell.ColSpan = 2;
            cell.InnerHtml = "<div style=\"font-weight:120\">" + optionName[i] + "</div>";
            row.Cells.Add(cell);
            htmltbResult.Rows.Add(row);

            row = new HtmlTableRow();
            cell = new HtmlTableCell();
            cell.Width = "70%";
            cell.InnerHtml = "<div class=\"pollbar\" style=\" width:" + percent[i] + "%; height:10px;\"></div>";
            row.Cells.Add(cell);
            cell = new HtmlTableCell();
            cell.Width = "30%";
            cell.InnerHtml = "<div style=\"font-size:13px; text-align:right\">" + percent[i] + "%</div>";
            row.Cells.Add(cell);
            htmltbResult.Rows.Add(row);

            row = new HtmlTableRow();
            cell = new HtmlTableCell();
            cell.ColSpan = 2;
            cell.InnerHtml = "<div style=\"font-size:10px; text-align:right\">" + votes[i] + " votes</div>";
            row.Cells.Add(cell);
            htmltbResult.Rows.Add(row);
        }

    }

    
    /// <summary>
    /// Update the controls in view vwPoll 
    /// </summary>
    private void UpdateVotingView()
    {
        int liTotal = 0;
        //Get the Options of this subject from database
        PollOptionInfoList options = PollOptionInfoManagement.GetPollOptionInfoList(PollSubject.ID);

        rblOptions.DataSource = options;
        rblOptions.DataBind();  // Watch out. This resets the selectedIndex

        //The default selected index of rblOptions is -1, means no one is selected by default.
        rblOptions.SelectedIndex = -1;

        // Calculates the sum of votes
        for (int i = 0; i < options.Count; i++)
        {
            liTotal += options[i].OptionVotes;
        }
        lbVotes.Text = String.Format("Votes: {0}", liTotal);

    }

    /// <summary>
    /// Try to get an identifier to the participant
    /// If this is a sercret ballot, it will be the participant's IP address,
    /// else it should be the user_id of the participant
    /// </summary>
    /// <returns></returns>
    private string GetUserID()
    {
        string userID;
        //If it is a secret ballot
        if (PollSubject.SecretBallot)
        {
            //In secret ballot mode, we use IpAddress to Identify a user
            userID = Session["visitorIP"].ToString();
        }
        else
        {
            //In this mode, we use the UserID from Application Evironment to Identify a user
            userID = Session["userid"].ToString();
        }
        return userID;
    }

    /// <summary>
    /// handle the submit button click event
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    protected void btnSubmit_Click(object sender, EventArgs e)
    {
        //If the user have selected
        if (rblOptions.SelectedIndex >= 0)
        {
            //If the user already have submitted
            if (!PollSubjectInfoManagement.HaveSubmit(this.GetUserID(), PollSubjecID))
            {
                //Submit the votes
                try
                {
                    PollRecordInfo record = new PollRecordInfo();
                    record.OptionID = int.Parse(rblOptions.SelectedValue);
                    record.UserID = this.GetUserID();
                    
                    //Submit record
                    //if it is not out of date
                    if (!PollSubjectInfoManagement.IsOutOfDate(this.PollSubject))
                    {
                        PollRecordInfoManagement.InsertPollRecord(record);
                    }

                    //show result
                    this.Show(PollState.RESULT);
                }
                catch
                {
                    //TODO:If there are problems
                }
            }
            else
            {
                //show result
                this.Show(PollState.RESULT);
            }
        }
    }
}
