protected override string DoImpl()
        {
            var haveElement = this.ExecutedCommand.Parameters.ContainsKey("element");
            var havePoint   = this.ExecutedCommand.Parameters.ContainsKey("x") &&
                              this.ExecutedCommand.Parameters.ContainsKey("y");

            if (!(haveElement || havePoint))
            {
                // TODO: in the future '400 : invalid argument' will be used
                return(this.JsonResponse(ResponseStatus.UnknownError, "WRONG PARAMETERS"));
            }

            bool             success;
            CruciatusElement element = null;
            var x = 0;
            var y = 0;

            if (haveElement)
            {
                var registeredKey = this.ExecutedCommand.Parameters["element"].ToString();
                element = this.Automator.ElementsRegistry.GetRegisteredElement(registeredKey);
            }

            if (havePoint)
            {
                x = this.ExecutedCommand.GetParameterAsInt("x");
                y = this.ExecutedCommand.GetParameterAsInt("y");
            }

            var duration = this.ExecutedCommand.Parameters.ContainsKey("duration")
                               ? this.ExecutedCommand.GetParameterAsInt("duration")
                               : 1000;

            if (haveElement && havePoint)
            {
                success = TouchSimulator.LongTap(element, x, y, duration);
            }
            else if (haveElement)
            {
                success = TouchSimulator.LongTap(element, duration);
            }
            else
            {
                success = TouchSimulator.LongTap(x, y, duration);
            }

            return(success
                ? this.JsonResponse()
                : this.JsonResponse(ResponseStatus.UnknownError, "Touch input failed"));
        }
        private static bool Perform(List <TouchAction> actions)
        {
            var    previousX      = 0;
            var    previousY      = 0;
            var    havePrevious   = false;
            string previousAction = null;

            for (var i = 0; i < actions.Count; i++)
            {
                var action = actions[i];

                Point point;

                switch (action.Action)
                {
                case TouchAction.LongPress:
                    point = action.GetLocation();
                    TouchSimulator.LongTap((int)point.X, (int)point.Y, action.MiliSeconds);
                    havePrevious = false;
                    break;

                case TouchAction.MoveTo:
                    int?duration = null;
                    if (i > 0 && actions[i - 1].Action == TouchAction.Wait)
                    {
                        duration = actions[i - 1].MiliSeconds;
                    }
                    point = action.GetLocation();
                    var x = (int)point.X;
                    var y = (int)point.Y;
                    TouchSimulator.MoveTo(previousX, previousY, previousX + x, previousY + y, duration);
                    previousX   += x;
                    previousY   += y;
                    havePrevious = true;
                    break;

                case TouchAction.Press:
                    point = action.GetLocation();
                    TouchSimulator.TouchDown((int)point.X, (int)point.Y);
                    previousX    = (int)point.X;
                    previousY    = (int)point.Y;
                    havePrevious = true;
                    break;

                case TouchAction.Release:
                    if (previousAction == TouchAction.Tap || previousAction == TouchAction.LongPress)
                    {
                        break;
                    }
                    TouchSimulator.TouchUp(previousX, previousY);
                    havePrevious = false;
                    break;

                case TouchAction.Tap:
                    point = action.GetLocation();
                    for (var n = 1; n <= action.Count; n++)
                    {
                        TouchSimulator.Tap((int)point.X, (int)point.Y);
                        Thread.Sleep(250);
                    }
                    havePrevious = false;
                    break;

                case TouchAction.Wait:
                    if (actions.Count > i + 1 && actions[i + 1].Action == TouchAction.MoveTo)
                    {
                        break;
                    }
                    if (havePrevious)
                    {
                        var startTime = DateTime.Now;
                        while (DateTime.Now < startTime + TimeSpan.FromMilliseconds(action.MiliSeconds))
                        {
                            TouchSimulator.TouchUpdate(previousX, previousY);
                            Thread.Sleep(16);
                        }
                    }
                    else
                    {
                        Thread.Sleep(action.MiliSeconds);
                    }
                    break;

                default:
                    throw new AutomationException($"unrecognised action {action.Action}");
                }

                previousAction = action.Action;
            }

            return(true);
        }