// -*-C++-*-
// This file is part of the gmod package
// Copyright (C) 1997 by Andrew J. Robinson

#include <stdlib.h>
#include <qmsgbox.h>

#include "defines.h"
#include "structs.h"
#include "globals.h"
#include "protos.h"

#include "QueueShell.h"
#include "OptShell.h"
#include "Sequencer.h"

struct qInfoArray QueueShell::buttonInfo[8] = 
{
  {"addButton", "Add", 0, 60, 60, 25},
  {"saveButton", "Save", 65, 60, 60, 25},
  {"currentButton", "Current", 130, 60, 60, 25},
  {"playButton", "Play", 195, 60, 60, 25},
  {"removeButton", "Remove", 0, 30, 60, 25},
  {"clearButton", "Clear", 65, 30, 60, 25},
  {"shuffleButton", "Shuffle", 130, 30, 60, 25},
  {"closeButton", "Close", 195, 30, 60, 25}
};

QueueShell::QueueShell(QWidget *w) : QWidget(w, "queueShell")
{
  int i;

  setMinimumSize(265, 75);
  setCaption("Xgmod Queue");

  for (i = 0; i < 8; i++)
    {
      buttons[i] = new QPushButton(this, buttonInfo[i].name);
      buttons[i]->setText(buttonInfo[i].label);
      buttons[i]->setGeometry(buttonInfo[i].x + 5, 270 - buttonInfo[i].y,
			      buttonInfo[i].width, buttonInfo[i].height);
    }
		    
  connect (buttons[0], SIGNAL(clicked()), this, SLOT(addClicked()));
  connect (buttons[1], SIGNAL(clicked()), this, SLOT(saveClicked()));
  connect (buttons[2], SIGNAL(clicked()), this, SLOT(currentClicked()));
  connect (buttons[3], SIGNAL(clicked()), this, SLOT(playClicked()));
  connect (buttons[4], SIGNAL(clicked()), this, SLOT(removeClicked()));
  connect (buttons[5], SIGNAL(clicked()), this, SLOT(clearClicked()));
  connect (buttons[6], SIGNAL(clicked()), this, SLOT(shuffleClicked()));
  connect (buttons[7], SIGNAL(clicked()), this, SLOT(closeClicked()));

  queueList = new QListBox(this, "queueList");
  queueList->setGeometry(5, 5, 255, 200);
  connect(queueList, SIGNAL(selected(int)), this, SLOT(playClicked()));

  loadDialog = new XQFileDialog;
  loadDialog->setCaption("Xgmod - Add");
  connect (loadDialog, SIGNAL(fileSelected(const char *)), this,
	   SLOT(loadFileSelected(const char *)));

  saveDialog = new QFileDialog;
  saveDialog->setCaption("Xgmod - Save");
  connect (saveDialog, SIGNAL(fileSelected(const char *)), this,
	   SLOT(saveFileSelected(const char *)));

  resize (265, 270);
}

void
QueueShell::showQueueShell()
{
  show();
}

void
QueueShell::closeClicked()
{
  close();
}

void
QueueShell::resizeEvent(QResizeEvent *)
{
  int i;

  for (i = 0; i < 8; i++)
    buttons[i]->move((width() - 255) / 2 + buttonInfo[i].x, height() - buttonInfo[i].y);

  queueList->resize(width() - 10, height() - 70);
}

void
QueueShell::addClicked()
{
  loadDialog->show();
}

void
QueueShell::saveClicked()
{
  saveDialog->show();
}

void
QueueShell::addModule (int addPlace, const char *filename)
{
  if (currentMod >= addPlace)
    currentMod++;

  xInfo.nrFileStrings++;

  xInfo.fileStrings =
    (char * *)realloc (xInfo.fileStrings, sizeof (char *) * xInfo.nrFileStrings);

  memmove (xInfo.fileStrings + addPlace + 1,
	   xInfo.fileStrings + addPlace,
	   (xInfo.nrFileStrings - addPlace - 1) * sizeof (char *));

  xInfo.fileStrings[addPlace] = strdup (filename);
  queueList->insertItem(filename, addPlace);
}

void
QueueShell::loadFileSelected (const char *filename)
{
  int addPlace;
  FILE *fp;
  char buffer[BUFSIZ];

  addPlace = queueList->currentItem();

  if (addPlace == -1)
    addPlace = queueList->count() - 1;

  if ((fp = fopen (filename, "r")) == NULL)
    {
      QMessageBox::message("Xgmod Error", "Cannot open file", 0, loadDialog);
      return;
    }

  fgets (buffer, BUFSIZ, fp);

  queueList->setAutoUpdate(FALSE);

  if (!memcmp (buffer, "@(#)GMOD-PLAYLIST", 17))
    while (fgets (buffer, BUFSIZ, fp) != NULL)
      {
	buffer[strlen (buffer) - 1] = '\0';
	addPlace++;
	addModule (addPlace, buffer);
      }
  else
    {
      addPlace++;
      addModule (addPlace, filename);
    }

  fclose (fp);

  queueList->setCurrentItem(addPlace);
  queueList->repaint();
  queueList->setAutoUpdate(TRUE);
}

void
QueueShell::currentClicked()
{
  int highlightMod;

  if (currentMod < 0)
    highlightMod = -currentMod - 1;
  else
    highlightMod = currentMod;

  if (highlightMod < xInfo.nrFileStrings)
    {
      queueList->setCurrentItem(highlightMod);
      queueList->centerCurrentItem();
    }
  else
    queueList->setCurrentItem(-1);
}

void
QueueShell::playClicked()
{
  int oCurrentMod;
  extern Sequencer *seq;
 
  if (queueList->currentItem() != -1)
    {
      oCurrentMod = currentMod;
      currentMod = queueList->currentItem();

      // stop playback and deallocate current module
      if (oCurrentMod >= 0)
	{
	  seq->stopPlayback ();
	  endModule (0);
	}

      // start playback of the new module
      if (!startPlayback (0))
	currentMod = -currentMod - 1;
    }
  else
    QMessageBox::message("Xgmod Error", "No module is selected", 0, this);
}

void
QueueShell::saveFileSelected(const char *filename)
{
  FILE *fp;
  int i;

  if ((fp = fopen (filename, "w")) == NULL)
    QMessageBox::message("Xgmod Error", "Cannot open file", 0, saveDialog);
  else
    {
      fprintf (fp, "@(#)GMOD-PLAYLIST\n");

      for (i = 0; i < xInfo.nrFileStrings; i++)
	fprintf (fp, "%s\n", (xInfo.fileStrings)[i]);

      fclose (fp);
    }
}

void
QueueShell::removeModule(int current)
{
  int highlight = queueList->currentItem();

  queueList->removeItem(current);

  if (highlight != -1)
    {
      if (highlight >= queueList->count())
	highlight--;
      
      queueList->setCurrentItem(highlight);
    }
  
  free (xInfo.fileStrings[current]);
  xInfo.nrFileStrings--;
  
  if (xInfo.nrFileStrings != current)
    memmove (xInfo.fileStrings + current,
	     xInfo.fileStrings + current + 1,
	     (xInfo.nrFileStrings - current) * sizeof (char *));
  
  xInfo.fileStrings =
    (char * *)realloc (xInfo.fileStrings, sizeof (char *) *
		       xInfo.nrFileStrings);
}
  
void
QueueShell::removeClicked()
{
  int current;
  unsigned char lstopFlag = 0;
  //extern TopShell *topShell;
  extern OptShell *optShell;
  extern Sequencer *seq;

  if ((current = queueList->currentItem()) != -1)
    {
      removeModule(current);

      if (current == currentMod)
	{
	  lstopFlag = STOP_GOTO;

	  // stop playback and deallocate current module
	  if (currentMod >= 0)
	    {
	      seq->stopPlayback ();
	      endModule (0);
	    }

	  if (currentMod >= xInfo.nrFileStrings)
	    currentMod = -1;

	  if (xInfo.nrFileStrings > 0)
	    {
	      if (optShell->randomChecked() == TRUE)
		currentMod = rand () % xInfo.nrFileStrings;
	    }
	}
      else if (current < currentMod)
	currentMod--;
      else if (current == (-currentMod - 1))
	emit currentDeleted();

      if (xInfo.nrFileStrings == 0)
	{
	  currentMod = -1;
	  emit currentDeleted();
	}

      //topShell->checkButtons ();

      // start playback of new module if current module was deleted
      if ((lstopFlag == STOP_GOTO) && (currentMod >= 0))
	if (!startPlayback (0))
	  currentMod = -currentMod - 1;
    }
  else
    QMessageBox::message("Xgmod Error", "No module is selected", 0, this);
}

void
QueueShell::clearClicked()
{
  int i, oCurrentMod;
  extern Sequencer *seq;

  queueList->clear();

  for (i = 0; i < xInfo.nrFileStrings; i++)
    free (xInfo.fileStrings[i]);
  free (xInfo.fileStrings);
  xInfo.nrFileStrings = 0;
  xInfo.fileStrings = NULL;
  oCurrentMod = currentMod;
  currentMod = -1;
  
  // stop playback and deallocate current module
  if (oCurrentMod >= 0)
    {
      seq->stopPlayback ();
      endModule (0);
    }

  //topShell->checkButtons ();
  emit currentDeleted();
}

void
QueueShell::shuffleClicked()
{
  int i, swapNum;
  char *tmpString;
  int current = queueList->currentItem();

  for (i = 0; i < xInfo.nrFileStrings; i++)
    {
      swapNum = rand () % xInfo.nrFileStrings;

      tmpString = xInfo.fileStrings[i];
      xInfo.fileStrings[i] = xInfo.fileStrings[swapNum];
      xInfo.fileStrings[swapNum] = tmpString;

      if (currentMod == i)
	currentMod = swapNum;
      else if (swapNum == currentMod)
	currentMod = i;
    }

  queueList->setAutoUpdate(FALSE);
  queueList->clear();

  for (i = 0; i < xInfo.nrFileStrings; i++)
    queueList->insertItem(xInfo.fileStrings[i]);

  if (current != -1)
    queueList->setCurrentItem(current);
  
  queueList->repaint();
  queueList->setAutoUpdate(TRUE);
}

#ifndef DEPEND
#include "QueueShell.moc"  
#endif
