text: /*
  * Copyright 2011 Software Freedom Conservancy
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
  *  You may obtain a copy of the License at
  *
  *      http://www.apache.org/licenses/LICENSE-2.0
  *
  *  Unless required by applicable law or agreed to in writing, software
  *  distributed under the License is distributed on an "AS IS" BASIS,
  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  *  See the License for the specific language governing permissions and
  *  limitations under the License.
  */
  
  function TestLoop(commandFactory) {
      this.commandFactory = commandFactory;
  }
  
  TestLoop.prototype = {
  
      start : function() {
          selenium.reset();
          LOG.debug("currentTest.start()");
          this.continueTest();
      },
  
      continueTest : function() {
          /**
           * Select the next command and continue the test.
           */
          LOG.debug("currentTest.continueTest() - acquire the next command");
          if (! this.aborted) {
              this.currentCommand = this.nextCommand();
          }
          if (! this.requiresCallBack) {
              this.continueTestAtCurrentCommand();
          } // otherwise, just finish and let the callback invoke continueTestAtCurrentCommand()
      },
  
      continueTestAtCurrentCommand : function() {
          LOG.debug("currentTest.continueTestAtCurrentCommand()");
          if (this.currentCommand) {
              // TODO: rename commandStarted to commandSelected, OR roll it into nextCommand
              this.commandStarted(this.currentCommand);
              this._resumeAfterDelay();
          } else {
              this._testComplete();
          }
      },
  
      _resumeAfterDelay : function() {
          /**
           * Pause, then execute the current command.
           */
  
          // Get the command delay. If a pauseInterval is set, use it once
          // and reset it.  Otherwise, use the defined command-interval.
          var delay = this.pauseInterval || this.getCommandInterval();
          this.pauseInterval = undefined;
  
          if (this.currentCommand.isBreakpoint || delay < 0) {
              // Pause: enable the "next/continue" button
              this.pause();
          } else {
              window.setTimeout(fnBind(this.resume, this), delay);
          }
      },
  
      resume: function() {
          /**
           * Select the next command and continue the test.
           */
          LOG.debug("currentTest.resume() - actually execute");
          try {
              selenium.browserbot.runScheduledPollers();
              this._executeCurrentCommand();
              this.continueTestWhenConditionIsTrue();
          } catch (e) {
              if (!this._handleCommandError(e)) {
                  this.testComplete();
              } else {
                  this.continueTest();
              }
          }
      },
  
      _testComplete : function() {
          selenium.ensureNoUnhandledPopups();
          this.testComplete();
      },
  
      _executeCurrentCommand : function() {
          /**
           * Execute the current command.
           *
           * @return a function which will be used to determine when
           * execution can continue, or null if we can continue immediately
           */
          var command = this.currentCommand;
          LOG.info("Executing: |" + command.command + " | " + command.target + " | " + command.value + " |");
  
          if (Math.random() > 0.8) {
              LOG.info("Selenium 1.0 (Core, RC, etc) is no longer under active development. Please update to WebDriver ASAP");
          }
  
          var handler = this.commandFactory.getCommandHandler(command.command);
          if (handler == null) {
              throw new SeleniumError("Unknown command: '" + command.command + "'");
          }
  
          command.target = selenium.preprocessParameter(command.target);
          command.value = selenium.preprocessParameter(command.value);
          LOG.debug("Command found, going to execute " + command.command);
          this.result = handler.execute(selenium, command);
          
  
          this.waitForCondition = this.result.terminationCondition;
  
      },
  
      _handleCommandError : function(e) {
          if (!e.isSeleniumError) {
              LOG.exception(e);
              var msg = "Command execution failure. Please search the user group at https://groups.google.com/forum/#!forum/selenium-users for error details from the log window.";
              msg += "  The error message is: " + extractExceptionMessage(e);
              return this.commandError(msg);
          } else {
              LOG.error(e.message);
              return this.commandError(e.message);
          }
      },
  
      continueTestWhenConditionIsTrue: function () {
          /**
           * Busy wait for waitForCondition() to become true, and then carry
           * on with test.  Fail the current test if there's a timeout or an
           * exception.
           */
          //LOG.debug("currentTest.continueTestWhenConditionIsTrue()");
          selenium.browserbot.runScheduledPollers();
          try {
              if (this.waitForCondition == null) {
                  LOG.debug("null condition; let's continueTest()");
                  LOG.debug("Command complete");
                  this.commandComplete(this.result);
                  this.continueTest();
              } else if (this.waitForCondition()) {
                  LOG.debug("condition satisfied; let's continueTest()");
                  this.waitForCondition = null;
                  LOG.debug("Command complete");
                  this.commandComplete(this.result);
                  this.continueTest();
              } else {
                  //LOG.debug("waitForCondition was false; keep waiting!");
                  window.setTimeout(fnBind(this.continueTestWhenConditionIsTrue, this), 10);
              }
          } catch (e) {
              this.result = {};
              this.result.failed = true;
              this.result.failureMessage = extractExceptionMessage(e);
              this.commandComplete(this.result);
              this.continueTest();
          }
      },
  
      pause : function() {},
      nextCommand : function() {},
      commandStarted : function() {},
      commandComplete : function() {},
      commandError : function() {},
      testComplete : function() {},
  
      getCommandInterval : function() {
          return 0;
      }
  
  }
  