#include "allegro.h"

#ifdef _WIN32
#include "winalleg.h"

#include <winsock.h>
#else
#define SOCKET_ERROR -1
#include <sys/time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <netdb.h>
#endif

#include <fmod.h>

#include "math.h"

#include "defs.h"
#include "console.h"
#include "maths.h"
#include "sound.h"

extern int fpsLimit;

soundEngine Sound;

int soundEngine::Start()
{
   int success = 1;

   Console.WriteF("Initializing the FMOD sound system...");
#ifdef _WIN32
//   FSOUND_SetOutput(FSOUND_OUTPUT_A3D);
   FSOUND_SetOutput(FSOUND_OUTPUT_DSOUND);
//   FSOUND_SetOutput(FSOUND_OUTPUT_WINMM);
#elif defined(__linux__)
   FSOUND_SetOutput(FSOUND_OUTPUT_OSS);
//   FSOUND_SetOutput(FSOUND_OUTPUT_ALSA);
//   FSOUND_SetOutput(FSOUND_OUTPUT_ESD);
#endif
   music = NULL;
   success = FSOUND_Init(44000, 32, 0);
   FSOUND_3D_SetDistanceFactor(100.0);
   FSOUND_3D_SetRolloffFactor(0.5);
   return success;
}

void soundEngine::startMusic(char *name)
{
   int channel = -1;
   
   Console.WriteF("Starting music playback (%s)...", name);
   music = FSOUND_Stream_Open(name, FSOUND_NORMAL | FSOUND_LOOP_NORMAL | FSOUND_MPEGACCURATE | FSOUND_2D, 0, 0);
   if (music)
   {
      channel = FSOUND_Stream_PlayEx(FSOUND_FREE, music, NULL, TRUE);
      if (channel != -1)
      {
         FSOUND_SetReserved(channel, TRUE);
         FSOUND_SetPaused(channel, FALSE);
      }
   }
   else
   {
      Console.WriteF("Error loading music file");
   }
}

void soundEngine::preFrame()
{
   float pos[3];
   float vel[3];
   
   pos[0] = (float)worms[viewport[0].player].coords.x;///100.0;
   pos[1] = -(float)worms[viewport[0].player].coords.y;///100.0;
   pos[2] = -3.0;

   vel[0] = ((float)worms[viewport[0].player].vel.x*40)/1000.0;
   vel[1] = -((float)worms[viewport[0].player].vel.y*40)/1000.0;
   vel[2] = 0;

   if (numViewports == 1)
      FSOUND_3D_Listener_SetAttributes(&pos[0], &vel[0], 0.0, 0.0, 1.0, 0.0, 1.0, 0.0);
}

void soundEngine::postFrame()
{
   if (numViewports == 1)
      FSOUND_Update();
}

void soundEngine::Free()
{
   if (music)
   {
      FSOUND_Stream_Close(music);
   }
   Console.WriteF("FMOD sound system down...");
   FSOUND_Close();
}

int soundEngine::initSounds()
{
   int sndCount, i;
   sampleItem *tempItem;
   sndCount = get_config_int("Weapons", "SoundCount", 0);

   for (i=0; i<sndCount; i++)
   {
      sprintf(buf, "Sound.%d", i);
      sprintf(buf, "sound/%s", get_config_string(buf, "File", "default.wav"));
      tempItem = (sampleItem *)malloc(sizeof(sampleItem));
      if (!tempItem)
      {
         Console.WriteF("Sound not allocated: %d - %s", i, buf);
      }
      else
      {
         tempItem->next = sampleList;
         if (sampleList)
            sampleList->prev = tempItem;
         tempItem->prev = NULL;
         tempItem->num = i;
         tempItem->soundData = FSOUND_Sample_Load(FSOUND_FREE, buf, FSOUND_FORCEMONO, 0, 0);
         sampleList = tempItem;
         if (tempItem->soundData)
         {
            sprintf(buf, "Sound.%d", i);
            tempItem->priority = get_config_int(buf, "Priority", 128);
            FSOUND_Sample_SetDefaults(tempItem->soundData, -1, -1, -1, tempItem->priority);
            FSOUND_Sample_SetMinMaxDistance(tempItem->soundData, 32, 600);
         }
         else
         {
            Console.WriteF("Sound not loaded: %d - %s", i, buf);
         }
      }
   }
   Console.WriteF("Loaded %d sounds...", sndCount);
   return 0;
}

void soundEngine::freeSounds()
{
}

void soundEngine::playSound(int i, int x, int y)
{
   int channel;
   float pos[3];
   float vel[3];

   sampleItem *tempItem;
   tempItem = sampleList;
   while ((tempItem) && (tempItem->num != i)) tempItem = tempItem->next;

   pos[0] = (float)x;///100.0;
   pos[1] = -(float)y;///100.0;
   pos[2] = 0;

   vel[0] = 0;
   vel[1] = 0;
   vel[2] = 0;

   channel = -1;

   if (tempItem)
   {
      channel = FSOUND_PlaySoundEx(FSOUND_FREE, tempItem->soundData, NULL, TRUE);
      if (channel != -1)
      {
         FSOUND_SetPriority(channel, tempItem->priority);
         if (numViewports == 1)
            FSOUND_3D_SetAttributes(channel, &pos[0], &vel[0]);
         FSOUND_SetPaused(channel, FALSE);
      }
   }
   else if (i != -1)
   {
      Console.WriteCF("Error: trying to play a non-existant sample #%d", i);
   }
}

int soundEngine::loopSound(int i, int x, int y, long velx, long vely)
{
   int channel;
   float pos[3];
   float vel[3];

   sampleItem *tempItem;
   tempItem = sampleList;
   while ((tempItem) && (tempItem->num != i)) tempItem = tempItem->next;

   pos[0] = (float)x;///100.0;
   pos[1] = -(float)y;///100.0;
   pos[2] = 0;

   vel[0] = ((float)velx*40)/1000.0;
   vel[1] = -((float)vely*40)/1000.0;
   vel[2] = 0;

   channel = -1;

   if (tempItem)
   {
      channel = FSOUND_PlaySoundEx(FSOUND_FREE, tempItem->soundData, NULL, TRUE);
      if (channel != -1)
      {
         FSOUND_SetPriority(channel, tempItem->priority);
         FSOUND_SetLoopMode(channel, FSOUND_LOOP_NORMAL);
         if (numViewports == 1)
            FSOUND_3D_SetAttributes(channel, &pos[0], &vel[0]);
         FSOUND_SetPaused(channel, FALSE);
      }
   }
   return channel;
}

void soundEngine::updateSound(int i, int x, int y, long velx, long vely)
{
   float pos[3];
   float vel[3];

   pos[0] = (float)x;///100.0;
   pos[1] = -(float)y;///100.0;
   pos[2] = 0;

   vel[0] = ((float)velx*40)/1000.0;
   vel[1] = -((float)vely*40)/1000.0;
   vel[2] = 0;

   if (i != -1)
   {
      if (numViewports == 1)
         FSOUND_3D_SetAttributes(i, &pos[0], &vel[0]);
   }
}

void soundEngine::stopSound(int i)
{
   if (i != -1)
      FSOUND_StopSound(i);
}

