using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using FlaUI.UIA2;
using FlaUI.Core;
using FlaUI.Core.Input;
using FlaUI.Core.Shapes;
using System.Threading;
using System.Diagnostics;
using FlaUI.Core.WindowsAPI;

namespace FWHandler
{  
    public sealed class FlaUIHandler : IFWController
    {
        private static FlaUI.Core.Application app;
        private static UIA2Automation automation;

        private FlaUI.Core.AutomationElements.Infrastructure.AutomationElement lookedElement;
        private FlaUI.Core.AutomationElements.TextBox textBoxGeneral;
        private FlaUI.Core.AutomationElements.ListBox listBoxGeneral;
        private FlaUI.Core.AutomationElements.Tree treeGeneral;
        private FlaUI.Core.AutomationElements.Infrastructure.AutomationElement[] elementArrayGeneral;
        private FlaUI.Core.AutomationElements.Window window;

        private static FlaUIHandler instance = null;

        private FlaUIHandler() { }
   

        public static FlaUIHandler Instance
        {
            get
            {
                if (instance == null)
                    instance = new FlaUIHandler();
                return instance;
            }
        }

        //app handlers

        public void AppInicialize(string wayToApp, int timing = 0)
        {
            automation = new UIA2Automation();

            FlaUI.Core.Tools.Retry.WhileException(() =>
            {
               app = FlaUI.Core.Application.Launch(wayToApp);
               window = app.GetMainWindow(automation);
            }, TimeSpan.FromMilliseconds(timing));
        }

        public void AttachNewWindow(string newApp, int timing = 0)
        {
            automation = new UIA2Automation();

            FlaUI.Core.Tools.Retry.WhileException(() =>
            {
                app = FlaUI.Core.Application.Attach(newApp);
                FlaUI.Core.AutomationElements.Window window = app.GetMainWindow(automation);
                if(window == null)
                {
                    throw new Exception();
                }
            }, TimeSpan.FromMilliseconds(timing));
        }
        public void AttachNewWindow(string newWindow,string lookedName, int timing = 0)
        {
            automation = new UIA2Automation();
            Process correctProcess = null;
            FlaUI.Core.Tools.Retry.WhileException(() =>
            {
                var localByName = Process.GetProcessesByName(newWindow);
                foreach (Process name in localByName)
                {
                    if(name.MainWindowTitle == lookedName)
                    {
                        correctProcess = name; 
                    }
                }
                app = FlaUI.Core.Application.Attach(correctProcess);
                FlaUI.Core.AutomationElements.Window window = app.GetMainWindow(automation);
                if (window == null)
                {
                    throw new Exception();
                }
            }, TimeSpan.FromMilliseconds(timing));
        }

        public void AttachNewWindow(int timing = 0)
        {
            automation = new UIA2Automation();
            FlaUI.Core.Tools.Retry.WhileException(() =>
            {
                var localBy = Process.GetCurrentProcess();                
                app = FlaUI.Core.Application.Attach(localBy);
                FlaUI.Core.AutomationElements.Window window = app.GetMainWindow(automation);
                if (window == null)
                {
                    throw new Exception();
                }
            }, TimeSpan.FromMilliseconds(timing));
        }

        public void FindNewWindow(int timing = 0)
        {
            FlaUI.Core.Tools.Retry.WhileException(() =>
            {
                FlaUI.Core.AutomationElements.Window window = app.GetMainWindow(automation);
                if (window == null)
                {
                    throw new Exception();
                }
            }, TimeSpan.FromMilliseconds(timing));
        }

        public string GetWindowName(int timing = 0)
        {
            FlaUI.Core.AutomationElements.Window window = app.GetMainWindow(automation);
            string name = string.Empty;
            FlaUI.Core.Tools.Retry.WhileException(() =>
            {
                name = window.Title;
                if (name == string.Empty)
                    throw new Exception();
            }, TimeSpan.FromMilliseconds(timing));
            return name;
        }

        public void AppClose(int timing = 0)
        {
            if (app != null)
            {
                FlaUI.Core.Tools.Retry.WhileException(() =>
                {
                    app.Close();
                }, TimeSpan.FromMilliseconds(timing));
            }
        }

        public void AppKill()
        {
            if (app != null)
            {
                app.Kill();
            }
        }


        //window handlers
        public void SetForeground()
        {
            FlaUI.Core.AutomationElements.Window window = app.GetMainWindow(automation);
            if (window != null)
            {
                window.SetForeground();
            }
            else
            {
                throw new Exception("No window to set foreground!");
            }
        }

        public double GetHeight()
        {
            FlaUI.Core.AutomationElements.Window window = app.GetMainWindow(automation);
            if (window != null)
            {
                return window.ActualHeight;
            }
            else return -1;          
        }
        public double GetWidth()
        {
            FlaUI.Core.AutomationElements.Window window = app.GetMainWindow(automation);
            if (window != null)
            {
                return window.ActualWidth;
            }
            else return -1;
        }
        public void WindowMaximize()
        {
            FlaUI.Core.AutomationElements.Window window = app.GetMainWindow(automation);
            if(window != null)
            {
                window.TitleBar.MaximizeButton.Invoke();
            }
        }
        public void WindowMinimaze()
        {
            FlaUI.Core.AutomationElements.Window window = app.GetMainWindow(automation);
            if (window != null)
            {
                window.TitleBar.MinimizeButton.Invoke();
            }
        }

        public void FindElementBy(string name, int repeatingTime = 0)
        {
            FlaUI.Core.AutomationElements.Infrastructure.AutomationElement element = lookedElement;

            FlaUI.Core.Tools.Retry.WhileException(() =>
            {
                var temp = element ?? app.GetMainWindow(automation);
                lookedElement = temp.FindFirstDescendant(cf => cf.ByAutomationId(name));

                if (lookedElement == null)
                {
                    lookedElement = temp.FindFirstDescendant(cf => cf.ByName(name));
                }

                if (lookedElement is null)
                    throw new ElementNotFoundException(ExceptionMessagesProvider.CreateMessage(name));

            }, TimeSpan.FromMilliseconds(repeatingTime));
        }
      
        public void FindAllChildrenBy(string name, int repeatingTime = 0)
        {
            FlaUI.Core.AutomationElements.Infrastructure.AutomationElement element = lookedElement;
            lookedElement = null;
            FlaUI.Core.Tools.Retry.WhileException(() =>
            {
                var temp = element ?? app.GetMainWindow(automation);
                elementArrayGeneral = temp.FindAllChildren(cf => cf.ByAutomationId(name));

                if (lookedElement == null)
                {
                    elementArrayGeneral = temp.FindAllChildren(cf => cf.ByName(name));
                }

                if (lookedElement is null)
                    throw new ElementNotFoundException(ExceptionMessagesProvider.CreateMessage(name));

            }, TimeSpan.FromMilliseconds(repeatingTime));
        }
        public void FindAllDescendentsBy(string name, int repeatingTime = 0)
        {
            FlaUI.Core.AutomationElements.Infrastructure.AutomationElement element = lookedElement;
            lookedElement = null;
            FlaUI.Core.Tools.Retry.WhileException(() =>
            {
                var temp = element ?? app.GetMainWindow(automation);
                elementArrayGeneral = temp.FindAllDescendants(cf => cf.ByAutomationId(name));

                if (elementArrayGeneral == null)
                {
                    elementArrayGeneral = temp.FindAllDescendants(cf => cf.ByName(name));
                }

                if (elementArrayGeneral is null)
                    throw new ElementNotFoundException(ExceptionMessagesProvider.CreateMessage(name));

            }, TimeSpan.FromMilliseconds(repeatingTime));
        }

        public void SelectSpecificId(int id)
        {
            lookedElement = elementArrayGeneral[id];
        }
   
        public void ElementClickBy(string value, int id, int repeatingTime = 0)
        {          
            FindElementBy(value, repeatingTime);
            var lookedelement = lookedElement;
            lookedElement = null;
            var elements = lookedelement.FindAllChildren();
            elements[id].Click();
        }
        public void ElementFindBy(string value, int id, int repeatingTime = 0)
        {          
            FindElementBy(value, repeatingTime);
            var lookedelement = lookedElement;
            lookedElement = null;
            var elements = lookedelement.FindAllChildren();
            lookedElement = elements[id];
        }
        public void ElementDoubleClickBy(string value, int id, int repeatingTime = 0)
        {           
            FindElementBy(value, repeatingTime);
            var lookedelement = lookedElement;
            lookedElement = null;
            var elements = lookedelement.FindAllChildren();
            elements[id].DoubleClick();
        }
        public void ElementRightClickBy(string value, int id, int repeatingTime = 0)
        {            
            FindElementBy(value, repeatingTime);
            var lookedelement = lookedElement;
            lookedElement = null;
            var elements = lookedelement.FindAllChildren();
            elements[id].RightClick();
        }    
        public bool ElementExist(string value, int repeatingTime = 0)
        {
            try
            {
                FindElementBy(value, repeatingTime);
                lookedElement = null;
            }
            catch(Exception ex)
            {
                if (ex is NullReferenceException)
                {
                    return false;
                }
                else if (ex.Message == "Timeout occurred in retry")
                {
                    return false;
                }
            }
            return true;         
        }
        public bool ElementIsVisible(string value, int repeatingTime = 0)
        {           
            FindElementBy(value, repeatingTime);
            var lookedelement = lookedElement;
            lookedElement = null;
            if (lookedelement.IsOffscreen == true)
                return false;
            return true;
        }
        public bool ElementIsVisible(string value,int id, int repeatingTime = 0)
        {            
            FindElementBy(value, repeatingTime);
            var lookedelement = lookedElement;
            lookedElement = null;
            var elements = lookedelement.FindAllChildren();
            if (elements[id].IsOffscreen == true)
                return false;
            return true;
        }

        public string GetElementName(string value, int repeatingTime = 0)
       {   
            FindElementBy(value, repeatingTime);
            var lookedelement = lookedElement;
            lookedElement = null;
            var element = lookedelement;
            lookedElement = null;
            return element.Name;
       }
        public string GetElementName(string value, int id, int repeatingTime = 0)
        {
            FindElementBy(value, repeatingTime);
            var lookedelement = lookedElement;
            lookedElement = null;
            var elements = lookedelement.FindAllChildren();
            return elements[id].Name;
        }
        public void SetNull()
        {
            lookedElement = null;
        }

        //MENU OPERATIONS
        private FlaUI.Core.AutomationElements.MenuItem MenuItemFindByName(string menuItemName, int repeatingTime = 0)
        {
            FlaUI.Core.AutomationElements.MenuItem menuItem = null;
            FlaUI.Core.AutomationElements.Infrastructure.AutomationElement element = lookedElement;
            lookedElement = null;

            FlaUI.Core.Tools.Retry.WhileException(() =>
            {               
                menuItem = window.FindFirstDescendant(cf => cf.ByName(menuItemName))?.AsMenuItem();

                if (menuItem == null)
                    menuItem = window.FindFirstDescendant(cf => cf.ByAutomationId(menuItemName))?.AsMenuItem();

                if (menuItem is null)
                {
                    window = app.GetMainWindow(automation);
                        throw new ElementNotFoundException(ExceptionMessagesProvider.CreateMessage(menuItemName));
                }

            }, TimeSpan.FromMilliseconds(repeatingTime));

            return menuItem;
        }

        public void MenuItemInvokeByName(string menuItemName, int repeatingTime = 0)
        {
            FlaUI.Core.AutomationElements.MenuItem menuItem = MenuItemFindByName(menuItemName, repeatingTime);
            menuItem.Invoke();
        }

        public void MenuItemClickByName(string menuItemName, int repeatingTime = 0)
        {
            FlaUI.Core.AutomationElements.MenuItem menuItem = MenuItemFindByName(menuItemName, repeatingTime);
            menuItem.Click();
        }

        public void MenuItemDoubleClickByName(string menuItemName, int repeatingTime = 0)
        {
            FlaUI.Core.AutomationElements.MenuItem menuItem = MenuItemFindByName(menuItemName, repeatingTime);
            menuItem.DoubleClick();
        }
        public void MenuItemRightClickByName(string menuItemName, int repeatingTime = 0)
        {
            FlaUI.Core.AutomationElements.MenuItem menuItem = MenuItemFindByName(menuItemName, repeatingTime);
            menuItem.RightClick();
        }

        public bool MenuItemExist(string menuItemid, int repeatingTime = 0)
        {
            try
            {
                FlaUI.Core.AutomationElements.MenuItem menuItem = MenuItemFindByName(menuItemid, repeatingTime);
            }
            catch (Exception ex)
            {
                if (ex is NullReferenceException)
                {
                    return false;
                }
                else if (ex.Message == "Timeout occurred in retry")
                {
                    return false;
                }
                else
                {
                    return false;
                }
            }
            return true;
        }
        public bool MenuItemIsVisible(string menuItemid, int repeatingTime = 0)
        {
            FlaUI.Core.AutomationElements.MenuItem menuItem = MenuItemFindByName(menuItemid, repeatingTime);
            if (menuItem.IsOffscreen == true)
                return false;
            return true;
        }


        //BUTTONS OPERATIONS
        private FlaUI.Core.AutomationElements.Button ButtonFindByName(string name, int repeatingTime = 0)
        {
            FlaUI.Core.AutomationElements.Button button = null;
            FlaUI.Core.AutomationElements.Infrastructure.AutomationElement element = lookedElement;
            lookedElement = null;

            FlaUI.Core.Tools.Retry.WhileException(() =>
            {
                var temp = element ?? app.GetMainWindow(automation);
                button = temp.FindFirstDescendant(cf => cf.ByName(name)).AsButton();                                   
                if (button is null)
                    throw new ElementNotFoundException(ExceptionMessagesProvider.CreateMessage(name));

            }, TimeSpan.FromMilliseconds(repeatingTime));
            return button;
        }

        public void ButtonInvokeByName(string name, int repeatingTime = 0)
        {
            FlaUI.Core.AutomationElements.Button button = ButtonFindByName(name, repeatingTime);
            button.Invoke();
        }

        public FlaUI.Core.AutomationElements.Button ButtonFindByAutomationID(string name, int repeatingTime = 0)
        {
            FlaUI.Core.AutomationElements.Button button = null;
            FlaUI.Core.AutomationElements.Infrastructure.AutomationElement element = lookedElement;
            lookedElement = null;

            FlaUI.Core.Tools.Retry.WhileException(() =>
            {
                var temp = element ?? app.GetMainWindow(automation);                           
                button = temp.FindFirstDescendant(cf => cf.ByAutomationId(name)).AsButton();              
                if (button is null)
                    throw new ElementNotFoundException(ExceptionMessagesProvider.CreateMessage(name));

            }, TimeSpan.FromMilliseconds(repeatingTime));
            return button;
        }
        public void ButtonInvokeByAutomationID(string name, int repeatingTime = 0)
        {
            FlaUI.Core.AutomationElements.Button button = ButtonFindByAutomationID(name, repeatingTime);
            button.Invoke();
        }

        private FlaUI.Core.AutomationElements.Button ButtonFindBy(string name, int repeatingTime = 0)
        {
            FlaUI.Core.AutomationElements.Button button = null;
            FlaUI.Core.AutomationElements.Infrastructure.AutomationElement element = lookedElement;
            lookedElement = null;

            FlaUI.Core.Tools.Retry.WhileException(() =>
            {
                var temp = element ?? app.GetMainWindow(automation);
              
                button = temp.FindFirstDescendant(cf => cf.ByAutomationId(name))?.AsButton();
                if (button == null)
                {
                    button = temp.FindFirstDescendant(cf => cf.ByName(name))?.AsButton();
                }
                            
                if (button is null)
                    throw new ElementNotFoundException(ExceptionMessagesProvider.CreateMessage(name));

            }, TimeSpan.FromMilliseconds(repeatingTime));
            return button;
        }

        public void ButtonClickBy(string name, int repeatingTime = 0)
        {
            FlaUI.Core.AutomationElements.Button button = ButtonFindBy(name, repeatingTime);
            button.Click();
        }

        public void ButtonDoubleClickBy(string name, int repeatingTime = 0)
        {
            FlaUI.Core.AutomationElements.Button button = ButtonFindBy(name, repeatingTime);
            button.DoubleClick();
        }

        public void ButtonInvokeBy(string name, int repeatingTime = 0)
        {
            FlaUI.Core.AutomationElements.Button button = ButtonFindBy(name, repeatingTime);
            button.Invoke();
        }
      
        public void ButtonClickByName(string name, int repeatingTime = 0)
        {
            FlaUI.Core.AutomationElements.Button button = ButtonFindByName(name, repeatingTime);
            button.Click();
        }

        public void ButtonClickByAutomationID(string name, int repeatingTime = 0)
        {
            FlaUI.Core.AutomationElements.Button button = ButtonFindByAutomationID(name, repeatingTime);
            button.Click();
        }

        public bool ButtonIsEnabled(string value, int repeatingTime = 0)
        {
            FlaUI.Core.AutomationElements.Button button = ButtonFindBy(value, repeatingTime);

            if (button.IsEnabled == true)
            {
                return true;
            }
            else return false;
        }
        public bool ButtonExist(string value, int repeatingTime = 0)
        {
            try
            {
                FlaUI.Core.AutomationElements.Button button = ButtonFindBy(value, repeatingTime);
            }
            catch (Exception ex)
            {
                if (ex is NullReferenceException)
                {
                    return false;
                }
                else if (ex.Message == "Timeout occurred in retry")
                {
                    return false;
                }
            }
            return true;
        }
        public bool ButtonIsVisible(string value, int repeatingTime = 0)
        {
            FlaUI.Core.AutomationElements.Button button = ButtonFindBy(value, repeatingTime);
            if (button.IsOffscreen == true)
                return false;
            return true;
        }


        //CHECKBOX OPERATIONS
        public FlaUI.Core.AutomationElements.CheckBox CheckBoxFindByName(string name, int repeatingTime = 0)
        {
            FlaUI.Core.AutomationElements.CheckBox checkBox = null;
            FlaUI.Core.AutomationElements.Infrastructure.AutomationElement element = lookedElement;
            lookedElement = null;

            FlaUI.Core.Tools.Retry.WhileException(() =>
            {
                var temp = element ?? app.GetMainWindow(automation);
               
                checkBox = temp.FindFirstDescendant(cf => cf.ByName(name)).AsCheckBox();
                if (checkBox is null)
                    throw new ElementNotFoundException(ExceptionMessagesProvider.CreateMessage(name));

            }, TimeSpan.FromMilliseconds(repeatingTime));
            return checkBox;
        }
        public void CheckBoxClickByName(string name, int repeatingTime = 0)
        {
            FlaUI.Core.AutomationElements.CheckBox checkBox = CheckBoxFindByName(name, repeatingTime);
            checkBox.Click();
        }

        public FlaUI.Core.AutomationElements.CheckBox CheckBoxFindByAutomationID(string name, int repeatingTime = 0)
        {
            FlaUI.Core.AutomationElements.CheckBox checkBox = null;
            FlaUI.Core.AutomationElements.Infrastructure.AutomationElement element = lookedElement;
            lookedElement = null;

            FlaUI.Core.Tools.Retry.WhileException(() =>
            {
                var temp = element ?? app.GetMainWindow(automation);
                checkBox = temp.FindFirstDescendant(cf => cf.ByAutomationId(name)).AsCheckBox();
                if (checkBox is null)
                    throw new ElementNotFoundException(ExceptionMessagesProvider.CreateMessage(name));

            }, TimeSpan.FromMilliseconds(repeatingTime));
            return checkBox;
        }
        public void CheckBoxClickByAutomationID(string name, int repeatingTime = 0)
        {
            FlaUI.Core.AutomationElements.CheckBox checkBox = CheckBoxFindByAutomationID(name, repeatingTime);
            checkBox.Click();
        }

        private FlaUI.Core.AutomationElements.CheckBox CheckBoxFindBy(string name, int repeatingTime = 0)
        {
            FlaUI.Core.AutomationElements.CheckBox checkBox = null;
            FlaUI.Core.AutomationElements.Infrastructure.AutomationElement element = lookedElement;
            lookedElement = null;

            FlaUI.Core.Tools.Retry.WhileException(() =>
            {
                var temp = element ?? app.GetMainWindow(automation);
                                  
                checkBox = temp.FindFirstDescendant(cf => cf.ByAutomationId(name))?.AsCheckBox();
                if (checkBox == null)
                {
                     checkBox = temp.FindFirstDescendant(cf => cf.ByName(name))?.AsCheckBox();
                }
                              
                if (checkBox is null)
                    throw new ElementNotFoundException(ExceptionMessagesProvider.CreateMessage(name));

            }, TimeSpan.FromMilliseconds(repeatingTime));

            return checkBox;
        }
        public void CheckBoxClickBy(string name, int repeatingTime = 0)
        {
            FlaUI.Core.AutomationElements.CheckBox checkBox = CheckBoxFindBy(name, repeatingTime); // Tady nacitat z te funkce
            checkBox.Click();
       
        }
        public void CheckBoxDoubleClickBy(string name, int repeatingTime = 0)
        {
            FlaUI.Core.AutomationElements.CheckBox checkBox = CheckBoxFindBy(name, repeatingTime);
            checkBox.DoubleClick();
        }
        public bool CheckBoxExist(string name, int repeatingTime = 0)
        {         
            try
            {
                FlaUI.Core.AutomationElements.CheckBox checkBox = CheckBoxFindBy(name, repeatingTime);
            }
            catch (Exception ex)
            {
                if (ex is NullReferenceException)
                {
                    return false;
                }
                else if (ex.Message == "Timeout occurred in retry")
                {
                    return false;
                }
            }
            return true;
        }
        public bool CheckBoxIsChecked(string name, int repeatingTime = 0)
        {
            FlaUI.Core.AutomationElements.CheckBox checkBox = CheckBoxFindBy(name, repeatingTime);
            if (checkBox.IsChecked != true)
                return false;
            return true;
        }

        //TEXTBOX OPERATIONS
        public FlaUI.Core.AutomationElements.TextBox TextBoxFindByName(string name, int repeatingTime = 0)
        {
            FlaUI.Core.AutomationElements.TextBox textBox = null;
            FlaUI.Core.AutomationElements.Infrastructure.AutomationElement element = lookedElement;
            lookedElement = null;

            FlaUI.Core.Tools.Retry.WhileException(() =>
            {
                var temp = element ?? app.GetMainWindow(automation);
                textBox = temp.FindFirstDescendant(cf => cf.ByName(name)).AsTextBox();
                if (textBox is null)
                    throw new ElementNotFoundException(ExceptionMessagesProvider.CreateMessage(name));

            }, TimeSpan.FromMilliseconds(repeatingTime));
            return textBox;
        }
        public FlaUI.Core.AutomationElements.TextBox TextBoxFindByAutomationID(string name, int repeatingTime = 0)
        {
            FlaUI.Core.AutomationElements.TextBox textBox = null;
            FlaUI.Core.AutomationElements.Infrastructure.AutomationElement element = lookedElement;
            lookedElement = null;

            FlaUI.Core.Tools.Retry.WhileException(() =>
            {
                var temp = element ?? app.GetMainWindow(automation);
                textBox = temp.FindFirstDescendant(cf => cf.ByAutomationId(name)).AsTextBox();
                if (textBox is null)
                    throw new ElementNotFoundException(ExceptionMessagesProvider.CreateMessage(name));

            }, TimeSpan.FromMilliseconds(repeatingTime));
            return textBox;
        }
        public void TextBoxClickByName(string name, int repeatingTime = 0)
        {
            FlaUI.Core.AutomationElements.TextBox textBox = TextBoxFindByName(name, repeatingTime);
            textBox.Click();
        }
        public void TextBoxClickByAutomationID(string name, int repeatingTime = 0)
        {
            FlaUI.Core.AutomationElements.TextBox textBox = TextBoxFindByAutomationID(name, repeatingTime);
            textBox.Click();
        }
        private FlaUI.Core.AutomationElements.TextBox TextBoxFindBy(string value, int repeatingTime = 0)
        {
            FlaUI.Core.AutomationElements.TextBox textBox = null;
            FlaUI.Core.AutomationElements.Infrastructure.AutomationElement element = lookedElement;
            lookedElement = null;

            FlaUI.Core.Tools.Retry.WhileException(() =>
             {

                 var temp = element ?? app.GetMainWindow(automation);
                 textBox = temp.FindFirstDescendant(cf => cf.ByAutomationId(value))?.AsTextBox();
                 if (textBox == null)
                 {
                     textBox = temp.FindFirstDescendant(cf => cf.ByName(value))?.AsTextBox();
                 }
                                
                 if (textBox is null)
                     throw new ElementNotFoundException(ExceptionMessagesProvider.CreateMessage(value));

             }, TimeSpan.FromMilliseconds(repeatingTime)); 
            return textBox;
        }

        public void TextBoxFind(string value, int repeatingTime = 0)
        {
            FlaUI.Core.AutomationElements.TextBox textBox = TextBoxFindBy(value, repeatingTime);
            textBoxGeneral = textBox;
        }
        public void TextBoxFindBy(int id)
        {
            FlaUI.Core.AutomationElements.Infrastructure.AutomationElement[] elementArray = elementArrayGeneral;
            elementArrayGeneral = null;
            FlaUI.Core.AutomationElements.TextBox textBox = textBoxGeneral;
            textBox = (FlaUI.Core.AutomationElements.TextBox)elementArray[id];
        }

        public void TextBoxClickBy(string name, int repeatingTime = 0)
        {
            FlaUI.Core.AutomationElements.TextBox textBox = TextBoxFindBy(name, repeatingTime);
            textBoxGeneral = null;
            textBox.Click();
        }
        public void TextBoxDoubleClickBy(string name, int repeatingTime = 0)
        {
            FlaUI.Core.AutomationElements.TextBox textBox = TextBoxFindBy(name, repeatingTime);
            textBoxGeneral = null;
            textBox.DoubleClick();
        }

        public void InsertToTextBox(string text)
        {
            FlaUI.Core.AutomationElements.TextBox textBox = textBoxGeneral;
            textBoxGeneral = null;
            textBox.Text = text;
        }

        public string ReadFromTextBox()
        {
            FlaUI.Core.AutomationElements.TextBox textBox = textBoxGeneral;
            textBoxGeneral = null;
            return textBox.Text;
        }
        public bool TextBoxExist(string name, int repeatingTime = 0)
        {
            try
            {
                FlaUI.Core.AutomationElements.TextBox textBox = TextBoxFindBy(name, repeatingTime);
            }
            catch (Exception ex)
            {
                if (ex is NullReferenceException)
                {
                    return false;
                }
                else if (ex.Message == "Timeout occurred in retry")
                {
                    return false;
                }
            }
            return true;
        }

        public bool TextBoxIsVisible(string name, int repeatingTime = 0)
        {
            FlaUI.Core.AutomationElements.TextBox textBox = TextBoxFindBy(name, repeatingTime);
            if (textBox.IsOffscreen == true)
                return false;
            return true;
        }

        //RADIO BUTTONS
        private FlaUI.Core.AutomationElements.RadioButton RadioButtonFindBy(string value, int repeatingTime = 0)
        {
            FlaUI.Core.AutomationElements.RadioButton radioButton = null;
            FlaUI.Core.AutomationElements.Infrastructure.AutomationElement element = lookedElement;
            lookedElement = null;

            FlaUI.Core.Tools.Retry.WhileException(() =>
            {
                var temp = element ?? app.GetMainWindow(automation);
               
                radioButton = temp.FindFirstDescendant(cf => cf.ByAutomationId(value))?.AsRadioButton();
                if (radioButton == null)
                    {
                    radioButton = temp.FindFirstDescendant(cf => cf.ByName(value))?.AsRadioButton();
                }                         
                if (radioButton is null)
                    throw new ElementNotFoundException(ExceptionMessagesProvider.CreateMessage(value));

            }, TimeSpan.FromMilliseconds(repeatingTime));
            return radioButton;
        }

        public void RadioButtonClickBy(string value, int repeatingTime = 0)
        {
            FlaUI.Core.AutomationElements.RadioButton radioButton = RadioButtonFindBy(value, repeatingTime);
            radioButton.Click();
        }
        public void RadioButtonDoubleClickBy(string value, int repeatingTime = 0)
        {
            FlaUI.Core.AutomationElements.RadioButton radioButton = RadioButtonFindBy(value, repeatingTime);
            radioButton.DoubleClick();
        }
        public bool RadioIsChecked(string value, int repeatingTime = 0)
        {
            FlaUI.Core.AutomationElements.RadioButton radioButton = RadioButtonFindBy(value, repeatingTime);
            if (radioButton.IsChecked == true)
            {
                return true;
            }
            else return false;
        }
        public bool RadioButtonExist(string value, int repeatingTime = 0)
        {
            try
            {
                FlaUI.Core.AutomationElements.RadioButton radioButton = RadioButtonFindBy(value, repeatingTime);
            }
            catch (Exception ex)
            {
                if (ex is NullReferenceException)
                {
                    return false;
                }
                else if (ex.Message == "Timeout occurred in retry")
                {
                    return false;
                }
            }
            return true;
        }

        public bool RadioButtonIsVisible(string value, int repeatingTime = 0)
        {
            FlaUI.Core.AutomationElements.RadioButton radioButton = RadioButtonFindBy(value, repeatingTime);
            if (radioButton.IsOffscreen == true)
                return false;
            return true;
        }

        private FlaUI.Core.AutomationElements.RadioButton RadioButtonFindByName(string value, int repeatingTime = 0)
        {
            FlaUI.Core.AutomationElements.RadioButton radioButton = null;
            FlaUI.Core.AutomationElements.Infrastructure.AutomationElement element = lookedElement;
            lookedElement = null;

            FlaUI.Core.Tools.Retry.WhileException(() =>
            {
                var temp = element ?? app.GetMainWindow(automation);
                radioButton = temp.FindFirstDescendant(cf => cf.ByName(value))?.AsRadioButton();
                if (radioButton is null)
                    throw new ElementNotFoundException(ExceptionMessagesProvider.CreateMessage(value));
            }, TimeSpan.FromMilliseconds(repeatingTime));
            return radioButton;
        }
        public void RadioButtonClickByName(string value, int repeatingTime = 0)
        {
            FlaUI.Core.AutomationElements.RadioButton radioButton = RadioButtonFindByName(value, repeatingTime);
            radioButton.Click();
        }

        private FlaUI.Core.AutomationElements.RadioButton RadioButtonFindByAutoID(string value, int repeatingTime = 0)
        {
            FlaUI.Core.AutomationElements.RadioButton radioButton = null;
            FlaUI.Core.AutomationElements.Infrastructure.AutomationElement element = lookedElement;
            lookedElement = null;

            FlaUI.Core.Tools.Retry.WhileException(() =>
            {
                var temp = element ?? app.GetMainWindow(automation);
                radioButton = temp.FindFirstDescendant(cf => cf.ByAutomationId(value))?.AsRadioButton();
                if (radioButton is null)
                    throw new ElementNotFoundException(ExceptionMessagesProvider.CreateMessage(value));
            }, TimeSpan.FromMilliseconds(repeatingTime));
            return radioButton;
        }
        public void RadioButtonClickByAutoID(string value, int repeatingTime = 0)
        {
            FlaUI.Core.AutomationElements.RadioButton radioButton = RadioButtonFindByAutoID(value, repeatingTime);
            radioButton.Click();
        }

        //COMBO BOX OPERATIONS

        private FlaUI.Core.AutomationElements.ComboBox ComboBoxFindBy(string value, int repeatingTime = 0)
        {
            FlaUI.Core.AutomationElements.ComboBox combobox = null;
            FlaUI.Core.AutomationElements.Infrastructure.AutomationElement element = lookedElement;
            lookedElement = null;

            FlaUI.Core.Tools.Retry.WhileException(() =>
            {
                var temp = element ?? app.GetMainWindow(automation);
                combobox = temp.FindFirstDescendant(cf => cf.ByAutomationId(value).And(cf.ByControlType(FlaUI.Core.Definitions.ControlType.ComboBox)))?.AsComboBox();
                if (combobox == null)
                {
                    combobox = temp.FindFirstDescendant(cf => cf.ByName(value).And(cf.ByControlType(FlaUI.Core.Definitions.ControlType.ComboBox)))?.AsComboBox();
                }

                if (combobox is null)
                    throw new ElementNotFoundException(ExceptionMessagesProvider.CreateMessage(value));

            }, TimeSpan.FromMilliseconds(repeatingTime));
            return combobox;
        }       

        public void ComboBoxSelectBy(string value, int id, int repeatingTime = 0)
        {
            FlaUI.Core.AutomationElements.ComboBox combobox = ComboBoxFindBy(value, repeatingTime);
            combobox.Select(id);
        }
        public void ComboBoxSelectBy(string value, string itemId, int repeatingTime = 0)
        {
            FlaUI.Core.AutomationElements.ComboBox combobox = ComboBoxFindBy(value, repeatingTime);
            combobox.Select(itemId);
        }
        public void ComboBoxClickBy(string value, int repeatingTime = 0)
        {
            FlaUI.Core.AutomationElements.ComboBox combobox = ComboBoxFindBy(value, repeatingTime);
            combobox.Click();
        }
        public void ComboBoxClickBy(string value, int id, int repeatingTime = 0)
        {
            FlaUI.Core.AutomationElements.ComboBox combobox = ComboBoxFindBy(value, repeatingTime);
            var comboboxitem = combobox.Items[id];
            comboboxitem.Click();
        }
        public void ComboBoxDoubleClickBy(string value, int id, int repeatingTime = 0)
        {
            FlaUI.Core.AutomationElements.ComboBox combobox = ComboBoxFindBy(value, repeatingTime);
            var comboboxItem = combobox.Items[id];
            comboboxItem.DoubleClick();
        }
        public void ComboBoxExpand(string value, int repeatingTime = 0)
        {
            FlaUI.Core.AutomationElements.ComboBox combobox = ComboBoxFindBy(value, repeatingTime);
            combobox.Expand();
        }

        public bool ComboBoxExist(string value, int repeatingTime = 0)
        {
            try
            {
                FlaUI.Core.AutomationElements.ComboBox combobox = ComboBoxFindBy(value, repeatingTime);
            }
            catch (Exception ex)
            {
                if (ex is NullReferenceException)
                {
                    return false;
                }
                else if (ex.Message == "Timeout occurred in retry")
                {
                    return false;
                }
            }
            return true;
        }

        public bool ComboBoxIsVisible(string value, int repeatingTime = 0)
        {
            FlaUI.Core.AutomationElements.ComboBox combobox = ComboBoxFindBy(value, repeatingTime);
            if (combobox.IsOffscreen == true)
                return false;
            return true;
        }

        //TreeItem

        public FlaUI.Core.AutomationElements.TreeItem TreeItemFindBy(string value, int repeatingTime = 0)
        {
            FlaUI.Core.AutomationElements.TreeItem treeItem = null;
            FlaUI.Core.AutomationElements.Infrastructure.AutomationElement element = lookedElement;
            lookedElement = null;

            FlaUI.Core.Tools.Retry.WhileException(() =>
            {
                var temp = element ?? app.GetMainWindow(automation);
                treeItem = temp.FindFirstDescendant(cf => cf.ByName(value))?.AsTreeItem();
                if (treeItem == null)
                {
                    treeItem = temp.FindFirstDescendant(cf => cf.ByAutomationId(value))?.AsTreeItem();
                }

                if (treeItem is null)
                    throw new ElementNotFoundException(ExceptionMessagesProvider.CreateMessage(value));

            }, TimeSpan.FromMilliseconds(repeatingTime));
            return treeItem;
        }

        public void TreeItemClickBy(string value, int repeatingTime = 0)
        {
            FlaUI.Core.AutomationElements.TreeItem treeItem = TreeItemFindBy(value, repeatingTime);
            treeItem.Click();
        }

        public void TreeItemDoubleClickBy(string value, int repeatingTime = 0)
        {
            FlaUI.Core.AutomationElements.TreeItem treeItem = TreeItemFindBy(value, repeatingTime);
            treeItem.DoubleClick();
        }

        public FlaUI.Core.AutomationElements.Tree TreeFind(string value, int repeatingTime = 0)
        {
            FlaUI.Core.AutomationElements.Tree tree = null;
            FlaUI.Core.AutomationElements.Infrastructure.AutomationElement element = lookedElement;
            lookedElement = null;

            FlaUI.Core.Tools.Retry.WhileException(() =>
            {
                var temp = element ?? app.GetMainWindow(automation);
                tree = temp.FindFirstDescendant(cf => cf.ByAutomationId(value))?.AsTree();
                if (tree == null)
                {
                    tree = temp.FindFirstDescendant(cf => cf.ByName(value))?.AsTree();
                }
                if (tree is null)
                    throw new ElementNotFoundException(ExceptionMessagesProvider.CreateMessage(value));

            }, TimeSpan.FromMilliseconds(repeatingTime));
            treeGeneral = tree;
            return tree;
        }
        public void TreeFindBy(string value, int repeatingTime = 0)
        {
            FlaUI.Core.AutomationElements.Tree tree = TreeFind(value, repeatingTime);
        }

        public void TreeClickBy(string value, int id, int repeatingTime)
        {
            FlaUI.Core.AutomationElements.Tree tree = TreeFind(value, repeatingTime);
            treeGeneral = null;
            var treeItem = tree.FindAllDescendants()[id].AsTreeItem();
            treeItem.Click();
        }

        public bool TreeItemExist(string value, int repeatingTime = 0)
        {
            try
            {
                FlaUI.Core.AutomationElements.TreeItem treeItem = TreeItemFindBy(value, repeatingTime);
            }
            catch (Exception ex)
            {
                if (ex is NullReferenceException)
                {
                    return false;
                }
                else if (ex.Message == "Timeout occurred in retry")
                {
                    return false;
                }
            }
            return true;                     
        }

        //List

        public FlaUI.Core.AutomationElements.ListBox ListFindBy(string value, int repeatingTime = 0)
        {
            FlaUI.Core.AutomationElements.ListBox listBox = null;
            FlaUI.Core.AutomationElements.Infrastructure.AutomationElement element = lookedElement;
            lookedElement = null;

            FlaUI.Core.Tools.Retry.WhileException(() =>
            {
                var temp = element ?? app.GetMainWindow(automation);
                listBox = temp.FindFirstDescendant(cf => cf.ByAutomationId(value))?.AsListBox();
                if (listBox == null)
                {
                    listBox = temp.FindFirstDescendant(cf => cf.ByName(value))?.AsListBox();
                }
                if (listBox is null)
                    throw new ElementNotFoundException(ExceptionMessagesProvider.CreateMessage(value));

            }, TimeSpan.FromMilliseconds(repeatingTime));
            listBoxGeneral = listBox;
            return listBox;
        }
        private FlaUI.Core.AutomationElements.ListBoxItem ListItemFindBy(string value, int repeatingTime = 0)
        {
            FlaUI.Core.AutomationElements.ListBoxItem listBoxItem = null;
            FlaUI.Core.AutomationElements.Infrastructure.AutomationElement element = lookedElement;
            lookedElement = null;

            FlaUI.Core.Tools.Retry.WhileException(() =>
            {
                var temp = element ?? app.GetMainWindow(automation);
                listBoxItem = temp.FindFirstDescendant(cf => cf.ByAutomationId(value))?.AsListBoxItem();
                if (listBoxItem == null)
                {
                    listBoxItem = temp.FindFirstDescendant(cf => cf.ByName(value))?.AsListBoxItem();
                }

                if (listBoxItem is null)
                    throw new ElementNotFoundException(ExceptionMessagesProvider.CreateMessage(value));

            }, TimeSpan.FromMilliseconds(repeatingTime));
            return listBoxItem;
        }
        public void ListItemClickBy(string value, int repeatingTime = 0)
        {
            FlaUI.Core.AutomationElements.ListBoxItem listBoxItem = ListItemFindBy(value, repeatingTime);
            listBoxItem.Click();
        }
        public void ListItemDoubleClickBy(string value, int repeatingTime = 0)
        {
            FlaUI.Core.AutomationElements.ListBoxItem listBoxItem = ListItemFindBy(value, repeatingTime);
            listBoxItem.DoubleClick();
        }
        public void ListClickBy(string value, int id, int repeatingTime = 0)
        {
            FlaUI.Core.AutomationElements.ListBox listBox = ListFindBy(value, repeatingTime);
            var listBoxItem = listBox.FindAllChildren()[id].AsListBoxItem();
            listBoxItem.Click();
        }

        public bool ListItemExist(string value, int repeatingTime = 0)
        {
             FlaUI.Core.AutomationElements.ListBoxItem listBoxItem = ListItemFindBy(value, repeatingTime);

            if (listBoxItem != null)
            {
                return true;
            }
            else return false;
        }
        public bool ListItemExist(string value,int id, int repeatingTime = 0)
        {
            FlaUI.Core.AutomationElements.ListBox listBox = ListFindBy(value, repeatingTime);
            FlaUI.Core.AutomationElements.ListBoxItem listBoxItem = listBox.FindAllChildren()[id].AsListBoxItem();
            if (listBoxItem != null)
            {
                return true;
            }
            else return false;
        }

        public bool ListExist(string value, int repeatingTime = 0)
        {
            try
            {
                FlaUI.Core.AutomationElements.ListBox listBox = ListFindBy(value, repeatingTime);
            }
            catch(Exception ex)
            {
                if(ex is NullReferenceException)
                {
                    return false;
                }
               else if(ex.Message == "Timeout occurred in retry")
                {
                    return false;
                }
            }
           
            return true;
        }

        public void ListDoubleClickBy(string value, int id, int repeatingTime = 0)
        {
            FlaUI.Core.AutomationElements.ListBox listBox = ListFindBy(value, repeatingTime);
            FlaUI.Core.AutomationElements.ListBoxItem listBoxItem = listBox.FindAllChildren()[id].AsListBoxItem();
            listBoxItem.DoubleClick();
        }
      

        //Label

        private FlaUI.Core.AutomationElements.Label LabelFindBy(string value, int repeatingTime = 0)
        {
            FlaUI.Core.AutomationElements.Label label = null;
            FlaUI.Core.AutomationElements.Infrastructure.AutomationElement element = lookedElement;
            lookedElement = null;

            FlaUI.Core.Tools.Retry.WhileException(() =>
            {
                var temp = element ?? app.GetMainWindow(automation);
               
                label = temp.FindFirstDescendant(cf => cf.ByName(value))?.AsLabel();
                if (label == null)
                {
                     label = temp.FindFirstDescendant(cf => cf.ByAutomationId(value))?.AsLabel();
                }                            
                if (label is null)
                    throw new ElementNotFoundException(ExceptionMessagesProvider.CreateMessage(value));

            }, TimeSpan.FromMilliseconds(repeatingTime));
            return label;
        }

        public void LabelClickBy(string value, int repeatingTime = 0)
        {
            FlaUI.Core.AutomationElements.Label label = LabelFindBy(value, repeatingTime);
            label.Click();
        }
        public void LabelDoubleClickBy(string value, int repeatingTime = 0)
        {
            FlaUI.Core.AutomationElements.Label label = LabelFindBy(value, repeatingTime);
            label.DoubleClick();
        }
        public string LabelGetName(string value, int repeatingTime = 0)
        {
            FlaUI.Core.AutomationElements.Label label = LabelFindBy(value, repeatingTime);
            return label.Name;
        }
        public bool LabelExist(string value, int repeatingTime = 0)
        {
            try
            {
                FlaUI.Core.AutomationElements.Label label = LabelFindBy(value, repeatingTime);
            }
            catch (Exception ex)
            {
                if (ex is NullReferenceException)
                {
                    return false;
                }
                else if (ex.Message == "Timeout occurred in retry")
                {
                    return false;
                }
            }
            return true;
        }

        public bool LabelIsVisible(string value, int repeatingTime = 0)
        {
            FlaUI.Core.AutomationElements.Label label = LabelFindBy(value, repeatingTime);
            if (label.IsOffscreen == true)
                return false;
            return true;
        }

        //Progess bar

        private FlaUI.Core.AutomationElements.ProgressBar ProgressFindBy(string value, int repeatingTime = 0)
        {
            FlaUI.Core.AutomationElements.ProgressBar progress = null;
            FlaUI.Core.AutomationElements.Infrastructure.AutomationElement element = lookedElement;
            lookedElement = null;

            FlaUI.Core.Tools.Retry.WhileException(() =>
            {
                var temp = element ?? app.GetMainWindow(automation);

                progress = temp.FindFirstDescendant(cf => cf.ByName(value))?.AsProgressBar();
                if (progress == null)
                {
                    progress = temp.FindFirstDescendant(cf => cf.ByAutomationId(value))?.AsProgressBar();
                }
                if (progress is null)
                    throw new ElementNotFoundException(ExceptionMessagesProvider.CreateMessage(value));

            }, TimeSpan.FromMilliseconds(repeatingTime));
            return progress;
        }

        public void ProgressWaitBy(string value, int repeatingTime = 0)
        {
            FlaUI.Core.AutomationElements.ProgressBar progess = ProgressFindBy(value, repeatingTime);
            while(progess.Value != progess.Maximum)
            {
                Thread.Sleep(repeatingTime);                  
            }
        }

        //Horizontal & Vertical scrollbal

        public void VerticalScrollBy(int id, EnumProviderScrollBarsVertical type)
        {
            FlaUI.Core.AutomationElements.ListBox listBox = listBoxGeneral;
            FlaUI.Core.AutomationElements.Tree tree = treeGeneral;
            listBoxGeneral = null;
            treeGeneral = null;
            FlaUI.Core.AutomationElements.Scrolling.VerticalScrollBar verticalScrollBar = null;
            FlaUI.Core.AutomationElements.Infrastructure.AutomationElement[] elementArray = null;
            try
            {
                elementArray = tree.FindAllChildren();
            }
            catch (Exception ex)
            {
                try
                {
                    elementArray = listBox.FindAllChildren();
                }
                catch (Exception ex2) { System.Diagnostics.Debug.Write("Error: Before Finding ScrollBar, you must find tree or list, in which scrollbar is nested !"); }
            }

            verticalScrollBar = elementArray[id].AsVerticalScrollBar();

            switch (type)
            {
                case EnumProviderScrollBarsVertical.NormalUp:
                    verticalScrollBar.ScrollUp();
                    break;
                case EnumProviderScrollBarsVertical.LargeUp:
                    verticalScrollBar.ScrollUpLarge();
                    break;
                case EnumProviderScrollBarsVertical.NormalDown:
                    verticalScrollBar.ScrollDown();
                    break;
                case EnumProviderScrollBarsVertical.LargeDown:
                    verticalScrollBar.ScrollDownLarge();
                    break;
                default:
                    break;
            }
        }


        //CAPTURE OPERATIONS
        public void CaptureScreenshot(string location)
        {
            var image = Capture.Screen();
            image.ToFile(location);
        }

        //INPUT OPERATIONS
        public void MouseJump(int x, int y)
        {
            Mouse.Position = new Point(x, y);
        }

        public void MouseSlowMoveBy(int x, int y)
        {

        }

        public void MouseScroll(int x)
        {
            Mouse.Scroll(x);
        }
        public void MouseClick()
        {
            Mouse.Click(MouseButton.Left);
        }

        public void KeyBoardType(char c)
        {
            FlaUI.Core.Input.Keyboard.Type(c);
            // FlaUI.Core.Input.Keyboard.Type(VirtualKeyShort.SPACE);
        }

        public void KeyBoardTypeSpecialKeys(EnumProviderPressSpecialKeys keys)
        {
            switch (keys)
            {
                case EnumProviderPressSpecialKeys.Enter:
                    FlaUI.Core.Input.Keyboard.Type(VirtualKeyShort.ENTER);
                    break;
                case EnumProviderPressSpecialKeys.Space:
                    FlaUI.Core.Input.Keyboard.Type(VirtualKeyShort.SPACE);
                    break;
                case EnumProviderPressSpecialKeys.Backspace:
                    FlaUI.Core.Input.Keyboard.Type(VirtualKeyShort.BACK);
                    break;
                case EnumProviderPressSpecialKeys.ArrowUp:
                    FlaUI.Core.Input.Keyboard.Type(VirtualKeyShort.UP);
                    break;
                case EnumProviderPressSpecialKeys.ArrowDown:
                    FlaUI.Core.Input.Keyboard.Type(VirtualKeyShort.DOWN);
                    break;
                case EnumProviderPressSpecialKeys.ArrowLeft:
                    FlaUI.Core.Input.Keyboard.Type(VirtualKeyShort.LEFT);
                    break;
                case EnumProviderPressSpecialKeys.ArrowRight:
                    FlaUI.Core.Input.Keyboard.Type(VirtualKeyShort.RIGHT);
                    break;
                case EnumProviderPressSpecialKeys.Delete:
                    FlaUI.Core.Input.Keyboard.Type(VirtualKeyShort.DELETE);
                    break;               
                default:
                    break;
            }
        }

    }

}


