#include "DemoIDEPch.h"
#include "common.h"

GUILoadedEffect* FindGUIEffect(MBStaticList<GUILoadedEffect*>* pslEntryList, SM_DemoEffect* pEffect)
{
  int              iIterator;
  GUILoadedEffect* pGUIEffect;

  for (iIterator = pslEntryList->First() ; iIterator != -1 ; iIterator = pslEntryList->Next(iIterator))
  {
    pslEntryList->Get(iIterator, pGUIEffect);
    if (pGUIEffect->DemoEffect() == pEffect)
    {
      return pGUIEffect;
    }
  }

  return 0;
}

GUICommand::GUICommand    ()
{
  m_pCommand = 0;
  m_iTick    = 0;
}

GUICommand::~GUICommand   ()
{
  Shutdown();
}

int GUICommand::Init(SM_DemoScript::TCommand* pCommand, int iTick)
{
  m_pCommand = pCommand->Clone();
  if (!m_pCommand)
  {
    return -1;
  }

  m_iTick = iTick;

  return 0;
}

int GUICommand::Shutdown()
{
  delete  m_pCommand;
  m_pCommand = 0;

  return 0;
}


bool GUICommandOrder::operator<(const GUICommandOrder& opB) const
{
  if (this->m_pCommand->m_iTick < opB.m_pCommand->m_iTick)
  {
    return true;
  }
  else if (this->m_pCommand->m_iTick == opB.m_pCommand->m_iTick)
  {
    if (this->m_pCommand->m_pCommand->GetCommand() == SM_DemoScript::TCommand::CM_FX_START)
    {
      return true;
    }
  }

  return false;
}


GUILoadedEffect::GUILoadedEffect()
{
  m_pDemoEffect     = 0;
  m_pcLoadArguments = 0;  
  m_bActive         = false;
}

GUILoadedEffect::~GUILoadedEffect()
{
  Shutdown();
}

int GUILoadedEffect::Init(SM_DemoEffect* pDemoEffect, const char* pcLoadArguments)
{
  m_pDemoEffect     = pDemoEffect;

  if (SetArguments(pcLoadArguments) != 0)
  {
    return -1;
  }
  
  if (m_Commands.Init() != 0)
  {
    delete[] m_pcLoadArguments;
    return -1;
  }



  return 0;
} 

int GUILoadedEffect::SetArguments(const char* pcLoadArguments)
{
  
  if (m_pcLoadArguments) delete[] m_pcLoadArguments;
  
  if (pcLoadArguments)
  {
    m_pcLoadArguments = new char[strlen(pcLoadArguments)+1];    
  }
  else
  {
    m_pcLoadArguments = new char[1];
  }

  if (!m_pcLoadArguments)
  {
    return -1;
  }

  if (pcLoadArguments)
  {
    strcpy(m_pcLoadArguments, pcLoadArguments);    
  }
  else
  {
    m_pcLoadArguments[0] = '\0';
  }

  return 0;
}

int GUILoadedEffect::Shutdown()
{
  int iIterator;

  GUICommand* pCommand;
  for (iIterator = First() ; iIterator != -1 ; iIterator = Next(iIterator) )
  {
    Get(iIterator, pCommand);
    delete pCommand;
  }

  m_Commands.Shutdown();

  if (m_pcLoadArguments)
  {
    delete[] m_pcLoadArguments;
    m_pcLoadArguments = 0;
  }

  return 0;
};



SM_DemoEffect*  GUILoadedEffect::DemoEffect                 ()
{
  return m_pDemoEffect;
}

const char*     GUILoadedEffect::LoadArguments              ()
{
  return m_pcLoadArguments;
}

int             GUILoadedEffect::First                      ()
{
  return m_Commands.First();
}

int             GUILoadedEffect::Last                       ()
{
  return m_Commands.Last();
}

int             GUILoadedEffect::Next                       (int iIterator)
{
  return m_Commands.Next(iIterator);
}

int             GUILoadedEffect::Previous                   (int iIterator)
{
  return m_Commands.Previous(iIterator);
}

int             GUILoadedEffect::Get                        (int iIterator, GUICommand*& pCommand)
{
  return m_Commands.Get(iIterator, pCommand);
}

#ifdef _DEBUG
void GUILoadedEffect::TestIntegrity()
{
  bool bInside = false;
  int iIterator;
  
  GUICommand* pCommand;
  for (iIterator = m_Commands.First() ; iIterator != -1 ; iIterator = m_Commands.Next(iIterator))
  {
    m_Commands.Get(iIterator, pCommand);      

    if (pCommand->m_pCommand->GetCommand() == SM_DemoScript::TCommand::CM_FX_START)
    {
      assert(!bInside);
      bInside = true;
    }
    else
    if (pCommand->m_pCommand->GetCommand() == SM_DemoScript::TCommand::CM_FX_STOP)
    {
      assert(bInside);
      bInside = false;
    }
  }

}
#endif

int             GUILoadedEffect::Insert                     (GUICommand* pCommand)
{
  GUICommandOrder Order;

  Order.m_pCommand = pCommand;
  
  int iIterator = -1;
  int iReturn = -1;
  bool bInside = false;

  GUICommand* pTemp;
  for (iIterator = m_Commands.First() ; iIterator != -1 ; iIterator = m_Commands.Next(iIterator))
  {
    m_Commands.Get(iIterator, pTemp);          

    int iSearch;
    if (pTemp->m_iTick == pCommand->m_iTick)          
    {
      // Insert in the last legal place posible
      bool bSearch = bInside;

      for (iSearch = iIterator ; iSearch != -1 ; iSearch = m_Commands.Next(iSearch))
      {
        m_Commands.Get(iSearch, pTemp);

        // First test if it's the last place we can insert
        if (pTemp->m_iTick != pCommand->m_iTick ||
            (pTemp->m_pCommand->GetCommand() != SM_DemoScript::TCommand::CM_FX_START &&
            pTemp->m_pCommand->GetCommand() != SM_DemoScript::TCommand::CM_FX_STOP))
        {
          return m_Commands.InsertBefore(iSearch, pCommand);
        }
        else
        {
          // Not last place. Have we to insert here?
          if (pTemp->m_pCommand->GetCommand() == SM_DemoScript::TCommand::CM_FX_START)
          {
            if (bSearch == true && pCommand->m_pCommand->GetCommand() == SM_DemoScript::TCommand::CM_FX_STOP)
            {
              return m_Commands.InsertBefore(iSearch, pCommand);
              
            }
            
            bSearch = true;
          }
          else 
          if (pTemp->m_pCommand->GetCommand() == SM_DemoScript::TCommand::CM_FX_STOP)
          {
            if (bSearch == false && pCommand->m_pCommand->GetCommand() == SM_DemoScript::TCommand::CM_FX_START)
            {
              return m_Commands.InsertBefore(iSearch, pCommand);                
            }

            bSearch = false;
          }
          
        }
      }                          
    }
    else if (pTemp->m_iTick > pCommand->m_iTick)
    {
      // Found it. just insert it after rest of commands
      return m_Commands.InsertBefore(iIterator, pCommand);
    }

    if (pTemp->m_pCommand->GetCommand() == SM_DemoScript::TCommand::CM_FX_START)
    {
      bInside = true;
    }
    else
    if (pTemp->m_pCommand->GetCommand() == SM_DemoScript::TCommand::CM_FX_STOP)
    {
      bInside = false;
    }
  }    

  return m_Commands.InsertBefore(iIterator, pCommand);
}

#ifdef _DEBUG
void GUILoadedEffect::Dump()
{
  GUICommand* pCommand;
  int iIterator;
  for (iIterator = m_Commands.First() ; iIterator != -1 ; iIterator = m_Commands.Next(iIterator))
  {
    m_Commands.Get(iIterator, pCommand);      

    char pcText[1024];
    int iLength=1024;
    pCommand->m_pCommand->ToString(pcText, iLength);

    SM_Main::OutputDebug("%i: %s", pCommand->m_iTick, pcText);
  }
}
#endif

int             GUILoadedEffect::Delete                     (int iID, bool bDeleteCommand)
{
  GUICommand* pCommand;
  m_Commands.Get(iID, pCommand);  

  if (bDeleteCommand)
  {
    delete pCommand->m_pCommand;
    pCommand->m_pCommand = 0;
  }

  return m_Commands.Delete(iID);
}

bool            GUILoadedEffect::IsTickInActiveRange        (int iTick)
{
  bool bInside = false;
  int iIterator;
  
  GUICommand* pCommand;
  for (iIterator = m_Commands.First() ; iIterator != -1 ; iIterator = m_Commands.Next(iIterator))
  {
    m_Commands.Get(iIterator, pCommand);      

    if (iTick <= pCommand->m_iTick)
    {
      return bInside;
    }

    if (pCommand->m_pCommand->GetCommand() == SM_DemoScript::TCommand::CM_FX_START)
    {
      assert(!bInside);
      bInside = true;
    }
    else
    if (pCommand->m_pCommand->GetCommand() == SM_DemoScript::TCommand::CM_FX_STOP)
    {
      assert(bInside);
      bInside = false;
    }    
  }
  
  return false;
}

int             GUILoadedEffect::GetEndCommand(int iStartCommand)
{
  GUICommand* pCommand;  
  GUICommand* pTemp;

  int iResult = m_Commands.Get(iStartCommand, pCommand);      
  assert(iResult != -1);

  // We get the start command and walk the list until we find a stop command. It assumes
  // the list will remain consistent
  assert(pCommand->m_pCommand->GetCommand() == SM_DemoScript::TCommand::CM_FX_START);
  if (pCommand->m_pCommand->GetCommand() != SM_DemoScript::TCommand::CM_FX_START)
  {
    return -1;
  }

  for (int iIterator = iStartCommand ; iIterator != -1 ; iIterator = m_Commands.Next(iIterator))
  {
    m_Commands.Get(iIterator, pTemp);      
    if (pTemp->m_pCommand->GetCommand() == SM_DemoScript::TCommand::CM_FX_STOP)
    {
      return iIterator;
    }
  }

  assert(!"Did not find stop!");
  return -1;
}

int             GUILoadedEffect::GetStartCommand(int iEndCommand)
{
  GUICommand* pCommand;  
  GUICommand* pTemp;

  int iResult = m_Commands.Get(iEndCommand, pCommand);      
  assert(iResult != -1);

  // We get the start command and walk the list until we find a start command. It assumes
  // the list will remain consistent
  assert(pCommand->m_pCommand->GetCommand() == SM_DemoScript::TCommand::CM_FX_STOP);
  if (pCommand->m_pCommand->GetCommand() != SM_DemoScript::TCommand::CM_FX_STOP)
  {
    return -1;
  }

  for (int iIterator = iEndCommand ; iIterator != -1 ; iIterator = m_Commands.Previous(iIterator))
  {
    m_Commands.Get(iIterator, pTemp);      
    if (pTemp->m_pCommand->GetCommand() == SM_DemoScript::TCommand::CM_FX_START)
    {
      return iIterator;
    }
  }

  assert(!"Did not find start!");
  return -1;
}


bool GUILoadedEffect::CanMoveWithoutIntersection(int iCommand, int iToTick)
{
  GUICommand* pCommand;    
  int iResult = m_Commands.Get(iCommand, pCommand);      
  assert(iResult != -1);

  // We will start from the command and go forward or backwards as required. If we go across
  // a FXSTART or FXSTOP, then we have an intersection, so we return false.

  bool bForward = iToTick >= pCommand->m_iTick;
  
  // search
  for (int iIterator = bForward?
            m_Commands.Next(iCommand):
            m_Commands.Previous(iCommand) ; 
       iIterator != -1 ; 
       iIterator = bForward?
            m_Commands.Next(iIterator):
            m_Commands.Previous(iIterator))
  {
    GUICommand* pTemp;
    m_Commands.Get(iIterator, pTemp);          
    
    // Are we done?
    if (bForward)
    {
      if (pTemp->m_iTick >= iToTick)
      {
        // Done
        return true;
      }
    }
    else
    {
      if (pTemp->m_iTick <= iToTick)
      {
        // Done
        return true;
      }
    }    

    if (pTemp->m_pCommand->GetCommand() == SM_DemoScript::TCommand::CM_FX_START ||
        pTemp->m_pCommand->GetCommand() == SM_DemoScript::TCommand::CM_FX_STOP)
    {
      // Crossed boundary
      return false;
    }

  }
  
  return true;
} 

void GUILoadedEffect::SetActive(bool bActive)
{
  m_bActive = bActive;
}

bool GUILoadedEffect::GetActive()
{
  return m_bActive;
}

