//-----------------------------------------------------------------------
//  This file is part of the Microsoft Code Samples.
// 
//  Copyright (C) Microsoft Corporation.  All rights reserved.
// 
//This source code is intended only as a supplement to Microsoft
//Development Tools and/or on-line documentation.  See these other
//materials for detailed information regarding Microsoft code samples.
// 
//THIS CODE AND INFORMATION ARE PROVIDED AS IS WITHOUT WARRANTY OF ANY
//KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
//IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
//PARTICULAR PURPOSE.
//-----------------------------------------------------------------------

using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using Microsoft.SqlServer.Management.Smo;
using Microsoft.SqlServer.NotificationServices.Rules;
using System.Drawing;

namespace RulesControls
{
    // A control allowing the interactive construction of a "SimpleLeafCondition" of the
    // form "Field op Value". This control's parent context is "TableViewBase", the "InputType"
    // for the rule.
    public class SimpleLeafConditionControl : RulesUserControl<TableViewBase>
    {
        // Default constructor
        public SimpleLeafConditionControl()
            : base()
        {
            int x = ComponentMargin;

            this.SuspendLayout();

            this.columns = new ColumnChooser();
            this.operators = new ComboBox();
            this.parameter = new TextBox();

            // this
            this.Size = new Size(MinimumWidth, FixedHeight);
            this.MinimumSize = this.Size;
            this.MaximumSize = new Size(Int16.MaxValue, FixedHeight);
            this.Controls.Add(this.columns);
            this.Controls.Add(this.operators);
            this.Controls.Add(this.parameter);

            // column
            this.columns.Size = new Size(ColumnChooserWidth, ComponentHeight);
            this.columns.Location = new Point(x, ComponentMargin);
            x += ComponentMargin + ColumnChooserWidth;
            this.columns.Anchor = AnchorStyles.Left | AnchorStyles.Top;

            // operators
            this.operators.Size = new Size(OperatorChooserWidth, ComponentHeight);
            this.operators.Location = new Point(x, ComponentMargin);
            x += ComponentMargin + OperatorChooserWidth;
            this.operators.Anchor = AnchorStyles.Left | AnchorStyles.Top;
            this.PopulateOperators();
            this.operators.SelectedIndex = 0;

            // parameter
            this.parameter.Size = new Size(Width - x - ComponentMargin, ComponentHeight);
            this.parameter.Location = new Point(x, ComponentMargin);
            this.parameter.Anchor = AnchorStyles.Left | AnchorStyles.Top | AnchorStyles.Right;

            this.ResumeLayout();
        }

        // Gets the condition built using this control. The condition has the form "Column operator Parameter"
        public Condition Condition
        {
            get
            {
                SimpleLeafCondition condition = new SimpleLeafCondition();
                Column column = this.columns.Selected;

                if (null != column)
                {
                    condition.Left = new FieldValue(column.Name);
                }

                condition.Operator =
                    Operators[this.operators.Items[this.operators.SelectedIndex] as String];

                // parse the text according to the data type of the column
                if (null != column)
                {
                    try
                    {
                        bool parseSucceeded = false;
                        long longValue;
                        decimal decimalValue;
                        DateTime dateTimeValue;
                        switch (column.DataType.SqlDataType)
                        {
                            case SqlDataType.BigInt:
                            case SqlDataType.Int:
                            case SqlDataType.SmallInt:
                            case SqlDataType.TinyInt:
                                parseSucceeded = Int64.TryParse(this.parameter.Text, out longValue);
                                if (parseSucceeded)
                                {
                                    condition.Right = longValue;
                                }
                                break;
                            case SqlDataType.SmallMoney:
                            case SqlDataType.Money:
                            case SqlDataType.Decimal:
                            case SqlDataType.Float:
                            case SqlDataType.Real:
                                parseSucceeded = Decimal.TryParse(this.parameter.Text, out decimalValue);
                                if (parseSucceeded)
                                {

                                    condition.Right = decimalValue;
                                }
                                break;
                            case SqlDataType.DateTime:
                            case SqlDataType.SmallDateTime:
                                parseSucceeded = DateTime.TryParse(this.parameter.Text, out dateTimeValue);
                                if (parseSucceeded)
                                {
                                    condition.Right = dateTimeValue;
                                }
                                break;
                            default:
                                break;
                        }
                        if (!parseSucceeded)
                        {
                            condition.Right = new ConstantValue(this.parameter.Text);
                        }
                    }
                    catch
                    {
                        string message = String.Format(
                            "An error occurred while parsing the value '{0}'. It may not be a value of type {1}.",
                            this.parameter.Text,
                            column.DataType.SqlDataType);
                        MessageBox.Show(
                            message,
                            "Value parse error",
                            MessageBoxButtons.OK,
                            MessageBoxIcon.Exclamation);
                    }
                }

                return condition;
            }
        }

        // Adds all "SimpleLeafOperators" supported by this control.
        private void PopulateOperators()
        {
            foreach (string op in Operators.Keys)
            {
                this.operators.Items.Add(op);
            }
        }

        // Gets a dictionary mapping from UI operator descriptions to "SimpleLeafOperators".
        static public Dictionary<string, SimpleOperator> Operators
        {
            get
            {
                if (null == rulesOperators)
                {
                    Dictionary<string, SimpleOperator> temp =
                        new Dictionary<string, SimpleOperator>();
                    temp["="] = SimpleOperator.Equals;
                    temp[">"] = SimpleOperator.GreaterThan;
                    temp["<"] = SimpleOperator.LessThan;
                    temp[">="] = SimpleOperator.GreaterThanOrEqualTo;
                    temp["<="] = SimpleOperator.LessThanOrEqualTo;
                    temp["LIKE"] = SimpleOperator.Like;
                    temp["<>"] = SimpleOperator.NotEquals;
                    rulesOperators = temp;
                }
                return rulesOperators;
            }
        }

        protected override void UpdateParentContext()
        {
            this.columns.ParentContext = this.ParentContext;
        }

        private ColumnChooser columns;
        private ComboBox operators;
        private TextBox parameter;
        static private Dictionary<string, SimpleOperator> rulesOperators;

        internal const int MinimumWidth = 600;
        internal const int FixedHeight = ComponentHeight + 2 * ComponentMargin;
        internal const int ComponentHeight = 21;
        internal const int ComponentMargin = 3;
        internal const int ColumnChooserWidth = 194;
        internal const int OperatorChooserWidth = 94;
    }
}
