//-------------------------------------------------------------------------------------------------
// Module    : $RCSfile: AbstractUsabilityEvaluationTC.java,v $
// Version   : $Revision: 0.0 $  $Author: pharms $  $Date: 18.07.2012 $
// Project   : UsabilityEvaluationManager
// Creation  : 2012 by pharms
// Copyright : Patrick Harms, 2012
//-------------------------------------------------------------------------------------------------
package de.ugoe.cs.quest.usability;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;

import java.util.logging.Logger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.junit.Before;

import de.ugoe.cs.quest.tasktrees.testutils.DummyGUIElement;
import de.ugoe.cs.quest.tasktrees.testutils.DummyInteraction;
import de.ugoe.cs.quest.tasktrees.testutils.DummyTextField;
import de.ugoe.cs.quest.tasktrees.testutils.SimpleLogFormatter;
import de.ugoe.cs.quest.tasktrees.treeifc.Iteration;
import de.ugoe.cs.quest.tasktrees.treeifc.Selection;
import de.ugoe.cs.quest.tasktrees.treeifc.Sequence;
import de.ugoe.cs.quest.tasktrees.treeifc.TaskTree;
import de.ugoe.cs.quest.tasktrees.treeifc.TaskTreeBuilder;
import de.ugoe.cs.quest.tasktrees.treeifc.TaskTreeNode;
import de.ugoe.cs.quest.tasktrees.treeifc.TaskTreeNodeFactory;
import de.ugoe.cs.quest.tasktrees.treeifc.TextInputInteractionTask;
import de.ugoe.cs.quest.tasktrees.treeimpl.TaskTreeBuilderImpl;
import de.ugoe.cs.quest.tasktrees.treeimpl.TaskTreeNodeFactoryImpl;

//-------------------------------------------------------------------------------------------------
/**
 * TODO comment
 * 
 * @version $Revision: $ $Date: 18.07.2012$
 * @author 2012, last modified by $Author: pharms$
 */
//-------------------------------------------------------------------------------------------------
public class AbstractUsabilityEvaluationTC
{
  
  /** */
  private TaskTreeBuilder mTaskTreeBuilder = new TaskTreeBuilderImpl();

  /** */
  private TaskTreeNodeFactory mTaskTreeNodeFactory = new TaskTreeNodeFactoryImpl();
  
  //-----------------------------------------------------------------------------------------------
  /**
   *
   */
  //-----------------------------------------------------------------------------------------------
  @Before
  public void setUp()
  {
    Logger.getLogger("").getHandlers()[0].setFormatter(new SimpleLogFormatter());
  }

  //-----------------------------------------------------------------------------------------------
  /**
   *
   */
  //-----------------------------------------------------------------------------------------------
  protected TaskTree createTaskTree(String spec)
  {
    Matcher matcher =
      Pattern.compile("(\\s*(\\w+)\\s*(\\(((\\w*\\s*)*)\\))?\\s*(\\{))|(\\})").matcher(spec);
      
    if (!matcher.find())
    {
      if (!matcher.hitEnd())
      {
        throw new IllegalArgumentException("could not parse task specification");
      }
    }

    return mTaskTreeNodeFactory.createTaskTree(parseTask(matcher, new int[1]));
  }

  //-----------------------------------------------------------------------------------------------
  /**
   * TODO: comment
   *
   * @param expectedDefects
   * @param evaluateUsability
   */
  //-----------------------------------------------------------------------------------------------
  protected void assertUsabilityEvaluationResult(UsabilityDefect[]         expectedDefects,
                                                 UsabilityEvaluationResult evaluationResult)
  {
    assertEquals(expectedDefects.length, evaluationResult.getAllDefects().size());
    
    EXPECTED_DEFECT_ITERATION:
    for (UsabilityDefect expectedDefect : expectedDefects)
    {
      for (UsabilityDefect defect : evaluationResult.getAllDefects())
      {
        if (expectedDefect.equals(defect))
        {
          System.err.println(defect.getParameterizedDescription());
          continue EXPECTED_DEFECT_ITERATION;
        }
      }
      
      for (UsabilityDefect defect : evaluationResult.getAllDefects())
      {
        System.err.println(defect);
      }
      
      fail("expected defect " + expectedDefect + " not found in evaluation result");
    }
  }


  //-----------------------------------------------------------------------------------------------
  /**
   * 
   */
  //-----------------------------------------------------------------------------------------------
  private TaskTreeNode parseTask(Matcher tokenMatcher, int[] typeNumbers)
  {
    String firstToken = tokenMatcher.group();
    
    if ("}".equals(firstToken))
    {
      throw new IllegalArgumentException("found a closing bracket at an unexpected place");
    }
    
    TaskTreeNode treeNode = instantiateTreeNode(tokenMatcher, typeNumbers);
    
    if (!tokenMatcher.find())
    {
      throw new IllegalArgumentException("could not parse task specification");
    }
    
    firstToken = tokenMatcher.group();
    
    if (!"}".equals(firstToken))
    {
      TaskTreeNode child = null;
    
      do
      {
        child = parseTask(tokenMatcher, typeNumbers);
        
        if (child != null)
        {
          addChild(treeNode, child);
          
          if (!tokenMatcher.find())
          {
            throw new IllegalArgumentException("could not parse task specification");
          }
          
          firstToken = tokenMatcher.group();
          
          if ("}".equals(firstToken))
          {
            break;
          }
        }
        
      }
      while (child != null);
      
    }
    
    return treeNode;
  }

  //-----------------------------------------------------------------------------------------------
  /**
   * TODO: comment
   *
   * @param group
   * @return
   */
  //-----------------------------------------------------------------------------------------------
  private TaskTreeNode instantiateTreeNode(Matcher tokenMatcher, int[] typeNumbers)
  {
    String type = tokenMatcher.group(2);
    String additionalInfo = tokenMatcher.group(4);
    
    if ("Interaction".equals(type))
    {
      return mTaskTreeNodeFactory.createNewInteractionTask
        (new DummyGUIElement("dummy"), new DummyInteraction("dummy", typeNumbers[0]++));
    }
    else if ("Sequence".equals(type))
    {
      return mTaskTreeNodeFactory.createNewSequence();
    }
    else if ("Iteration".equals(type))
    {
      return mTaskTreeNodeFactory.createNewIteration();
    }
    else if ("Selection".equals(type))
    {
      return mTaskTreeNodeFactory.createNewSelection();
    }
    else if ("TextInput".equals(type))
    {
      if (additionalInfo == null)
      {
        fail("no simulated text provided for text input interactin task");
      }
      
      TextInputInteractionTask task =
        mTaskTreeNodeFactory.createNewTextInputInteractionTask(new DummyTextField(additionalInfo));
     
      task.setEnteredText(additionalInfo);
      return task;
    }
    else
    {
      fail("invalid type of task tree node: " + type);
      return null;
    }
  }

  //-----------------------------------------------------------------------------------------------
  /**
   * TODO: comment
   *
   * @param treeNode
   * @param child
   */
  //-----------------------------------------------------------------------------------------------
  private void addChild(TaskTreeNode parent, TaskTreeNode child)
  {
    if (parent instanceof Sequence)
    {
      mTaskTreeBuilder.addChild((Sequence) parent, child);
    }
    else if (parent instanceof Iteration)
    {
      if (parent.getChildren().size() <= 0)
      {
        mTaskTreeBuilder.setChild((Iteration) parent, child);
      }
      else
      {
        fail("can not add more than one child to an iteration");
      }
    }
    else if (parent instanceof Selection)
    {
      mTaskTreeBuilder.addChild((Selection) parent, child);
    }
    else if (parent instanceof TextInputInteractionTask)
    {
      mTaskTreeBuilder.addChild((TextInputInteractionTask) parent, child);
    }
    else
    {
      fail("can not add children to parent task tree node of type " + parent.getClass().getName());
    }
  }

}
