#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include <stdlib.h>
#include <setjmp.h>
#include "version.h"
#include "cs.h"
extern "C" long    kcnt;
extern "C" void csoundMessage(void *, const char *, ...);
extern "C" void csoundMessageV(void *, const char *, va_list);
extern "C" void csoundMessage0(const char *, ...);
extern "C" int csoundMain(void*, int, char**);
extern "C" void csoundReset(void*);
extern "C" int csoundPerformKsmps(void*);
extern "C" int runincomponents;
extern "C" int cleanup(void);
extern "C" OPARMS  O_;
extern "C" OPARMS O;
extern "C" GLOBALS cglob_;

extern "C" void remove_tmpfiles(void);      /* IV - Oct 31 2002 */
#ifdef MACOSX
#undef index
#endif
#include <FL/Fl.H>
#include <FL/Fl_Window.H>
#include <FL/Fl_Box.H>
#include <FL/Fl_File_Chooser.H>
#include <FL/Fl_File_Icon.H>
void do_render(void);
void orch_cb(Fl_Widget*, void*);
void score_cb(Fl_Widget*, void*); 
#include <FL/Fl_Value_Slider.H>
Fl_File_Input *Orch=(Fl_File_Input *)0;
Fl_File_Input *Score=(Fl_File_Input *)0;
FILE* ERROUT;

static void callback(Fl_Widget* o, void*) 
{
    //    printf("%g     \r", ((Fl_Valuator*)o)->value());
    //fflush(stdout);
}

Fl_File_Chooser		*fc;
static void orc_callback(void)
{
    int	i;			// Looping var
    int	count;			// Number of files selected
    char relative[1024];	// Relative filename

    //    fc->show();
    fc->filter("Unified Source File (*.csd)\tOrc Source Files (*.orc)");
    fc->show();
    
    while (fc->visible())
      Fl::wait();
    if (fc->count() > 0) {
      fprintf(ERROUT, "%s\n", fc->value(1));
      Orch->value(fc->value(1));
    }
    
}
static void sco_callback(void)
{
    int	i;			// Looping var
    char	relative[1024];		// Relative filename

    fc->filter("Score Source Files (*.sco)");
    fc->show();

    while (fc->visible())
      Fl::wait();
    if (fc->count() > 0) {
      fprintf(ERROUT, "%s\n", fc->value(1));
      Score->value(fc->value(1));
    }
}

void
fc_callback(Fl_File_Chooser *fc,	// I - File chooser
            void            *data)	// I - Data
{
    //    printf("fc_callback(fc = %p, data = %p)\n type=%d\n", fc, data, fc->type());
}

// generated by Fast Light User Interface Designer (fluid) version 1.0100

#include "csgui.h"

Fl_Text_Display *Output=(Fl_Text_Display *)0;
Fl_Text_Display *Errout=(Fl_Text_Display *)0;

Fl_Button *Render=(Fl_Button *)0;

static void cb_Render(Fl_Button*, void*) {
    do_render();
}

int fltk_abort = 0;

static void cb_Quit(Fl_Button*, void*) {
    exit(0);
}

static void cb_Abort(Fl_Button*, void*)
{
    fltk_abort = 1;
}
#include <FL/Fl_Bitmap.H>
static unsigned char idata_allfiles[] =
"\374?\4 \4 \4 \204!\244%\304#\364/\364/\304#\244%\204!\4 \4 \4 \374?";
static Fl_Bitmap image_allfiles(idata_allfiles, 16, 16);

Fl_File_Input *SFName=(Fl_File_Input *)0;

Fl_Choice *OType=(Fl_Choice *)0;

Fl_Menu_Item menu_OType[] = {
  {"WAV", 0,  0, 0, 0, 0, 0, 14, 56},
  {"AIFF", 0,  0, 0, 4, 0, 0, 14, 56},
  {"IRCAM", 0,  0, 0, 4, 0, 0, 14, 56},
  {"Raw", 0,  0, 0, 4, 0, 0, 14, 56},
  {0}
};

Fl_Choice *SSize=(Fl_Choice *)0;

Fl_Menu_Item menu_Size[] = {
  {"short", 0,  0, 0, 0, 0, 0, 14, 56},
  {"floats", 0,  0, 0, 4, 0, 0, 14, 56},
  {"long", 0,  0, 0, 4, 0, 0, 14, 56},
  {"24bit", 0,  0, 0, 4, 0, 0, 14, 56},
  {"char", 0,  0, 0, 4, 0, 0, 14, 56},
  {0}
};

Fl_Value_Slider *Messages=(Fl_Value_Slider *)0;

Fl_Input *Args=(Fl_Input *)0;

Fl_Window* make_window()
{
    Fl_File_Icon	*icon;	// New file icon
    Fl_File_Icon::load_system_icons();
    Fl_Window* w;
    w = new Fl_Window(606, 660, "Csound");
    w->align(FL_ALIGN_TOP_LEFT);
    {
      Fl_Text_Display* o =
        Output = new Fl_Text_Display(15, 300, 575, 350, "Output");
      o->tooltip("Output from csound");
      o->selection_color(7);
      o->labelcolor(216);
      o->textfont(FL_COURIER/*FL_SCREEN*/);
    }
    {
      Fl_Text_Display* o =
        Errout = new Fl_Text_Display(15, 195, 575, 75, "Error Messages");
      o->tooltip("Messages for StdErr");
      o->selection_color(1);
      o->labelcolor(1);
      o->textcolor(1);
      o->textfont(FL_COURIER/*FL_SCREEN*/);
    }
    {
      Fl_Button* o = Render = new Fl_Button(530, 20, 55, 30, "Render");
      o->tooltip("Create sound output");
      o->box(FL_ROUND_UP_BOX);
      o->callback((Fl_Callback*)cb_Render);
    }
    {
      Fl_Button* o = new Fl_Button(530, 55, 55, 30, "Quit");
      o->tooltip("Quit from csound");
      o->box(FL_ROUND_UP_BOX);
      o->callback((Fl_Callback*)cb_Quit);
    }
    {
      Fl_Button* o = new Fl_Button(530, 90, 55, 30, "Abort");
      o->tooltip("ABort current rendering");
      o->box(FL_ROUND_UP_BOX);
      o->callback((Fl_Callback*)cb_Abort);
    }
    {
      Fl_File_Input* o = Orch = new Fl_File_Input(45, 15, 170, 35, "Orchestra");
      o->tooltip("Orchestra File");
      o->align(FL_ALIGN_TOP_LEFT);
      o->value("");
    }
    {
      Fl_Button* o = new Fl_Button(215, 15, 35, 35);
      o->labelcolor(FL_DARK_YELLOW);
      o->callback((Fl_Callback *)orc_callback);
      //      o->image(image_allfiles);
      icon   = Fl_File_Icon::find(".", Fl_File_Icon::DIRECTORY);
      icon->label(o);
    }
    {
      Fl_File_Input* o = Score = new Fl_File_Input(280, 15, 185, 35, "Score");
      o->tooltip("Score File");
      o->align(FL_ALIGN_TOP_LEFT);
      o->value("");
    }
    {
      Fl_Button* o = new Fl_Button(465, 15, 35, 35, "button");
      o->labelcolor(FL_DARK_YELLOW);
      o->callback((Fl_Callback *)sco_callback);
      icon   = Fl_File_Icon::find(".", Fl_File_Icon::DIRECTORY);
      icon->label(o);
    }
    {
      Fl_File_Input* o = SFName = new Fl_File_Input(75, 60, 425, 35, "Soundfile");
      o->tooltip("Name of output file");
    }
    {
      Fl_Choice* o = OType = new Fl_Choice(95, 100, 80, 25, "Output Type");
      o->tooltip("Select type of output file");
      o->down_box(FL_BORDER_BOX);
      o->menu(menu_OType);
    }
    {
      Fl_Choice* o = SSize = new Fl_Choice(205, 100, 80, 25, "Size");
      o->tooltip("Select size of sample");
      o->down_box(FL_BORDER_BOX);
      o->menu(menu_Size);
    }
    {
      Fl_Value_Slider* o =
        Messages = new Fl_Value_Slider(300, 100, 75, 20, "Messages");
      o->tooltip("Verbosity of Messages");
      o->box(FL_FLAT_BOX);
      o->maximum(16);
      o->step(1);
      o->value(7);
      o->callback((Fl_Callback*)callback);
      Messages->type(FL_HOR_NICE_SLIDER);
      Messages->align(FL_ALIGN_RIGHT);
    }
    Args = new Fl_Input(105, 150, 485, 25, "Other Options");
    Args->tooltip("Other command line options");
    Args->value("");
    w->end();
    return w;
}

static Fl_Window *window;
static Fl_Text_Buffer     *textbuf = 0;
static Fl_Text_Buffer     *errbuf = 0;
static int do_calc = 0;
static char *largv[200];
static int largc = 0;

extern "C" int run_status;
int main(int argc, char **argv) 
{
    do_calc = 0;                // No calculation yet
    O = O_;
    cglob = cglob_;
    ERROUT = fopen("/tmp/errout", "w");
    setvbuf(ERROUT, (char*)NULL, _IONBF, 0);
    atexit(remove_tmpfiles);            /* IV - Oct 31 2002 */
    textbuf = new Fl_Text_Buffer;
    errbuf = new Fl_Text_Buffer;
    fc = new Fl_File_Chooser(".", "*",
                             Fl_File_Chooser::SINGLE, "Chooser");
    fc->callback(fc_callback);
    window = make_window();
    window->end();
    window->show(argc, argv);
    Output->buffer(textbuf);
    Errout->buffer(errbuf);
#ifndef MACOSX
    if (argc<2) {
#endif
    again:
      while (1) {
        fltk_abort = 0;
        do_calc = 0;
        while (!do_calc) Fl::wait();
        runincomponents = 1;
        run_status = csoundMain(NULL, largc, largv);
        if (strcmp(O.outfilename,"devaudio") == 0 ||
            strcmp(O.outfilename,"dac") == 0) {
          /* now just loop filling buffer until done */
          while (run_status == 0 && fltk_abort == 0) {
            Fl::wait(1.0);
          }
        }
        else {
          while(!csoundPerformKsmps(NULL));
        }
        csoundMessage(NULL, "***Resetting\n\n");
        csoundReset(NULL);
        remove_tmpfiles();
      }
#ifndef MACOSX
    }
    else {
      runincomponents = 1;
      run_status = csoundMain(NULL, argc, argv);
      if (strcmp(O.outfilename,"devaudio") == 0 ||
          strcmp(O.outfilename,"dac") == 0) {
        /* now just loop filling buffer until done */
        while (run_status == 0) {
          Fl::wait(1.0);
        }
      }
      else {
        while(!csoundPerformKsmps(NULL));
      }
      csoundMessage(NULL, "***Resetting\n\n");
      csoundReset(NULL);
      remove_tmpfiles();
      goto again;
    }
#endif
}

void csoundMessage0(const char *format, ...)
{
    char buffer[1024];
    va_list args;
    va_start(args, format);
    vsnprintf(buffer, 1024, format, args);
    va_end(args);
    Output->textcolor(FL_BLACK);
    textbuf->append(buffer);
    Output->insert_position(textbuf->length());
    Output->show_insert_position();
    Fl::wait(0.0);
}

void csoundMessage(void *csound, const char *format, ...)
{
    char buffer[1024];
    va_list args;
    va_start(args, format);
    vsnprintf(buffer, 1024, format, args);
    va_end(args);
    textbuf->append(buffer);
    Output->insert_position(textbuf->length());
    Output->show_insert_position();
    Fl::wait(0.0);
}

void csoundMessageV(void *csound, const char *format, va_list args)
{
    char buffer[1024];
    int l = errbuf->length();
    vsnprintf(buffer, 1024, format, args);
    va_end(args);
    errbuf->append(buffer);
    Errout->insert_position(l);
    Errout->show_insert_position();
    Fl::wait(0.0);
}

void do_render(void)
{
    char call[256];
    char *otype[] = {"-W", "-A", "-J", ""};
    char *size[] = {"-s", "-f", "-l", "-3", "-c"};
    csoundMessage(NULL, "### csound %s %s -m%d %s %s %s",
                  otype[OType->value()], size[SSize->value()],
                  (int)Messages->value(), Args->value(),
                  Orch->value(), Score->value());
    if (strcmp(SFName->value(),""))
      csoundMessage(NULL, " -o %s", SFName->value());
    csoundMessage(NULL, "\n");
    largv[0] = "csound";
    largv[1] = otype[OType->value()];
    largv[2] = size[SSize->value()];
    sprintf(call, "-m%d", (int)Messages->value());
    largv[3] = (char*)malloc(strlen(call)+1);
    strcpy(largv[3], call);
    largc = 4;
    if (strcmp(Orch->value(), ""))
      largv[largc++] = (char*)Orch->value();
    if (strcmp(Score->value(), ""))
      largv[largc++] = (char*)Score->value();
    if (strcmp(SFName->value(),"")) {
      largv[largc++] = "-o";
      largv[largc++] = (char*)SFName->value();
    }
    if (Args->value()[0]!='\0') {
      char *x;
      static char b[1024];
      strncpy(b, Args->value(), 1024);
      largv[largc++] = strtok(b, " \t\n");
      while (x=strtok(NULL, " \t\n"))
        largv[largc++] = x;
    }
    largv[largc] = NULL;
//     {
//       int i;
//       fprintf(ERROUT, "largc=%d\n", largc);
//       for (i=0; i<largc; i++) fprintf(ERROUT, "%d: \"%s\"\n", i, largv[i]);
//     }
    do_calc = 1;
}

