IntegerMan/angularIF

View on GitHub
src/app/engine/parser/command.ts

Summary

Maintainability
A
0 mins
Test Coverage
import {CommandToken} from './command-token';
import {VerbHandler} from '../verbs/verb-handler';
import {CommandContext} from '../command-context';
import {TokenClassification} from './token-classification.enum';
import {CommandResult} from '../command-result';

/**
 * Represents an arrangement of tokens into a sentence structure that can be handed off to a verb interpreter. At present, sentences are
 * assumed to be imperative only (e.g. "Open the door" or "Throw the ball from the attic at the stupid gray cat"
 */
export class Command {


  userInput: string;
  tokens: CommandToken[];

  verb: CommandToken;
  subject: CommandToken;
  objects: CommandToken[];
  verbHandler: VerbHandler;
  result: CommandResult;
  prepositions: any;
  hasPrepositions: boolean = false;

  constructor(userInput: string) {

    // Farm out parameters
    this.userInput = userInput;

    // Initialize empty collections
    this.objects = [];
    this.tokens = [];
    this.prepositions = {};
  }

  public execute(context: CommandContext): CommandResult {

    // This is decently important to log
    context.logger.debug(`Handling command associated with sentence ${this.userInput}.`);
    context.logger.debug(this);

    // We have to have a verb here
    if (!this.verb) {

      context.analytics.emitEvent(
        'No Verb',
        this.userInput,
        `${context.story.title} - ${context.currentRoom.name}`,
        context.ifService.commandId);

      context.outputService.displayParserError('I couldn\'t figure out what you want to do. Try starting with a verb.');
      return CommandResult.BuildParseFailedResult();
    }

    // If we don't have a verb handler for the verb in question, display a generic error message
    if (!this.verbHandler) {

      context.analytics.emitEvent(
        'Unknown Verb',
        this.verb.name,
        `${context.story.title} - ${context.currentRoom.name}`,
        context.ifService.commandId);

      context.outputService.displayParserError(`I don't know how to respond to the verb '${this.verb.name}' yet.`);
      return CommandResult.BuildParseFailedResult();
    }

    // Give the room a chance to veto any command
    if (!context.currentRoom.allowCommand(this, context)) {
      return CommandResult.BuildActionFailedResult();
    }

    return this.verbHandler.handleCommand(this, context);

  }

  getFirstDirection(): CommandToken {
    let direction: CommandToken = null;

    const directions: CommandToken[] = this.objects.filter(o => o.classification === TokenClassification.Direction);
    if (directions && directions.length > 0) {
      direction = directions[0];
    }

    return direction;
  }

  addPreposition(preposition: CommandToken): void {
    this.prepositions[preposition.name] = preposition;
    this.hasPrepositions = true;
  }

  getProposition(preposition: string): CommandToken {
    return this.prepositions[preposition];
  }

  getPrepositionWithFallbacks(prepNames: string[]): CommandToken {

    for (const prep of prepNames) {

      // Try the next preposition in line
      const prepToken: CommandToken = this.getProposition(prep);

      // If we've found it, return it
      if (prepToken) {
        return prepToken;
      }

    }

    return null;
  }

  get isTargetingAll(): boolean {
    return this.tokens.filter(t => t.name === 'all' || t.name === 'everything').length > 0;
  }

}