/**
 * Sets the current state of the stream listener.
 * 
 * @param pStateName The name of the state
 * @return An error if the state name is not recognized.
 */
UT_Error ODi_StreamListener::setState(const char* pStateName)
{
    
    UT_ASSERT(m_stateStack.getItemCount() == 0);
    UT_ASSERT(m_pCurrentState == NULL);
    _clear();
    
    m_pCurrentState = _createState(pStateName);
    m_deleteCurrentWhenPop = true;
    
    if (m_pCurrentState) {
        return UT_OK;
    } else {
        return UT_ERROR;
    }
}
/**
 * Push or pop the stack according to the action stated by the current state.
 */
void ODi_StreamListener::_handleStateAction ()
{
    ODi_StreamListener::StackCell stackCell;
    
    switch (m_stateAction.getAction()) {
        
        case ODi_ListenerStateAction::ACTION_PUSH:
        
            m_stateStack.push_back(
                ODi_StreamListener::StackCell(m_pCurrentState, m_deleteCurrentWhenPop));
                
            if (m_stateAction.getState() != NULL) {
                m_pCurrentState = m_stateAction.getState();
                m_deleteCurrentWhenPop = m_stateAction.getDeleteWhenPop();
            } else {
                
                if (!strcmp(m_stateAction.getStateName().c_str(),
                               "FontFaceDecls")) {
                                
                    m_pCurrentState = &m_fontFaceDecls;
                    m_deleteCurrentWhenPop = false;
                    
                } else {
                
                    m_pCurrentState = _createState(
                        m_stateAction.getStateName().c_str());
                        
                    m_deleteCurrentWhenPop = true;
                }
            }
            
            UT_ASSERT(m_pCurrentState);
            
            break;
            
            
        case ODi_ListenerStateAction::ACTION_POP:
            
            if (m_deleteCurrentWhenPop) {
                DELETEP(m_pCurrentState);
            } else {
                m_pCurrentState = NULL;
            }

            if (m_stateStack.getItemCount() > 0) {
                stackCell = m_stateStack.getLastItem();            
                m_pCurrentState = stackCell.m_pState;
                m_deleteCurrentWhenPop = stackCell.m_deleteWhenPop;
                
                m_stateStack.pop_back();
            }

            break;


        case ODi_ListenerStateAction::ACTION_POSTPONE:
            // If the state wants to come back later he shouldn't be deleted.
            //UT_ASSERT(!m_deleteCurrentWhenPop);
            
            ODi_Postpone_ListenerState* pPostponeState;
            
            if (m_stateAction.getState() != NULL) {
                pPostponeState = new ODi_Postpone_ListenerState(
                                                  m_stateAction.getState(),
                                                  m_stateAction.getDeleteWhenPop(),
                                                  *m_pElementStack);
            } else {
                ODi_ListenerState* pNewState;
                
                UT_ASSERT(!m_stateAction.getStateName().empty());
                
                pNewState = _createState(m_stateAction.getStateName().c_str());
                
                pPostponeState = new ODi_Postpone_ListenerState(
                                                  pNewState,
                                                  m_stateAction.getDeleteWhenPop(),
                                                  *m_pElementStack);
            }
            m_postponedParsing.addItem(pPostponeState);
            
            m_stateStack.push_back(
                ODi_StreamListener::StackCell(m_pCurrentState, m_deleteCurrentWhenPop));
                
            m_pCurrentState = pPostponeState;
            m_deleteCurrentWhenPop = false;
            
            UT_ASSERT(m_pCurrentState);
            
            break;
            
        case ODi_ListenerStateAction::ACTION_BRINGUPALL:
            
            {
                UT_sint32 i;
                bool comeBackAfter = m_stateAction.getComeBackAfter();
                            
                for (i=0; i<m_postponedParsing.getItemCount(); i++) {
                    _resumeParsing(m_postponedParsing[i]);
                }
                
                UT_VECTOR_PURGEALL(ODi_Postpone_ListenerState*, m_postponedParsing);
                m_postponedParsing.clear();
                
                if (!comeBackAfter) {
                    m_stateAction.popState();
                    this->_handleStateAction();
                }
            }
            
            break;
        
            
        case ODi_ListenerStateAction::ACTION_BRINGUP:
        
            if (m_postponedParsing.getItemCount() > 0) {
                    
                ODi_Postpone_ListenerState* pPostponedState;
                
                pPostponedState =
                    m_postponedParsing.getLastItem();
                    
                const UT_String& rStateName =
                    pPostponedState->getParserState()->getStateName();
                    
                if (rStateName == m_stateAction.getStateName()) {
                    
                    bool comeBackAfter = m_stateAction.getComeBackAfter();
                    
                    _resumeParsing(pPostponedState);
                    DELETEP(pPostponedState);
                    m_postponedParsing.pop_back();
                    
                    if (!comeBackAfter) {
                        m_stateAction.popState();
                        this->_handleStateAction();
                    }
                }
            }
            break;


        case ODi_ListenerStateAction::ACTION_REPEAT:
            UT_ASSERT(m_currentAction == ODI_NONE);
            
            m_currentAction = ODI_RECORDING;
            m_xmlRecorder.clear();
            m_elemenStackSize = m_pElementStack->getStackSize();
            break;


        case ODi_ListenerStateAction::ACTION_IGNORE:
            UT_ASSERT(m_currentAction == ODI_NONE);
            
            m_currentAction = ODI_IGNORING;
            
            UT_ASSERT(m_stateAction.getElementLevel() >= -1);
            UT_ASSERT((int)m_pElementStack->getStackSize() -
                      (m_stateAction.getElementLevel()+1) >= 0);
            
            m_elemenStackSize = m_pElementStack->getStackSize() -
                                (m_stateAction.getElementLevel()+1);
            break;
    };
}
void _testTree()
{
  // create 3 lvls for the initial tree
  //first lvl, max's turn, initial state of board
  _createNode(0,board); //create initial node for test_tree_head, current state = head at this point
  
  //second lvl, min's turn, 4 states
  //(top left corner, (4,4), (5,5), bottom right corner)
  char new_state[BOARD_SIZE][BOARD_SIZE];
  
  /*NOTE: x - 1, and y - 1 as array range from 0 -7, not 1 - 8 */

  /* top left corner */
  _createState(0,0,new_state,current_state->state);
  _createNode(0,new_state);
  /* (4,4) */
  _createState(3,3,new_state,current_state->state);
  _createNode(0,new_state);
  /* (5,5) */
  _createState(4,4,new_state,current_state->state);
  _createNode(0,new_state);
  /* bottom right corner */
  _createState(7,7,new_state,current_state->state);
  _createNode(0,new_state);
  
  /*third lvl, middle states have 4 children each, corners have 2 */
  /*NOTE: current state should point to child_head of top left corner node */
  current_state = current_state->child_head; //reset current state to firsts lvl's child_head
  
  /*NOTE: x - 1, and y - 1 as array range from 0 -7, not 1 - 8 */

  /* top left corner children = (1,2), (2,1) */
  _createState(0,1,new_state,current_state->state);
  _playerMove(0,0,0,1,new_state); //zero all slots between moves
  _createNode(0,new_state);
  _createState(1,0,new_state,current_state->state);
  _playerMove(0,0,1,0,new_state); //zero all slots between moves
  _createNode(0,new_state);

  /* (4,4) = (3,4), (4,3), (5,4), (4,5)*/
  _createState(2,3,new_state,current_state->next->state); //skip to next as current_state not reset
  _playerMove(3,3,2,3,new_state); //zero all slots between moves
  _createNode(1, new_state);  //reset current_state to next parent
  _createState(3,2,new_state,current_state->state);
  _playerMove(3,3,3,2,new_state); //zero all slots between moves
  _createNode(0,new_state);
  _createState(4,3,new_state,current_state->state);
  _playerMove(3,3,4,3,new_state); //zero all slots between moves
  _createNode(0,new_state);
  _createState(3,4,new_state,current_state->state);
  _playerMove(3,3,3,4,new_state); //zero all slots between moves
  _createNode(0,new_state);

  /* (5,5) = (4,5), (5,4), (5,6), (6,5) */
  _createState(3,4,new_state,current_state->next->state); //skip to next as current_state not reset
  _playerMove(4,4,3,4,new_state); //zero all slots between moves
  _createNode(1, new_state); //reset current-state to next parent
  _createState(4,3,new_state,current_state->state);
  _playerMove(4,4,4,3,new_state); //zero all slots between moves
  _createNode(0,new_state);
  _createState(4,5,new_state,current_state->state);
  _playerMove(4,4,4,5,new_state); //zero all slots between moves
  _createNode(0,new_state);
  _createState(5,4,new_state,current_state->state);
  _playerMove(4,4,5,4,new_state); //zero all slots between moves
  _createNode(0,new_state);

  /* bottom right corner = (8,7), (7,8) */
  _createState(7,6,new_state,current_state->next->state); //skip to next as current_state not reset
  _playerMove(7,7,7,6,new_state); //zero all slots between moves
  _createNode(1, new_state); //reset current-state to next parent
  _createState(6,7,new_state,current_state->state);
  _playerMove(7,7,6,7,new_state); //zero all slots between moves
  _createNode(0,new_state);

  // print tree and clean up memory
  _printTesttree(test_tree_head);
  _cleanTesttree(test_tree_head);

}