public function run()
    {
        $this->inputAttemptsUsed = 0;
        if ($this->executeBeforeRun !== null) {
            $callback = $this->executeBeforeRun;
            $callback($this);
        }
        for ($attempts = 0; $attempts < $this->totalAttemptsForInput; $attempts++) {
            $this->doInput();
            if ($this->wasCancelled()) {
                if ($this->cancelWithInputRetriesInput && $this->hasInput()) {
                    $this->logDebug("Cancelled input, retrying");
                    continue;
                }
                $this->logDebug("Cancelled node, quitting");
                break;
            }
            // dont play on last attempt by default
            if ($this->onNoInputMessage !== null
                && !$this->hasInput()
                && ($this->playOnNoInputInLastAttempt || $attempts != ($this->totalAttemptsForInput - 1))
            ) {
                $this->addPrePromptMessage($this->onNoInputMessage);
                continue;
            }
            if ($this->hasInput()) {
                if ($this->validate()) {
                    $this->logDebug("Input validated");
                    if ($this->executeOnValidInput !== null) {
                        $callback = $this->executeOnValidInput;
                        $this->beforeOnValidInput();
                        $callback($this);
                    }
                    break;
                } elseif ($this->executeAfterFailedValidation !== null) {
                    $callback = $this->executeAfterFailedValidation;
                    $callback($this);
                }
            }
        }
        $result = $this->playPrePromptMessages();
        if ($this->minInput > 0 && $attempts == $this->totalAttemptsForInput) {
            $this->logDebug("Max attempts reached");
            $this->state = self::STATE_MAX_INPUTS_REACHED;
            if ($this->onMaxValidInputAttempts !== null) {
                $this->callClientMethods(array(
                    array('streamFile' => array($this->onMaxValidInputAttempts, self::DTMF_ANY))
                ));
            }
        }
        if (!$this->isComplete() && $this->executeOnInputFailed !== null) {
            $callback = $this->executeOnInputFailed;
            $this->beforeOnInputFailed();
            $callback($this);
        }
        if ($this->executeAfterRun !== null) {
            $callback = $this->executeAfterRun;
            $callback($this);
        }

        $this->logDebug($this);
        return $this;
    }