%{

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <malloc.h>
#include "MissionPlan.h"
#include "BehaviorFactory.h"
#include "Syslog.h"

Boolean debug = False;


// Function prototypes
int yyerror(char *errorBuf);
int yylex();
int yyparse();

char parseErrorBuf[512];

const int eofReturn = -1;
const int errorReturn = 1;
const int okReturn = 0;

/* Function prototypes */
int mplanFileLineNo();


void clearInputs();

BehaviorStack *_behaviorStack;
BehaviorFactory *_behaviorFactory = BehaviorFactory::instanceOf();
Behavior *_behavior = 0;

AttributeInputs attributeInputs;

%}

%union 
{
  int integer;
  char *string;
}

%token <string> Word
%token BehaviorTag 

%%

MissionPlan: Behaviors
{
}


Behaviors: Behaviors Behavior
{
}


Behaviors: Behavior
{
}


Behavior: StartBehavior Attributes '}'
{
  dprintf("Finished parsing Behavior %s\n", _behavior->name());

  Boolean error = False;
  for (int i = 0; i < attributeInputs.size(); i++) {
    Attribute::Input *input;
    attributeInputs.get(i, &input);

    if (_behavior->attributes.parse(input) == -1) {
      error = True;
    }
  }

  if (error) {
    sprintf(parseErrorBuf, "Parse failed for one or more attribute inputs");
    return errorReturn;
  }

  if (_behavior->attributes.verify() == -1) {
    sprintf(parseErrorBuf, "verify() failed for behavior %s\n", 
	    _behavior->name());
    error = True;
  }

  if (!_behavior->validInput()) {
    sprintf(parseErrorBuf, "validInput() failed for behavior %s\n", 
	    _behavior->name());

    error = True;    
  }

  if (!error ) {

    // Add to stack
    _behaviorStack->add(&_behavior);
  }
  else {
    return errorReturn;
  }
}


Attributes: Attribute
{
  dprintf("Attributes\n");
};


Attributes: Attributes Attribute
{
  dprintf("Attributes\n");
};


Attribute: Word '=' Word ';'
{
  dprintf("Got Attribute:  %s = %s\n", $1, $3);

  Attribute::Input *input = new Attribute::Input($1, $3);

  if (_behavior->attributes.parse(input) == -1) {
    sprintf(parseErrorBuf, 
	    "Line %d: Invalid attribute for behavior %s: \"%s\"", 
	    mplanFileLineNo(), _behavior->name(), input->name);

    return errorReturn;
  }

  attributeInputs.add(&input);
}


StartBehavior: BehaviorTag Word '{'
{
  dprintf("StartBehavior %s\n", $2);
  const char *behaviorName = $2;

  clearInputs();

  if ((_behavior = _behaviorFactory->create(behaviorName)) == 0) {

    sprintf(parseErrorBuf, "Line %d: Unknown behavior type name: \"%s\"\n",
	    mplanFileLineNo(), behaviorName);

    return errorReturn;
  }
};



%%

extern char *yytext;

int yyerror(char *errorMsg)
{
  sprintf(parseErrorBuf, 
	  "Line %d: %s\noffending text: \"%s\"", 
	  mplanFileLineNo(), errorMsg, yytext);
  
  return 0;
}


void clearInputs()
{

  for (int i = 0; i < attributeInputs.size(); i++) {
    Attribute::Input *input;
    attributeInputs.get(i, &input);
    delete input;
  }

  attributeInputs.clear();
}


void MissionPlan::parse(FILE *fp, BehaviorStack *behaviorStack, 
			Boolean *error, char *errorMsg)
{
  int ret;
  extern FILE *yyin;

  _behaviorStack = behaviorStack;

  if (_behaviorStack) {
    _behaviorStack->clear();
  }

  *error = False;
  yyin = fp;
  
  if ((ret = yyparse()) != okReturn)
  {
    /* Error or end-of-file */
    if (ret == errorReturn)
    {
      *error = True;
      strcpy(errorMsg, parseErrorBuf);
    }
  }
  
  clearInputs();
  return;
}

