#include "SM_CommonFXPCH.h"
#include "SM_DemoEffect.h"
#include "MSurface.h"
#include "SM_Screen.h"
#include "SM_Main.h"
#include "MSystemFunctions.h"
#include "SM_Sound.h"


static  SM_DemoEffect::Helper  LoadHelp[] =
{
  {"nimages framelength name1 name2 ... namen", "nimages: number of images\r\nframelength: how much time each frame will be displayed\r\nNote: Images will be loaded from data/images/"},
};

static SM_DemoEffect::Helper CommandsHelp[] =
{
  {"POSITION iFrame x y","Updates position of iFrame(from 0 to nimages-1)"},
  {"POSITIONALL x y", "Updates positions of all frames"},
  {"VELOCITY x y", "velocity moving in pixels per second"},
  {"BLEND ADDITIVE", "sets image blend to additive"},
  {"BLEND SUBSTRACTIVE", "sets image blend to substractive"},
  {"BLEND MULTIPLY", "sets image blend to multiply"},
  {"BLEND NORMAL", "sets image blend to normal"},
  {"BLEND INVERT", "sets image blend to invert"},
  {"FADEIN time", "does a fade in"},
  {"FADEOUT time", "does a fade out"},
  {"FADESOUNDSYNC BEAT fadetime", ""},
  {"FADESOUNDSYNC RAW startamplitude endamplitude startfreq endfreq", "usa el soundsyncer para seleccionar el fade start/endamplitude: rango amplitud (0.0f-1.0f). startfreq y endfreq: frecuencias a  examinar (0.0f-1.0f)"},
  {"FADESOUNDSYNC OFF", "deshabilita soundsyncer para imagen"},
  {"ZOOM start speed", "makes zoom of image"},
  {"ZOOM 1.0  1.0", "Zoom out"},
  {"ZOOM 1.0 -1.0", "Zoom In"},

};


class StillFX : public SM_DemoEffect
{
public:              
  StillFX(char const* pcName) : SM_DemoEffect(pcName)
  {    
    m_fFrameTime=1.0f;
    m_piImages=0;
    m_pfPositions=0;
    m_iImages=0;

    m_bFadeIn=false;
    m_bFadeOut=false;
    m_bFadeSoundSync=false;
    m_bFadeBeat=false;

    m_fStartTime=0.0f;
    m_fDuration=0.0f;    

    m_fSpeedX = 0.0f;
    m_fSpeedY = 0.0f;
    m_fSetPosTime = 0.0f;

    m_fZoomStart = 1.0f;
    m_fZoomSpeed = 0.0f;    
    m_fZoomTime  = 0.0f;
  }

  virtual          ~StillFX()
  {
  }

  int      LoadArgumentsHelp     (Helper*& pHelpers)
  {
    pHelpers = LoadHelp;
    return (sizeof(LoadHelp)/sizeof(Helper));
  }

  int      CommandArgumentsHelp  (Helper*& pHelpers)
  {
    pHelpers = CommandsHelp;
    return (sizeof(CommandsHelp)/sizeof(Helper));
  }

  int      Init(const char* pcCommand)
  {
    char  pcPath[256];
    int iReturn = -1;

    char* pcCopy=new char[strlen(pcCommand)+1];

    strcpy(pcCopy, pcCommand);


    Shutdown();
    char* pcToken=strtok(pcCopy, " \t");
    
    m_iImages=SafeAtoi(pcToken);
    m_piImages=new int[m_iImages];
    m_pfPositions=new float[m_iImages*2];

    pcToken=strtok(0, " \t");
    if (!pcToken)
    {
      return -1;
    }

    m_fFrameTime=(float) SafeAtof(pcToken);

    
          
    int i;
    for (i=0 ; i<m_iImages ; i++)
    {      
      m_pfPositions[i*2  ]=0.0f;
      m_pfPositions[i*2+1]=0.0f;

      pcToken=strtok(0, " \t");

      if (!pcToken)
      { 
        SM_Main::OutputError("Numero de ficheros es menor que el numero de imagenes que has puesto: %s", pcCommand);
        return -1;
      }
    

      strcpy(pcPath, "data/images/");

      char pcAux[256];
      MExtractBasename(pcAux, pcToken);
      strcat(pcPath, pcAux);    

      if (strcmp(pcToken, "_")==0)        
      {
        m_piImages[i]=-1;
      }
      else
      {
        if ( (m_piImages[i]=ScreenManager::LoadImagen(pcPath))==-1)
        {
          SM_Main::OutputError("Error loading %s", pcPath);
          goto EXIT;
        }
      }
    }    

    m_bLoaded= true;
  
    iReturn  = 0;

    
EXIT:
    if (pcCopy) { delete[] pcCopy; pcCopy=0; }
    return iReturn;
  }

  int      Shutdown()
  {
    m_iImages=0;
    if (m_piImages) { delete[] m_piImages; m_piImages=0; }
    if (m_pfPositions) { delete[] m_pfPositions; m_pfPositions=0; }
    
    return (0);
  }

  int      Start(float fTime)
  {
    m_fStartTime  = fTime;
    m_fSetPosTime = fTime;
    m_fZoomTime   = fTime;
    return (0);
  }

  int      Stop()
  {
    return (0);
  }

  int      Reset()
  {
    m_bFadeIn = m_bFadeOut = false;
    m_Blend=ScreenManager::E_NORMAL;
    m_fSpeedX = m_fSpeedY = 0.0f;
    m_fZoomStart = 1.0f;
    m_fZoomSpeed = 0.0f;
    return (0);
  }

  int      Run(float fTime)
  {
    if (m_bLoaded)
    {
      float fAnimTime=fTime-m_fStartTime;

      int iFrame;
      if (m_iImages!=0)
      {
        iFrame=(int(fAnimTime/m_fFrameTime))%m_iImages;
      }
      else
      {
        iFrame=0;
      }

    
      if (m_piImages)
      {
        if (m_piImages[iFrame]!=-1)
        {
          bool bPaint=false;
          unsigned uColor;
          float fAlpha = 1.0f;

          if (m_bFadeIn || m_bFadeOut)
          {
            float fFade;

            if (!m_fDuration)
            {
              fFade=1.0f;
            }
            else
            {
              fFade=(fTime-m_fFadeStartTime)/m_fDuration;
            }

            
            if (fFade>=1.0f)
            {
              fFade=1.0f;                            
            }


            bPaint=true;

            fAlpha=m_bFadeIn?(1.0f-fFade):fFade;                                            
          }

          if (m_bFadeBeat)
          {
            if (SM_Sound::IsBeat(fTime))
            {
              m_fFadeStartTime = fTime;
            }

            float fFade=(fTime-m_fFadeStartTime)/m_fDuration;

            fFade=min(1.0f, max(0.0f, fFade));
            
            fAlpha=min(1.0f, max(0.0f, (1.0f-fFade)));
            bPaint=true;
          }

          if (m_bFadeSoundSync)
          {
            float* pfData;

            if (SM_Sound::GetFFT(fTime, pfData))
            {
              int iStart = m_fMinFrequency*float(SM_SOUND_DATASAMPLES-1);
              int iEnd   = m_fMaxFrequency*float(SM_SOUND_DATASAMPLES-1);
                  
              float fMax = 0.0f;
              int i;
              for (i = iStart ; i < iEnd ; i++)
              {
                fMax = max(fMax, pfData[i]);
              }

              fAlpha = max(m_fMinAmplitude, min(m_fMaxAmplitude, fMax));

              if (m_fMaxAmplitude - m_fMinAmplitude > 0.0f)
              {
                fAlpha = (fAlpha-m_fMinAmplitude)/(m_fMaxAmplitude - m_fMinAmplitude);
              }
              else
              {
                fAlpha = 1.0f;
              }

            }
            else
            {
              fAlpha=1.0f ; 
            }

            bPaint = true;
          }

          uColor=int(255.0f*fAlpha);
          uColor=uColor | (uColor<<8) | (uColor<<16) | (uColor<<24);

          if (fAlpha==1.0f) uColor=0xFFFFFFFF;

          if (fAlpha)
          {
            float x;
            float y;
            x = m_pfPositions[iFrame*2] + m_fSpeedX*(fTime - m_fSetPosTime);
            y = m_pfPositions[iFrame*2+1] + m_fSpeedY*(fTime - m_fSetPosTime);
            float zoom = max(0.0f, m_fZoomStart + m_fZoomSpeed*(fTime - m_fZoomTime));
            ScreenManager::Render(m_piImages[iFrame], x, y, 1, 1, m_Blend, bPaint?uColor:0xFFFFFFFF, zoom);      
          }
        }
      }
    }
    return (1);
  }

  int      Command           (float fTime, const char* pcCommand)
  {
    SM_DemoEffect::Command(fTime, pcCommand);
    char* pcCopy =0;
    char* pcToken;
    int   iReturn=-1;
    

    pcCopy=new char[strlen(pcCommand)+1];
    strcpy(pcCopy, pcCommand);

    pcToken=strtok(pcCopy, " \t");

    if (strcmp(pcToken, "LOAD")==0)
    {
      assert(!"This is now done with FXLOAD!!!!!!");
    }
    else if (strcmp(pcToken, "POSITION")==0)
    {
      int iFrame;

      if (m_pfPositions)
      {
        pcToken=strtok(0, " \t");
        iFrame=SafeAtoi(pcToken);

        if (iFrame<0 || iFrame>=m_iImages)
        {
          SM_Main::OutputError("Estas pasando un frame fuera de rango: %s", pcCommand);
        }

        pcToken=strtok(0, " \t");
        m_pfPositions[iFrame*2]=(float) SafeAtof(pcToken);

        pcToken=strtok(0, " \t");
        m_pfPositions[iFrame*2+1]=(float)  SafeAtof(pcToken);
      }

      // update time
      m_fSetPosTime = fTime;
    }
    else if (strcmp(pcToken, "POSITIONALL")==0)
    {
      if (m_pfPositions)
      {
        pcToken=strtok(0, " \t");
        float fPosX=(float) SafeAtof(pcToken);

        pcToken=strtok(0, " \t");
        float fPosY=(float) SafeAtof(pcToken);

        int i;
        for (i=0 ; i<m_iImages ; i++)
        {
          m_pfPositions[i*2]  =fPosX;
          m_pfPositions[i*2+1]=fPosY;
        }
      }

      // update time
      m_fSetPosTime = fTime;
    }
    else if (strcmp(pcToken, "BLEND")==0)
    {
      pcToken=strtok(0, " \t");
      if (strcmp(pcToken,"ADDITIVE")==0)
      {
        m_Blend=ScreenManager::E_ADDITIVE;
      }
      else if (strcmp(pcToken, "SUBSTRACTIVE") == 0)
      {
      	m_Blend=ScreenManager::E_SUBSTRACTIVE;
      }
      else if (strcmp(pcToken, "INVERT") == 0)
      {
      	m_Blend=ScreenManager::E_INVERT;
      }
      else if (strcmp(pcToken, "MULTIPLY") == 0)
      {
      	m_Blend=ScreenManager::E_MULTIPLY;
      }
      else
      {
        m_Blend=ScreenManager::E_NORMAL;
      }
    }
    if (strcmp(pcToken, "FADEIN")==0)
    { 
      pcToken=strtok(0, " \t");
      m_fDuration=(float)SafeAtof(pcToken);
      
      m_fFadeStartTime=fTime;

      m_bFadeSoundSync = false;
      m_bFadeOut=true;
      m_bFadeIn=false;
      m_bFadeBeat=false;
    }
    else
    if (strcmp(pcToken, "FADEOUT")==0)
    {         
      pcToken=strtok(0, " \t");
      m_fDuration=(float)SafeAtof(pcToken);

      
      m_fFadeStartTime=fTime;

      m_bFadeSoundSync = false;
      m_bFadeIn=true;
      m_bFadeOut=false;
      m_bFadeBeat=false;
    }
    else if (strcmp(pcToken, "FADESOUNDSYNC")==0)
    {

      pcToken=strtok(0, " \t");
      if (strcmp(pcToken, "BEAT")==0)
      {
        m_bFadeBeat=true;
        m_bFadeSoundSync = false;
        m_bFadeIn=false;
        m_bFadeOut=false;
        pcToken=strtok(0, " \t");        
        m_fDuration=(float)SafeAtof(pcToken);        
      }
      else if (strcmp(pcToken, "RAW")==0)
      {
        pcToken=strtok(0, " \t");
        m_fMinAmplitude=(float)SafeAtof(pcToken);
        m_fMinAmplitude= max(0.0f, min(m_fMinAmplitude, 1.0f));

        pcToken=strtok(0, " \t");      
        m_fMaxAmplitude=(float)SafeAtof(pcToken);
        m_fMaxAmplitude= max(0.0f, min(m_fMaxAmplitude, 1.0f));

        pcToken=strtok(0, " \t");
        m_fMinFrequency=(float)SafeAtof(pcToken);
        m_fMinFrequency= max(0.0f, min(m_fMinFrequency, 1.0f));

        pcToken=strtok(0, " \t");
        m_fMaxFrequency=(float)SafeAtof(pcToken);
        m_fMaxFrequency= max(0.0f, min(m_fMaxFrequency, 1.0f));      

        m_bFadeBeat=false;
        m_bFadeSoundSync = true;
        m_bFadeIn=false;
        m_bFadeOut=false;
      }
      else
      {
        m_bFadeBeat=false;
        m_bFadeSoundSync = false;
        m_bFadeIn=false;
        m_bFadeOut=false;
      }      
    }
    else if (strcmp(pcToken, "VELOCITY")==0)
    {
      // Snap current positions
      if (m_pfPositions)
      {
        int i;
        for (i=0 ; i<m_iImages ; i++)
        {
          m_pfPositions[i*2]  +=m_fSpeedX*(fTime - m_fSetPosTime);
          m_pfPositions[i*2+1]+=m_fSpeedY*(fTime - m_fSetPosTime);
        }
      }

      pcToken=strtok(0, " \t");
      m_fSpeedX=(float) SafeAtof(pcToken);

      pcToken=strtok(0, " \t");
      m_fSpeedY=(float) SafeAtof(pcToken);

      m_fSetPosTime = fTime;
    }
    else if (strcmp(pcToken, "ZOOM") == 0)
    {
      pcToken=strtok(0, " \t");      
      m_fZoomStart = (float) SafeAtof(pcToken);

      pcToken=strtok(0, " \t");      
      m_fZoomSpeed = (float) SafeAtof(pcToken);  

      m_fZoomTime = fTime;
    }
    
    iReturn  = 0;

    
    if (pcCopy) { delete[] pcCopy; pcCopy=0; }
    return iReturn;
  }  

protected:  
  bool                  m_bLoaded;
  ScreenManager::eBlend m_Blend;
  int*                  m_piImages;
  float*                m_pfPositions;
  int                   m_iImages;
  float                 m_fFrameTime;
  float                 m_fStartTime;
  float                 m_fSpeedX;
  float                 m_fSpeedY;
  float                 m_fZoomStart;
  float                 m_fZoomSpeed;
  float                 m_fZoomTime;
  float                 m_fSetPosTime;

  bool                  m_bFadeIn;
  bool                  m_bFadeOut;
  float                 m_fFadeStartTime;
  float                 m_fDuration; 

  float                 m_fMinAmplitude;
  float                 m_fMaxAmplitude;      
  float                 m_fMinFrequency;      
  float                 m_fMaxFrequency;      
  bool                  m_bFadeSoundSync;
  bool                  m_bFadeBeat;
  float                 m_fBeatFadeTime;      
};

DEFINE_EFFECT(StillFX)

StillFX Efecto00("IMAGE_00");
StillFX Efecto01("IMAGE_01");
StillFX Efecto02("IMAGE_02");
StillFX Efecto03("IMAGE_03");
StillFX Efecto04("IMAGE_04");
StillFX Efecto05("IMAGE_05");
StillFX Efecto06("IMAGE_06");
StillFX Efecto07("IMAGE_07");
StillFX Efecto08("IMAGE_08");
StillFX Efecto09("IMAGE_09");
StillFX Efecto10("IMAGE_10");
StillFX Efecto11("IMAGE_11");
StillFX Efecto12("IMAGE_12");
StillFX Efecto13("IMAGE_13");
StillFX Efecto14("IMAGE_14");
StillFX Efecto15("IMAGE_15");
StillFX Efecto16("IMAGE_16");
StillFX Efecto17("IMAGE_17");
StillFX Efecto18("IMAGE_18");
StillFX Efecto19("IMAGE_19");
StillFX Efecto20("IMAGE_20");
StillFX Efecto21("IMAGE_21");
StillFX Efecto22("IMAGE_22");
StillFX Efecto23("IMAGE_23");
StillFX Efecto24("IMAGE_24");
StillFX Efecto25("IMAGE_25");
StillFX Efecto26("IMAGE_26");
StillFX Efecto27("IMAGE_27");
StillFX Efecto28("IMAGE_28");
StillFX Efecto29("IMAGE_29");
StillFX Efecto30("IMAGE_30");
StillFX Efecto31("IMAGE_31");


