UserControls/CustomerIndividualEditControl.cs

using ChatworkBulkSender.Dtos;
using ChatworkBulkSender.Utils;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using ChatworkBulkSender.Services.Chatwork;

namespace ChatworkBulkSender.UserControls
{
    public partial class CustomerIndividualEditControl : UserControl
    {
        // エラー表示用ツールチップ
        private ToolTip errorToolTip = new ToolTip();
        
        public CustomerIndividualEditControl(CustomerMasterDto customer = null)
        {
            InitializeComponent();
            
            // イベントハンドラの設定
            txtMgmtNumber.KeyPress += TxtMgmtNumber_KeyPress;
            txtMgmtNumber.TextChanged += TxtMgmtNumber_TextChanged;
            txtSortOrder.KeyPress += TxtSortOrder_KeyPress;
            txtSortOrder.TextChanged += TxtSortOrder_TextChanged;
            
            if (customer != null)
            {
                LoadCustomerDataToControls(customer);              
                
            }
        }
        private void LoadCustomerDataToControls(CustomerMasterDto customer)
        {
            txtMgmtNumber.Text = customer.ManagementNumber.ToString();
            txtMgmtNumber.ReadOnly = true;
            txtCustomerName.Text = customer.CustomerName;
            txtRoomId.Text = customer.RoomId;
            txtDestinationAccountId.Text = customer.DestinationAccountId;
            txtSortOrder.Text = customer.SortOrder.ToString();
            chkUnusedData.Checked = customer.IsUnused;
        }

        public CustomerMasterDto GetCustomerData()
        {
            var newCustomer = new CustomerMasterDto
            {
                ManagementNumber = int.Parse(txtMgmtNumber.Text),
                CustomerName = txtCustomerName.Text,
                RoomId = txtRoomId.Text,
                DestinationAccountId = txtDestinationAccountId.Text,
                SortOrder = int.Parse(txtSortOrder.Text),
                CreatedAt = DateTime.Now,
                CreatedBy = Environment.MachineName
                ,
            };

            return newCustomer;
        }
        
        /// <summary>
        /// 顧客データを画面に設定する
        /// </summary>
        public void SetCustomerData(CustomerMasterDto customer)
        {
            if (customer == null) return;
            
            txtMgmtNumber.Text = customer.ManagementNumber.ToString();
            txtCustomerName.Text = customer.CustomerName;
            txtRoomId.Text = customer.RoomId;
            txtDestinationAccountId.Text = customer.DestinationAccountId;
            txtSortOrder.Text = customer.SortOrder.ToString();
            chkUnusedData.Checked = customer.IsUnused;
        }

        public bool ValidateInput_MgmtNumber(out string errorMessage)
        {
            errorMessage = string.Empty;

            var errors = new List<string>();

            // 管理番号
            if (string.IsNullOrWhiteSpace(txtMgmtNumber.Text))
            {
                errors.Add("管理番号を入力してください。");
            }
            else if (!ValidationHelperUtil.IsValidManagementNumber(txtMgmtNumber.Text))
            {
                errors.Add(ValidationHelperUtil.GetManagementNumberFormatErrorMessage());
            }

            if (errors.Any())
            {
                errorMessage = string.Join("\n",errors);
                return false;
            }

            return true;
        }

        public bool ValidateInput_CustomerName(out string errorMessage)
        {
            errorMessage = string.Empty;

            var errors = new List<string>();

            // 顧客名
            if (string.IsNullOrWhiteSpace(txtCustomerName.Text))
            {
                errors.Add("顧客名を入力してください。");
            }
            // 文字数制限
            else if (txtCustomerName.TextLength > Constants.CUSTOMER_NAME_MAX_LENGTH)
            {
                errors.Add(ValidationHelperUtil.GetLengthErrorMessage("顧客名",txtCustomerName.TextLength,Constants.CUSTOMER_NAME_MAX_LENGTH));
            }

            if (errors.Any())
            {
                errorMessage = string.Join("\n", errors);
                return false;
            }

            return true;
        }

        public async Task<(bool isValid, string errorMessage)> ValidateInput_RoomIdAsync()
        {
            var errors = new List<string>();

            if (string.IsNullOrWhiteSpace(txtRoomId.Text))
            {
                errors.Add("ルームIDを入力してください。");
            }
            else if (txtRoomId.TextLength > Constants.ROOM_ID_MAX_LENGTH)
            {
                errors.Add(ValidationHelperUtil.GetLengthErrorMessage("ルームID", txtRoomId.TextLength, Constants.ROOM_ID_MAX_LENGTH));
            }
            else if (!ValidationHelperUtil.IsValidRoomId(txtRoomId.Text))
            {
                errors.Add(ValidationHelperUtil.GetRoomIdFormatErrorMessage("ルームID"));
            }
            else
            {
                bool roomExists = await new ChatworkService().IsRoomExistsAsync(txtRoomId.Text);

                if (!roomExists)
                {
                    errors.Add("指定されたルームIDが存在しません。");
                }
            }

            string errorMessage = string.Join("\n", errors);

            // 検証結果(成功フラグ、エラーメッセージ)を返す
            return (!errors.Any(), errorMessage);
        }

        public async Task<(bool isValid, string errorMessage)> ValidateInput_DestinationAccountId()
        {
            var errors = new List<string>();

            if (string.IsNullOrWhiteSpace(txtDestinationAccountId.Text))
            {
                errors.Add("宛先アカウントIDを入力してください。");
            }

            else
            {
                var resultRoomExists = await ValidateInput_RoomIdAsync();

                if (resultRoomExists.isValid)
                {
                    bool accountExists = await new ChatworkService().IsAccountInRoomAsync(txtRoomId.Text,txtDestinationAccountId.Text);

                    if (!accountExists)
                    {
                        errors.Add("指定されたアカウントはルームIDの参加者ではありません。");
                    }
                }

            }

            string errorMessage = string.Join("\n", errors);

            // 検証結果(成功フラグ、エラーメッセージ)を返す
            return (!errors.Any(), errorMessage);

        }

        public bool ValidateInput_SortOrder(out string errorMessage)
        {
            errorMessage = string.Empty;

            var errors = new List<string>();

            // 並び順
            if (string.IsNullOrWhiteSpace(txtSortOrder.Text))
            {
                errors.Add("並び順を入力してください。");
            }
            else if (!ValidationHelperUtil.IsValidSortOrder(txtSortOrder.Text))
            {
                errors.Add(ValidationHelperUtil.GetSortOrderFormatErrorMessage());
            }

            if (errors.Any())
            {
                errorMessage = string.Join("\n", errors);
                return false;
            }

            return true;
        }

        /// <summary>
        /// 管理番号テキストボックスのKeyPressイベントハンドラ
        /// </summary>
        private void TxtMgmtNumber_KeyPress(object sender, KeyPressEventArgs e)
        {
            // バックスペース、Delete、Ctrl+V は許可
            if (e.KeyChar == '\b' || char.IsControl(e.KeyChar))
            {
                return;
            }

            // 数字以外の入力時
            if (!char.IsDigit(e.KeyChar))
            {
                e.Handled = true;
                
                // ツールチップでエラーメッセージを表示
                errorToolTip.Show("半角数字のみ入力可能です", txtMgmtNumber, 0, -25, 2000);
            }
        }

        /// <summary>
        /// 管理番号テキストボックスのTextChangedイベントハンドラ
        /// </summary>
        private void TxtMgmtNumber_TextChanged(object sender, EventArgs e)
        {
            // 貼り付けられた場合のチェック
            if (!string.IsNullOrWhiteSpace(txtMgmtNumber.Text))
            {
                if (!ValidationHelperUtil.IsValidManagementNumber(txtMgmtNumber.Text))
                {
                    // 背景色を薄い赤にして視覚的にエラーを示す
                    txtMgmtNumber.BackColor = Color.FromArgb(255, 230, 230);
                    errorToolTip.Show(ValidationHelperUtil.GetManagementNumberFormatErrorMessage(), 
                        txtMgmtNumber, 0, -25, 3000);
                }
                else
                {
                    // 正常な場合は背景色を元に戻す
                    txtMgmtNumber.BackColor = SystemColors.Window;
                    errorToolTip.Hide(txtMgmtNumber);
                }
            }
            else
            {
                // 空の場合も背景色を元に戻す
                txtMgmtNumber.BackColor = SystemColors.Window;
                errorToolTip.Hide(txtMgmtNumber);
            }
        }

        /// <summary>
        /// 並び順テキストボックスのKeyPressイベントハンドラ
        /// </summary>
        private void TxtSortOrder_KeyPress(object sender, KeyPressEventArgs e)
        {
            // バックスペース、Delete、Ctrl+V は許可
            if (e.KeyChar == '\b' || char.IsControl(e.KeyChar))
            {
                return;
            }

            // 数字以外の入力時
            if (!char.IsDigit(e.KeyChar))
            {
                e.Handled = true;
                
                // ツールチップでエラーメッセージを表示
                errorToolTip.Show("半角数字のみ入力可能です", txtSortOrder, 0, -25, 2000);
            }
        }

        /// <summary>
        /// 並び順テキストボックスのTextChangedイベントハンドラ
        /// </summary>
        private void TxtSortOrder_TextChanged(object sender, EventArgs e)
        {
            // 貼り付けられた場合のチェック
            if (!string.IsNullOrWhiteSpace(txtSortOrder.Text))
            {
                if (!ValidationHelperUtil.IsValidSortOrder(txtSortOrder.Text))
                {
                    // 背景色を薄い赤にして視覚的にエラーを示す
                    txtSortOrder.BackColor = Color.FromArgb(255, 230, 230);
                    errorToolTip.Show(ValidationHelperUtil.GetSortOrderFormatErrorMessage(), 
                        txtSortOrder, 0, -25, 3000);
                }
                else
                {
                    // 正常な場合は背景色を元に戻す
                    txtSortOrder.BackColor = SystemColors.Window;
                    errorToolTip.Hide(txtSortOrder);
                }
            }
            else
            {
                // 空の場合も背景色を元に戻す
                txtSortOrder.BackColor = SystemColors.Window;
                errorToolTip.Hide(txtSortOrder);
            }
        }
    }
}