/* Copyright (c) Citrix Systems, Inc. 
 * All rights reserved. 
 * 
 * Redistribution and use in source and binary forms, 
 * with or without modification, are permitted provided 
 * that the following conditions are met: 
 * 
 * *   Redistributions of source code must retain the above 
 *     copyright notice, this list of conditions and the 
 *     following disclaimer. 
 * *   Redistributions in binary form must reproduce the above 
 *     copyright notice, this list of conditions and the 
 *     following disclaimer in the documentation and/or other 
 *     materials provided with the distribution. 
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 
 * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, 
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR 
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 
 * SUCH DAMAGE.
 */

using System;
using System.Collections.Generic;
using System.Data;
using System.Drawing;
using System.Globalization;
using System.Text;
using System.Windows.Forms;
using XenAPI;
using XenAdmin.Core;
using XenAdmin.Wlb;
using XenAdmin.Dialogs;
using XenAdmin.Dialogs.Wlb;
using XenAdmin.Actions;
using XenAdmin.Actions.Wlb;
using System.Collections;

// Report viewer control dependencies
using Microsoft.Reporting.WinForms;
using System.IO;



namespace XenAdmin.Controls.Wlb
{
    public partial class WlbReportView : UserControl
    {
       
        #region Variables

        public event CustomRefreshEventHandler OnChangeOK;
        public event DrillthroughEventHandler ReportDrilledThrough;
        public event EventHandler Close;
        public event EventHandler PoolConnectionLost;

        private static readonly log4net.ILog log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);

        private bool _bDisplayedError;
        private int _currentOffsetMinutes;
        private int _startLine;
        private int _endLine;
        private int _currentReportSection;

        // To mitigate the WLB server memory pressure to generate pool audit trail report
        // and decrease the latency to display the report results on XenCenter,
        // split large pool audit trail report in sections, each contains at most 200 pages.
        // For the first page, there are 43 lines of record.
        // For other pages, each contains 45 lines of record.
        private const int _lineLimit = 9000 - 2; 
        private bool _userComboSet;
        private bool _objectComboSet;
        private string _startTime = String.Empty;
        private string _endTime = String.Empty;
        private bool _isAuditReport;

        private WlbReportInfo _reportInfo;
        private LocalReport _localReport;
        private IEnumerable<Host> _hosts;

        private List<string> _selectedCustomFilters; 
        private static string DELIMITER = ",";

        // for report subscription
        private Dictionary<string, string> _reportParameters;

        #endregion


        #region Properties

        public bool ButtonSubscribeVisible
        {
            set { btnSubscribe.Visible = value; }
        }

        public bool ButtonLaterReportVisible
        {
            set { btnLaterReport.Visible = value; }
        }

        public WlbReportInfo ViewerReportInfo
        {
            get { return _reportInfo; }
            set { _reportInfo = value; }
        }

        public LocalReport ViewerLocalReport
        {
            get { return _localReport; }
            set { _localReport = value; }
        }

        public Pool Pool { get; set; }

        public bool ResetReportViewer { get; set; }

        public IEnumerable<Host> Hosts
        {
            get { return _hosts; }
            set
            {
                _hosts = value;
                SetHostComboBox();
            }
        }

        public bool IsCreedenceOrLater { get; set; }

        #endregion


        #region Constructor

        public WlbReportView()
        {
            InitializeComponent();
            FixSearchTextField(); //Fix for CA-59482: don't let the text length be more that 32 chars
            
            //CA-67888: For localizing export menu items
            ToolStrip toolStrip = (ToolStrip)reportViewer1.Controls.Find("toolStrip1", true)[0];
            ToolStripDropDownButton exportButton = (ToolStripDropDownButton)toolStrip.Items["export"];

            //Internally Microsoft ReportViewer populates "Export" ToolStripDropDownButton on DropDownOpening event.
            //That means DropDownOpening has two event hanlders including ours below. Although they'll be executed in the order they were added
            //for now -- so these localized Texts will replace old Texts -- the .NET Framework specification doesn't say anything about the
            //order of execution of event handlers. So although highly unlikely, the order may not be proper in the future.
            exportButton.DropDownOpening += (sender, e) =>
            {
                if (exportButton.DropDownItems.Count == 2)
                {
                    exportButton.DropDownItems[0].Text = Messages.FILE_XLS;
                    exportButton.DropDownItems[1].Text = Messages.FILE_PDF;
                }
            };
        }

        /// <summary>
        /// Sets the maximum number of characters allowed in the find textbox to 32
        /// </summary>
        private void FixSearchTextField()
        {
            const int maxLen = 32;
            ToolStrip toolStrip = (ToolStrip)reportViewer1.Controls.Find("toolStrip1", true)[0];
            //text box
            ToolStripTextBox findTextBox = (ToolStripTextBox)toolStrip.Items["textToFind"];
            findTextBox.MaxLength = maxLen;
            //find button
            ToolStripLabel findButton = (ToolStripLabel)toolStrip.Items["find"];
            findButton.Click += (s, e) =>
            {
                if (findTextBox.Text.Length > maxLen)
                {
                    findTextBox.Text = findTextBox.Text.Remove(maxLen);
                }
            };
        }

        #endregion


        #region Helpers

        /// <summary>
        /// Implements all IReportViewerMessages to provide localization support to
        /// the report toolbar for tooltips and other misc items
        /// </summary>
        public class CCustomMessageClass : IReportViewerMessages
        {

            public string BackButtonToolTip
            {
                get { return (Messages.WLB_REPORT_BACKTOPARENTREPORT); }
            }

            public string BackMenuItemText
            {
                get { return (Messages.WLB_REPORT_BACKTOPARENTREPORT); }
            }

            public string ChangeCredentialsText
            {
                get { return (Messages.WLB_REPORT_CHANGECREDENTIALSTEXT); }
            }

            public string CurrentPageTextBoxToolTip
            {
                get { return (Messages.WLB_REPORT_CURRENTPAGETEXTBOXTOOLTIP); }
            }

            public string DocumentMapButtonToolTip
            {
                get { return (Messages.WLB_REPORT_DOCUMENTMAP); }
            }

            public string DocumentMapMenuItemText
            {
                get { return (Messages.WLB_REPORT_DOCUMENTMAP); }
            }

            public string ExportButtonToolTip
            {
                get { return (Messages.WLB_REPORT_EXPORT); }
            }

            public string ExportMenuItemText
            {
                get { return (Messages.WLB_REPORT_EXPORT); }
            }

            public string FalseValueText
            {
                get { return (Messages.WLB_REPORT_FALSEVALUETEXT); }
            }

            public string FindButtonText
            {
                get { return (Messages.WLB_REPORT_FIND); }
            }

            public string FindButtonToolTip
            {
                get { return (Messages.WLB_REPORT_FIND); }
            }

            public string FindNextButtonText
            {
                get { return (Messages.WLB_REPORT_NEXT); }
            }

            public string FindNextButtonToolTip
            {
                get { return (Messages.WLB_REPORT_FINDNEXT); }
            }

            public string FirstPageButtonToolTip
            {
                get { return (Messages.WLB_REPORT_FIRSTPAGE); }
            }

            public string LastPageButtonToolTip
            {
                get { return (Messages.WLB_REPORT_LASTPAGE); }
            }

            public string NextPageButtonToolTip
            {
                get { return (Messages.WLB_REPORT_NEXTPAGE); }
            }

            public string NoMoreMatches
            {
                get { return (Messages.WLB_REPORT_NOMOREMATCHES); }
            }

            public string NullCheckBoxText
            {
                get { return (Messages.WLB_REPORT_FALSEVALUETEXT); }
            }

            public string NullCheckBoxToolTip
            {
                get { return (Messages.WLB_REPORT_FALSEVALUETEXT); }
            }

            public string NullValueText
            {
                get { return (Messages.WLB_REPORT_FALSEVALUETEXT); }
            }

            public string PageOf
            {
                get { return (Messages.WLB_REPORT_PAGEOF); }
            }

            public string PageSetupButtonToolTip
            {
                get { return (Messages.WLB_REPORT_PAGESETUP); }
            }

            public string PageSetupMenuItemText
            {
                get { return (Messages.WLB_REPORT_PAGESETUP); }
            }

            public string ParameterAreaButtonToolTip
            {
                get { return (Messages.WLB_REPORT_PARAMETERS); }
            }

            public string PasswordPrompt
            {
                get { return (Messages.WLB_REPORT_PASSWORDPROMPT); }
            }

            public string PreviousPageButtonToolTip
            {
                get { return (Messages.WLB_REPORT_PREVIOUSPAGE); }
            }

            public string PrintButtonToolTip
            {
                get { return (Messages.WLB_REPORT_PRINT); }
            }

            public string PrintLayoutButtonToolTip
            {
                get { return (Messages.WLB_REPORT_PRINTLAYOUT); }
            }

            public string PrintLayoutMenuItemText
            {
                get { return (Messages.WLB_REPORT_PRINTLAYOUT); }
            }

            public string PrintMenuItemText
            {
                get { return (Messages.WLB_REPORT_PRINT); }
            }

            public string ProgressText
            {
                get { return (Messages.WLB_REPORT_PROCESSING); }
            }

            public string RefreshButtonToolTip
            {
                get { return (Messages.WLB_REPORT_REFRESH); }
            }

            public string RefreshMenuItemText
            {
                get { return (Messages.WLB_REPORT_REFRESH); }
            }

            public string SearchTextBoxToolTip
            {
                get { return (Messages.WLB_REPORT_SEARCH); }
            }

            public string SelectAValue
            {
                get { return (Messages.WLB_REPORT_SELECT); }
            }

            public string SelectAll
            {
                get { return (Messages.WLB_REPORT_SELECTALL); }
            }

            public string StopButtonToolTip
            {
                get { return (Messages.WLB_REPORT_STOPRENDERING); }
            }

            public string StopMenuItemText
            {
                get { return (Messages.WLB_REPORT_STOPRENDERING); }
            }

            public string TextNotFound
            {
                get { return (Messages.WLB_REPORT_TEXTNOTFOUND); }
            }

            public string TotalPagesToolTip
            {
                get { return (Messages.WLB_REPORT_TOTALPAGES); }
            }

            public string TrueValueText
            {
                get { return (""); }
            }

            public string UserNamePrompt
            {
                get { return (Messages.WLB_REPORT_USERNAME); }
            }

            public string ViewReportButtonText
            {
                get { return (Messages.WLB_REPORT_VIEWREPORT); }
            }

            public string ViewReportButtonToolTip
            {
                get { return (Messages.WLB_REPORT_VIEWREPORT); }
            }

            public string ZoomControlToolTip
            {
                get { return (Messages.WLB_REPORT_ZOOM); }
            }

            public string ZoomMenuItemText
            {
                get { return (Messages.WLB_REPORT_ZOOM); }
            }

            public string ZoomToPageWidth
            {
                get { return (Messages.WLB_REPORT_PAGEWIDTH); }
            }

            public string ZoomToWholePage
            {
                get { return (Messages.WLB_REPORT_WHOLEPAGE); }
            }
        }

        #endregion


        #region Public Methods

        /// <summary>
        /// Run report
        /// </summary>
        public void ExecuteReport()
        {
            try
            {
                // Make sure the pool is okay
                if (!Pool.Connection.IsConnected)
                {
                    PoolConnectionLost(this, EventArgs.Empty);
                }
                else if (StartDatePicker.Value.CompareTo(EndDatePicker.Value) > 0)
                {
                    using (var dlg = new ThreeButtonDialog(
                       new ThreeButtonDialog.Details(
                           SystemIcons.Warning,
                           Messages.WLB_REPORT_DATE_ORDERING_MESSAGE,
                           Messages.WLB_REPORT_DATE_ORDERING_CAPTION)))
                    {
                        dlg.ShowDialog(this);
                    }
                }
                else
                {

                    _bDisplayedError = false;

                    byte[] rdlBytes = Encoding.UTF8.GetBytes(_reportInfo.ReportDefinition);
                    System.IO.MemoryStream stream = new System.IO.MemoryStream(rdlBytes);

                    this.reportViewer1.LocalReport.LoadReportDefinition(stream);

                    _localReport = this.reportViewer1.LocalReport;
                    _localReport.DisplayName = _reportInfo.ReportName;

                    RunReport();

                    if (!_bDisplayedError)
                        this.reportViewer1.RefreshReport();

                    this.btnSubscribe.Enabled = true;
                }
            }
            catch (Exception ex)
            {
                log.Debug(ex, ex);
                using (var dlg = new ThreeButtonDialog(
                   new ThreeButtonDialog.Details(
                       SystemIcons.Error,
                       ex.Message,
                       Messages.XENCENTER)))
                {
                    dlg.ShowDialog(this);
                }
            }
        }


        /// <summary>
        /// Reset reportViewer after reportInfo is changed
        /// </summary>
        /// <param name="reportInfo">ReportInfo instance</param>
        public void SynchReportViewer(WlbReportInfo reportInfo)
        {
            if(reportInfo.ReportFile.StartsWith("pool_audit_history"))
            {
                _isAuditReport = true;
                InitializeAuditReport();
            }
            else
            {
                _isAuditReport = false;
            }

            this.btnLaterReport.Visible = false;
            this.ViewerReportInfo = reportInfo;

            if (ResetReportViewer == true)
                this.reportViewer1.Reset();

            ResetReportViewer = true;

            // Enable the run and disable subscribe buttons 
            this.btnRunReport.Enabled = true;
            this.btnLaterReport.Enabled = false;
            this.btnSubscribe.Enabled = false;

            // Set the run button text
            this.btnRunReport.Text = Messages.RUN_REPORT;

            // If host is a parameter for the selected report, show it
            if (reportInfo.DisplayHosts == true)
            {
                // Some serious hackage to get the correct host selected in the dropdown if the
                // parameter is being forced through other means (subreport or drillthrough)                      
                if (this.ViewerLocalReport != null)
                {
                    string currentHostID;

                    for (int i=0; i < this.ViewerLocalReport.OriginalParametersToDrillthrough.Count; i++)
                    {                         
                        if (this.ViewerLocalReport.OriginalParametersToDrillthrough[i].Name == "HostID")
                        {    
                            currentHostID = this.ViewerLocalReport.OriginalParametersToDrillthrough[i].Values[0];

                            for (int j = 0; j < this.hostComboBox.Items.Count; j++)
                            {
                                if (((Host)this.hostComboBox.Items[j]).uuid == currentHostID)
                                {
                                    this.hostComboBox.SelectedIndex = j;
                                    break;
                                }
                                    
                            }
                        }
                    }
                }

                // If none of the above worked out, we set it here                    
                if ((this.hostComboBox.SelectedIndex < 0) && (this.hostComboBox.Items.Count > 0))
                    this.hostComboBox.SelectedIndex = 0;

                // Set control items accordingly
                this.panelHosts.Visible = true;
            }
            else
            {
                // Host dropdown does not need to be displayed
                this.panelHosts.Visible = false;
            }

            if (reportInfo.DisplayFilter)
            {
                this.panelShow.Visible = true;
                SetViewComboBox(reportInfo.ReportFile);
                this.comboBoxView.SelectedIndex = 0;
            }
            else
            {
                this.panelShow.Visible = false;
            }


            if (reportInfo.DisplayUsers)
            {
                // User dropdown needs to be displayed
                this.panelUsers.Visible = true;
                if(!_userComboSet)
                {
                    // Fill user dropdown with user list retrieved from WLB server
                    string audit_users_string = reportInfo.ReportQueryParameterNames["AuditUser"].ToString();
                    string[] audit_users = audit_users_string.Length > 0 ? audit_users_string.Split(',') : (new string[0]);
                    Array.Sort(audit_users, StringComparer.InvariantCulture);
                    this.SetUserComboBox(audit_users);
                    _userComboSet = true;
                }

            }
            else
            {
                // Users dropdown does not need to be displayed
                this.panelUsers.Visible = false;
            }


            if (reportInfo.DisplayAuditObjects)
            {
                // Object dropdown needs to be displayed
                this.panelObjects.Visible = true;
                if(!_objectComboSet)
                {
                    // Fill object dropdown with object list retrieved from WLB server
                    string audit_objects_string = reportInfo.ReportQueryParameterNames["AuditObject"].ToString();
                    string[] audit_objects = audit_objects_string.Length > 0 ? audit_objects_string.Split(',') : (new string[0]);
                    Array.Sort(audit_objects, StringComparer.InvariantCulture);
                    this.SetObjectComboBox(audit_objects);
                    _objectComboSet = true;
                }

            }
            else
            {
                // Objects dropdown does not need to be displayed
                this.panelObjects.Visible = false;
            }


            this.Visible = true;
        }
        #endregion


        #region Private Methods

        /// <summary>
        /// Populates and configures date picker values
        /// </summary>
        private void SetPickerDateValues()
        {

            DateTime dt = DateTime.Now;
            EndDatePicker.Value = dt;

            dt = dt.AddDays(-6);
            StartDatePicker.Value = dt;

            StartDatePicker.Format = DateTimePickerFormat.Custom; // DateTimePickerFormat.Short;
            StartDatePicker.CustomFormat = Messages.DATEFORMAT_DMY; //"dd-MMM-yyyy";
            EndDatePicker.Format = DateTimePickerFormat.Custom; //.Short;
            EndDatePicker.CustomFormat = Messages.DATEFORMAT_DMY;
        }


        /// <summary>
        /// Populates the hosts drop down with hosts from the current pool
        /// </summary>        
        private void SetHostComboBox()
        {
            if (_hosts != null)
            {
                foreach (Host host in _hosts)
                {
                    hostComboBox.Items.Add(host);
                }
            }

            hostComboBox.Sorted = true;
        }

        /// <summary>
        /// Populates the users drop down with users retrieved from WLB server
        /// </summary>
        private void SetUserComboBox(string[] _users)
        {
            if (_users != null)
            {
                // Add ALL in dropdown to represent all users
                userComboBox.Items.Add(Messages.WLB_AUDIT_LOG_USER_OBJECT_ALL);

                foreach (string user in _users)
                {
                    userComboBox.Items.Add(user);
                }
            }

            userComboBox.SelectedIndex = 0;
        }

        /// <summary>
        /// Populates the objects drop down with objects retrieved from WLB server
        /// </summary>
        private void SetObjectComboBox(string[] _objects)
        {
            if (_objects != null)
            {
                // Add ALL in dropdown to represent all objects
                objectComboBox.Items.Add(Messages.WLB_AUDIT_LOG_USER_OBJECT_ALL);

                foreach (string auditObject in _objects)
                {
                    objectComboBox.Items.Add(auditObject);
                }
            }

            objectComboBox.SelectedIndex = 0;
        }

        /// <summary>
        /// Populates the hosts drop down with hosts from the current pool
        /// </summary>        
        private void SetViewComboBox(string reportFile)
        {
            this.comboBoxView.Items.Clear();

            if(_isAuditReport)
            {
                this.comboBoxView.Items.Add(Messages.WLB_REPORT_VIEW_BASIC);
                this.comboBoxView.Items.Add(Messages.WLB_REPORT_VIEW_VERBOSE);
            }
            else
            {
                this.comboBoxView.Items.Add(Messages.WLB_REPORT_VIEW_ALL);
                this.comboBoxView.Items.Add(Messages.WLB_REPORT_VIEW_CUSTOM);
            }
        }


        /// <summary>
        /// Sets the local report parameters, post-query.
        /// </summary>
        private void SetReportParameters()
        {
            try
            {
                ReportParameterInfoCollection currentParams = _localReport.GetParameters();
                ReportParameter rpCurrentParam;
                string paramValue = String.Empty;
                bool addParam = false;
                if (this._reportParameters == null)
                    this._reportParameters = new Dictionary<string, string>();
                else
                    this._reportParameters.Clear();

                foreach (ReportParameterInfo rp in currentParams)
                {
                    addParam = false;
                    switch (rp.Name)
                    {
                        case "LocaleCode":
                            paramValue = currentParams["LocaleCode"].Values.Count == 0 ? Program.CurrentLanguage : currentParams["LocaleCode"].Values[0];
                            addParam = true; 
                            break;

                        case "Start":
                            paramValue = currentParams["Start"].Values.Count == 0 ? GetDateOffset(HelpersGUI.DateTimeToString(StartDatePicker.Value, Messages.DATEFORMAT_DMY, false)) : currentParams["Start"].Values[0];
                            addParam = true;
                            break;

                        case "End":
                            paramValue = currentParams["End"].Values.Count == 0 ? GetDateOffset(HelpersGUI.DateTimeToString(EndDatePicker.Value, Messages.DATEFORMAT_DMY, false)) : currentParams["End"].Values[0];    
                            addParam = true;
                            break;

                        case "StartTime":
                            paramValue = currentParams["StartTime"].Values.Count == 0 ? GetDateOffset(HelpersGUI.DateTimeToString(StartDatePicker.Value, Messages.DATEFORMAT_DMY, false)) : currentParams["StartTime"].Values[0];
                            // For audit report enhancement, need to set time in seconds
                            if(String.IsNullOrEmpty(_startTime))
                            {
                                int offSet = Convert.ToInt32(paramValue);
                                // One day is 86400000 milliseconds or 86400 seconds
                                // Set start time as 00:00:00 of the day
                                paramValue = ((Convert.ToInt64((DateTime.UtcNow - new DateTime(1970, 1, 1)).TotalMilliseconds) / 86400000 + offSet) * 86400).ToString();
                                _startTime = paramValue;                                    
                            }
                            else
                            {
                                // To retrieve more report of pool audit trail,
                                // use the already set _startTime
                                paramValue = _startTime;
                            }

                            addParam = true;
                            break;

                        case "EndTime":
                            paramValue = currentParams["EndTime"].Values.Count == 0 ? GetDateOffset(HelpersGUI.DateTimeToString(EndDatePicker.Value, Messages.DATEFORMAT_DMY, false)) : currentParams["EndTime"].Values[0];    
                            // For audit report enhancement, need to set time in seconds
                            if(String.IsNullOrEmpty(_endTime))
                            {
                                if(paramValue == "0")
                                {
                                    // If today is selected, set the current time in seconds
                                    paramValue = Convert.ToInt64(((DateTime.UtcNow - new DateTime(1970, 1, 1)).TotalMilliseconds) / 1000).ToString();
                                }
                                else
                                {
                                    int offSet = Convert.ToInt32(paramValue) + 1;
                                    // One day is 86400000 milliseconds or 86400 seconds
                                    // Set end time as 23:59:59 of the day
                                    paramValue = (((Convert.ToInt64((DateTime.UtcNow - new DateTime(1970, 1, 1)).TotalMilliseconds) / 86400000 + offSet) * 86400) - 1).ToString();
                                }
                                _endTime = paramValue;

                            }
                            else
                            {
                                // To retrieve more report of pool audit trail,
                                // use the already set _endTime
                                paramValue = _endTime;
                            }

                            addParam = true;
                            break;

                        case "GroupBy1":
                            paramValue = currentParams["GroupBy1"].Values.Count == 0 ? "day" : currentParams["GroupBy1"].Values[0];
                            addParam = true;
                            break;

                        case "TopN":
                            paramValue = currentParams["TopN"].Values.Count == 0 ? "100000" : currentParams["TopN"].Values[0];
                            addParam = true;
                            break;

                        case "PoolID":
                            paramValue = currentParams["PoolID"].Values.Count == 0 ? Pool.uuid : currentParams["PoolID"].Values[0];
                            addParam = true;
                            break;

                        case "PoolName":
                            paramValue = currentParams["PoolName"].Values.Count == 0 ? Helpers.GetName(Pool) : currentParams["PoolName"].Values[0];
                            addParam = true;
                            break;

                        case "HostID":
                            paramValue = currentParams["HostID"].Values.Count == 0 ? ((Host)hostComboBox.SelectedItem).uuid : currentParams["HostID"].Values[0];
                            addParam = true;
                            break;

                        case "HostName":
                            paramValue = currentParams["HostName"].Values.Count == 0 ? ((Host)hostComboBox.SelectedItem).name_label : currentParams["HostName"].Values[0];
                            addParam = true;
                            break;

                        case "Filter":
                            paramValue = currentParams["Filter"].Values.Count == 0 ?
                                (_selectedCustomFilters != null && _selectedCustomFilters.Count > 0 ? String.Join(DELIMITER, _selectedCustomFilters.ToArray()) : comboBoxView.SelectedIndex.ToString()) : 
                                currentParams["Filter"].Values[0];
                            addParam = true;
                            break;

                        case "UTCOffset":
                            paramValue = currentParams["UTCOffset"].Values.Count == 0 ? _currentOffsetMinutes.ToString(): currentParams["UTCOffset"].Values[0];
                            addParam = true;
                            break;

                        case "AuditUser":
                            if (userComboBox.SelectedIndex == 0)
                            {
                                // The first item is ALL in localized characters,
                                // set it as "ALL" so WLB server could recognize.
                                paramValue = "ALL";
                            }
                            else
                            {
                                paramValue = currentParams["AuditUser"].Values.Count == 0 ? userComboBox.SelectedItem.ToString(): currentParams["AuditUser"].Values[0];
                            }
                            addParam = true;
                            break;

                        case "AuditObject":
                            if(objectComboBox.SelectedIndex == 0)
                            {
                                // The first item is ALL in localized characters,
                                // set it as "ALL" so WLB server could recognize.
                                paramValue = "ALL";
                            }
                            else
                            {
                                paramValue = currentParams["AuditObject"].Values.Count == 0 ? objectComboBox.SelectedItem.ToString(): currentParams["AuditObject"].Values[0];
                            }
                            addParam = true;
                            break;

                        case "StartLine":
                            paramValue = _startLine.ToString();
                            addParam = true;
                            break;

                        case "EndLine":
                            paramValue = _endLine.ToString();
                            addParam = true;
                            break;

                        case "ReportVersion":
                            paramValue = "Creedence";
                            addParam = true;
                            break;

                    }
                    if (addParam)
                    {
                        rpCurrentParam = new ReportParameter(rp.Name, paramValue);
                        _localReport.SetParameters(new Microsoft.Reporting.WinForms.ReportParameter[] { rpCurrentParam });
                        _reportParameters.Add(rp.Name, paramValue);
                    }
                }
            }
            catch(LocalProcessingException ex)
            {
                log.Debug(ex, ex);
                throw new Exception(String.Format(Messages.WLB_REPORT_SET_PARAMS, ex.InnerException.InnerException.Message));
            }
            catch (Exception ex)
            {
                log.Debug(ex, ex);
                throw new Exception(String.Format(Messages.WLB_REPORT_SET_PARAMS, ex.Message));
            }
        }


        /// <summary>
        /// Sets the date offset to an integer for UTC offset handling
        /// </summary>
        /// <param name="dateValue"></param>
        /// <returns>string representing the offset from the current date</returns>
        private string GetDateOffset(string dateValue)
        {
            DateTime passedDate = DateTime.Parse(dateValue, CultureInfo.InvariantCulture);
            TimeSpan diff = passedDate - DateTime.Today;
            int diffDays = diff.Days;
            return diffDays.ToString();

        }


        /// <summary>
        /// Invokes and executes a call to the Kirkwood database via Xapi to obtain report data.
        /// </summary>
        /// <param name="reportKey"></param>
        /// <param name="currentParams"></param>
        /// <returns></returns>
        private string GetReportData(string reportKey, ReportParameterInfoCollection currentParams)
        {
            string returnValue = string.Empty;
            List<string> reportQueryParams;

            reportQueryParams = new List<String>();
            ICollection keyCollections = _reportInfo.ReportQueryParameterNames.Keys;
            int cnt = _reportInfo.ReportQueryParameterNames.Count;
            String[] paramKeys = new String[cnt];
            keyCollections.CopyTo(paramKeys, 0);
            
            for (int i = 0; i <cnt; i++)
            {
                reportQueryParams.Add(paramKeys[i]);
            }

            reportQueryParams.Add("UTCOffset");
            reportQueryParams.Add("LocaleCode");

            Dictionary<string, string> parms = new Dictionary<string, string>();

            for (int i = 0; i < reportQueryParams.Count; i++)
            {
                parms[reportQueryParams[i].ToString()] = currentParams[reportQueryParams[i].ToString()].Values[0].ToString();
            }

            AsyncAction a = new WlbReportAction(Pool.Connection, 
                                                Helpers.GetMaster(Pool.Connection),
                                                reportKey, 
                                                _reportInfo.ReportName, 
                                                false,
                                                parms);
            using (var dlg = new ActionProgressDialog(a, ProgressBarStyle.Marquee))
                dlg.ShowDialog();

            if (a.Succeeded)
            {
                returnValue = a.Result;
            }
            else
            {
                _bDisplayedError = true;
            }

            return returnValue;

        }


        /// <summary>
        /// Responsible for marshalling the string data returned back from Xapi->Kirkwood into XML and 
        /// then into a dataset object.  Once the dataset is obtained, set the rdlc path and then bind a local
        /// datasource to the datasource container within the rdlc. 
        /// </summary>
        private void PopulateReportData()
        {
            string reportLabelNames = "None";
            string reportLabelValues = "None";
            string reportKey = _reportInfo.ReportFile.Replace(".rdlc", "");

            DataSet reportDS = new DataSet();

            string xmlData = GetReportData(reportKey, _localReport.GetParameters());

            try
            {
                if ((!String.IsNullOrEmpty(xmlData)) && (!_bDisplayedError))
                {

                    // Read the XML document into the DataSet.  
                    System.IO.StringReader xmlSR = new System.IO.StringReader(xmlData);
                    reportDS.ReadXml(xmlSR, XmlReadMode.ReadSchema);
                    xmlSR.Close();

                    // Create a Data Source and add it to reportviewer.  This is to allow the RDLC fields to bind
                    ReportDataSource reportDataSource1 = new ReportDataSource();
                    reportDataSource1.Name = "KirkwoodDBDataSetLocal";
                    reportDataSource1.Value = reportDS.Tables[0];
                    _localReport.DataSources.Add(reportDataSource1);

                    if(_isAuditReport && IsCreedenceOrLater)
                    {
                        int cnt = reportDS.Tables[0].Rows.Count;

                        if (cnt >= _lineLimit)
                        {
                            // If audit trail report from WLB server exceeds the line limit,
                            // change the run button text to "More",
                            // display the label to indicate there's more report.

                            this.btnRunReport.Text = Messages.FETCH_EARLIER_DATA;
                            this.btnRunReport.Enabled = true;

                        }
                        else
                        {
                            // If audit trail report from WLB server doesn't exceed the line limit,
                            // and this is the first section of report,
                            // change the run button text back to "Run Report",
                            // or disable the run report button and just keep the later report button.
                            if(btnLaterReport.Visible)
                            {
                                this.btnRunReport.Enabled = false;
                            }
                            else
                            {
                                this.btnRunReport.Text = Messages.RUN_REPORT;
                            }
                            
                        }

                        if(_currentReportSection > 1)
                        {
                            this.btnLaterReport.Visible = true;
                            this.btnLaterReport.Enabled = true;
                            if (!this.btnRunReport.Enabled)
                            {
                                this.btnLaterReport.Select();
                            }
                        }
                        else if (_currentReportSection == 1 && 
                                 this.btnRunReport.Text == Messages.FETCH_EARLIER_DATA)
                        {
                            this.btnLaterReport.Visible = true;
                            this.btnLaterReport.Enabled = false;                            
                            this.btnRunReport.Select();
                        }
                        else
                        {
                            this.btnLaterReport.Visible = false;
                            this.btnLaterReport.Enabled = false;
                        }
                    }
                    

                    // Set the report label names and values
                    if (reportDS.Tables[1].Rows.Count > 0)
                    {
                        DataRow dr = reportDS.Tables[1].Rows[0];
                        reportLabelNames = dr["name"].ToString();
                        reportLabelValues = dr["description"].ToString();
                    }

                    PopulateReportLabelData(reportLabelNames, reportLabelValues);
                }
            }
            catch (Exception ex)
            {
                log.Debug(ex, ex);
                throw new Exception(String.Format(Messages.WLB_REPORT_BIND_DATASOURCE, ex.Message));
            }
        }


        /// <summary>
        /// Jams labels and values into two separate parameters that is extracted programatically within 
        /// the rdlc code block.
        /// </summary>
        /// <param name="reportLabelNames"></param>
        /// <param name="reportLabelValues"></param>
        private void PopulateReportLabelData(string reportLabelNames, string reportLabelValues)
        {
            try
            {
                // Set the parameter values
                Microsoft.Reporting.WinForms.ReportParameter rpParamLabels = new Microsoft.Reporting.WinForms.ReportParameter("ParamLabels", reportLabelNames);
                Microsoft.Reporting.WinForms.ReportParameter rpParamValues = new Microsoft.Reporting.WinForms.ReportParameter("ParamValues", reportLabelValues);

                // Add report parameters array
                _localReport.SetParameters(new Microsoft.Reporting.WinForms.ReportParameter[] { 
                    rpParamLabels,
                    rpParamValues});
            }
            catch (Exception ex)
            {
                log.Debug(ex, ex);
                throw new Exception(String.Format(Messages.WLB_REPORT_ERROR_LOCALIZED_PARAMS, ex.Message));
            }
        }


        /// <summary>
        /// Performs common report execution steps such as populating datasets, labels and defaults
        /// </summary>
        private void RunReport()
        {
            try
            {
                // Event handler for SubreportProcessing
                _localReport.SubreportProcessing += new SubreportProcessingEventHandler(reportViewer1SubReportEventHandler);

                // Set the parameters
                SetReportParameters();

                // Bind the report to a datasource and set label values
                PopulateReportData();

                // Go ahead and show the toolbar now that a report has been executed
                CCustomMessageClass customMessages = new CCustomMessageClass();
                this.reportViewer1.Messages = customMessages;

                this.reportViewer1.ShowToolBar = true;

            }
            catch (Exception ex)
            {
                log.Debug(ex, ex);
                throw new Exception(ex.Message);
            }
        }

        #endregion


        #region Event Handler

        /// <summary>
        /// Clean up tool tip for Host combobox
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void comboBox_DropDownClosed(object sender, EventArgs e)
        {
            toolTip1.Hide(this);
        }
        /// <summary>
        /// Owner Draw for Host combobox, showing tooltips.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void comboBox_DrawItem(object sender, DrawItemEventArgs e)
        {
            if (sender is ComboBox)
            {
                ComboBox thisComboBox = (ComboBox)sender;

                //CA-85278: XenCenter/WLB | XenCenter error when click on Pool Audit Trail report
                //  Be sure we have a valid item index
                if ((e.Index > -1) &&
                    (thisComboBox.Items.Count > e.Index))
                {
                    string text = thisComboBox.GetItemText(thisComboBox.Items[e.Index]);
                    e.DrawBackground();
                    using (SolidBrush br = new SolidBrush(e.ForeColor))
                    {
                        e.Graphics.DrawString(text, e.Font, br, e.Bounds);
                    }
                    if ((e.State & DrawItemState.Selected) == DrawItemState.Selected && thisComboBox.DroppedDown)
                    {
                        toolTip1.Show(text, thisComboBox, e.Bounds.Right, e.Bounds.Bottom);
                    }
                    e.DrawFocusRectangle();
                }
            }
        }

        /// <summary>
        /// Form Load
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void ReportView_Load(object sender, EventArgs e)
        {
            this.btnRunReport.Enabled = false;
            this.btnLaterReport.Enabled = false;
            this.btnSubscribe.Enabled = false;

            this.hostComboBox.DropDownStyle = ComboBoxStyle.DropDownList;

            // Hide the toolbar until a report is executed
            this.reportViewer1.ShowToolBar = false;

            SetPickerDateValues();

            // Hosts dropdown and label is invisible until we need it
            this.panelShow.Visible = false;
            this.panelHosts.Visible = false;

            // Users and Objects dropdowns and labels are invisible until we need it
            this.panelUsers.Visible = false;
            this.panelObjects.Visible = false;

            // Set UTC Offset
            TimeZone tz = TimeZone.CurrentTimeZone;
            DateTime currentDate = DateTime.Now;

            int currentOffsetHours = tz.GetUtcOffset(currentDate).Hours;
            int currentOffsetMinutes = tz.GetUtcOffset(currentDate).Minutes;
            _currentOffsetMinutes = (currentOffsetHours * 60) + (currentOffsetMinutes);
                        
        }


        /// <summary>
        /// 
        /// </summary>
        /// <param name="currentDrillthroughEventArgs"></param>
        private void OnReportDrilledThrough(DrillthroughEventArgs currentDrillthroughEventArgs)
        {
            if (ReportDrilledThrough != null)
            {
                ReportDrilledThrough(this, currentDrillthroughEventArgs);
            }
        }


        /// <summary>
        /// Event handler for the "Run Report"/"Next Section" button
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        internal void btnRunReport_Click(object sender, EventArgs e)
        {
            if(_isAuditReport && IsCreedenceOrLater)
            {
                // If the button displays "Run Report",
                // that means the 1st report section is requested.
                // Or else the button text is "Next Section",
                // next report section is requested.

                if(this.btnRunReport.Text == Messages.RUN_REPORT)
                {
                    _currentReportSection = 1;
                    _startLine = 1;
                    _endLine = _lineLimit;
                    _endTime = String.Empty;
                }
                else
                {
                    _currentReportSection += 1;
                    _startLine += _lineLimit;
                    _endLine += _lineLimit;
                }
            }
            this.reportViewer1.Reset();
            this.ExecuteReport();
        }


        /// <summary>
        /// Event handler for the "Previous Section" button
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        internal void btnLaterReport_Click(object sender, EventArgs e)
        {
            if(_isAuditReport && IsCreedenceOrLater)
            {
                // The previous report section is requested.

                _currentReportSection -= 1;
                _startLine -= _lineLimit;
                _endLine -= _lineLimit;
            }
            this.reportViewer1.Reset();
            this.ExecuteReport();
        }


        /// <summary>
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnSubscribe_Click(object sender, EventArgs e)
        {
            // Make sure the pool is okay
            if (!Pool.Connection.IsConnected)
            {
                PoolConnectionLost(this, EventArgs.Empty);
            }
            else
            {
                if (this._reportParameters.ContainsKey("reportName"))
                {
                    this._reportParameters.Remove("reportName");
                }
                this._reportParameters.Add("reportName", this._reportInfo.ReportFile.Split('.')[0]);
                WlbReportSubscriptionDialog rpSubDialog = new WlbReportSubscriptionDialog(this._reportInfo.ReportName, this._reportParameters, Pool);
                if (rpSubDialog.ShowDialog() == DialogResult.OK)
                {
                    OnChangeOK(this, e);
                }
            }
        }


        /// <summary>
        /// Handles the render subreport event
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void reportViewer1SubReportEventHandler(object sender, SubreportProcessingEventArgs e)
        {
            string reportPath = e.ReportPath.Remove(0, _localReport.ReportPath.LastIndexOf("\\") + 1);
        }


        /// <summary>
        /// Handles drilldown report events
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void reportViewer1_Drillthrough(object sender, DrillthroughEventArgs e)
        {

            _localReport = (LocalReport)e.Report;

            OnReportDrilledThrough(e);

            byte[] rdlBytes = Encoding.UTF8.GetBytes(_reportInfo.ReportDefinition);
            System.IO.MemoryStream stream = new System.IO.MemoryStream(rdlBytes);
            _localReport.LoadReportDefinition(stream);

            RunReport();

            if (!_bDisplayedError)
                _localReport.Refresh(); 

        }


        /// <summary>
        /// Handles back button
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void reportViewer1_Back(object sender, BackEventArgs e)
        {
            _localReport = (LocalReport)e.ParentReport;
        }


        /// <summary>
        /// Close button
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnClose_Click(object sender, EventArgs e)
        {
            if (Close != null)
            {
                Close(this, e);
            }
        }


        private void comboBoxView_SelectedIndexChanged(object sender, EventArgs e)
        {
            _selectedCustomFilters = null;

            if (this.comboBoxView.SelectedItem.ToString() == Messages.WLB_REPORT_VIEW_CUSTOM)
            {
                if (this.comboBoxView.SelectedIndex == 1)
                {
                    WlbReportCustomFilter customFilterDialog = new WlbReportCustomFilter(Pool.Connection);
                    customFilterDialog.InitializeFilterTypeIndex();
                    if (customFilterDialog.ShowDialog() == DialogResult.OK)
                    {
                        _selectedCustomFilters = customFilterDialog.GetSelectedFilters();
                        this.btnSubscribe.Enabled = false;
                        this.reportViewer1.Reset();
                        this.ExecuteReport();
                    }
                    else
                    {
                        this.comboBoxView.SelectedIndex = 0;
                    }
                }
                else
                {
                    this.btnSubscribe.Enabled = false;
                    this.reportViewer1.Reset();
                }
            }
        }

         delegate byte[] ReportExporterDelgate(string fileExtension);

        private void reportViewer1_ReportExport(object sender, ReportExportEventArgs e)
        {
            //cancel the default process
            e.Cancel = true;

            //the dropdown menu wasn't hiding itself
            //so this hack was needed to hide the menu
            //find the export button
            ToolStrip toolStrip = (ToolStrip)reportViewer1.Controls.Find("toolStrip1", true)[0];

            ToolStripDropDownButton exportButton = (ToolStripDropDownButton)toolStrip.Items["export"];
            exportButton.DropDown.Close();

            reportViewer1.Cursor = Cursors.WaitCursor;

            //and run our own code to export

            ExportReportAction action = new ExportReportAction(e.Extension.Name, ref reportViewer1);
            using (var dlg = new ActionProgressDialog(action, ProgressBarStyle.Marquee))
                dlg.ShowDialog();

            //ReportExporterDelgate exp = new ReportExporterDelgate(RunExportReport);


            //IAsyncResult result = exp.BeginInvoke(e.Extension.Name, null, null);

            ////new ActionProgressDialog(result, ProgressBarStyle.Marquee).ShowDialog();

            //result.AsyncWaitHandle.WaitOne();

            //byte[] bytes = exp.EndInvoke(result);

            reportViewer1.Cursor = Cursors.Default;

            string fileExtension = "";
            if (e.Extension.Name == "Excel")
                fileExtension = "xls";
            else if (e.Extension.Name == "PDF")
                fileExtension = "pdf";
            
            SaveFileDialog sfDialog = new SaveFileDialog();
            
            sfDialog.Filter = (fileExtension == "pdf" ? Messages.FILE_PDF + "|*.pdf|" : Messages.FILE_XLS + "|*.xls|")
                + Messages.FILE_ALL + "|*.*";

            sfDialog.AddExtension = true;
            if (sfDialog.ShowDialog() == DialogResult.OK)
            {                
                FileStream fs = null;
                try
                {
                    fs = new FileStream(sfDialog.FileName, FileMode.Create);
                    fs.Write(action.ReportData, 0, action.ReportData.Length);
                    lblExported.Text = Messages.WLBREPORT_EXPORT_SUCC;
                    lblExported.Visible = true;                    
                    timer1.Start();
                }
                catch (Exception ex)
                {
                    log.Debug(ex, ex);
                    using (var dlg = new ThreeButtonDialog(
                       new ThreeButtonDialog.Details(
                           SystemIcons.Error,
                           ex.Message,
                           Messages.XENCENTER)))
                    {
                        dlg.ShowDialog(this);
                    }
                }
                finally
                {
                    if (fs != null)
                    {
                        fs.Close();
                        fs.Dispose();
                    }
                }
            }

            //bytes = null;
        }

        private void timer1_Tick(object sender, EventArgs e)
        {
            timer1.Stop();
            lblExported.Visible = false;
        }


        #endregion //Event Handler

        private void comboBox_SelectionChanged(object sender, EventArgs e)
        {
            if(_isAuditReport)
            {
                InitializeAuditReport();
            }
        }

        private void InitializeAuditReport()
        {
            _startTime = String.Empty;
            _endTime = String.Empty;
            _startLine = 1;
            _endLine = _lineLimit;
            _currentReportSection = 0;
            btnRunReport.Text = Messages.RUN_REPORT;
            btnRunReport.Enabled = true;
            btnLaterReport.Visible = false;
        }

    }
}
