#ifdef HAVE_CONFIG_H
#  include <config.h>
#endif

#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>

#include <sstream>
#include <stdlib.h>
#include <gnome.h>
#include "GUIDocument.h"
#include "BaseException.h"

using namespace std;

namespace FD {

class CodeGenState {
   GtkWidget* dialog;
   GUIDocument *doc;
   GtkWidget *fileentry1;
   GtkWidget *combo_entry1;
   GtkWidget *combo_entry2;
   GtkWidget *checkbutton1;
   GtkWidget *checkbutton2;
   GtkWidget *checkbutton3;
public:
   CodeGenState(GUIDocument *_doc);
   ~CodeGenState() {gtk_widget_destroy(dialog);}
   void ok();
   void cancel() {}
};

void CodeGenState::ok()
{
   try {
      const char *dirname=gnome_file_entry_get_full_path(GNOME_FILE_ENTRY(fileentry1),FALSE);
      if (!dirname || !strlen(dirname))
	 dirname = ".";

      //Should create directory??

      const char *filename=(char*)gtk_entry_get_text(GTK_ENTRY(combo_entry2));
      if (!filename || !strlen(filename))
	 filename = "build_doc.cc";

      const char *funcname = (char*)gtk_entry_get_text(GTK_ENTRY(combo_entry1));
      if (!funcname || !strlen(funcname))
	 funcname = "buildFunct";
 
      bool generateMain=false, copyDepend=false, createMakefile=false;
      bool compile = false;
      if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(checkbutton1)))
      {
	 generateMain=true;
      }
      if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(checkbutton2)))
      {
	 copyDepend=true;
      }
      if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(checkbutton3)))
      {
	 createMakefile=true;
      }
      
      string fullname = string(dirname) + "/" + filename;
      //cerr << "fullname = " << fullname << endl;
      doc->less_print("Warning: automatic code generation is still experimental");
      ofstream out(fullname.c_str());
      set<string> nodeList = doc->genCode(out, funcname, copyDepend);

      doc->less_print(string("C++ code generated in '") + filename 
		      + "', build function name is '" + funcname + "'");

      if (generateMain)
      {
	 out << "\n\n";
	 if (!copyDepend)
	 {
	    out << "#include <path.h>\n\n";
	    out << "#include <iextensions.h>\n\n";
	 } else {
	    out << "#include \"iextensions.h\"\n\n";
	 }
	 out << "int main(int argc, char **argv)\n";
	 out << "{\n\n";
	 out << "   try {\n";
	 out << "      IExtensions::detect();\n";
	 if (!copyDepend)
	    out << "      scanDL();\n";
	 out << "      ParameterSet param;\n";
	 out << "      for (int arg = 1; arg<argc; arg++)\n";
	 out << "      {\n";
	 out << "         char arg_name[100];\n";
	 out << "         sprintf (arg_name, \"ARG%d\", arg);\n";
	 out << "         param.add(arg_name, ObjectRef (new String (argv[arg])));\n";
	 out << "      }\n";
	 out << "      Network *net = " << funcname << "(\"MAIN\", param);\n";
	 out << "      net->verifyConnect();\n";
	 out << "      net->initialize();\n";
	 out << "      net->getOutput(0,0);\n";
	 out << "\n";
	 

	 out << "   }\n";
	 out << "   catch (BaseException *e)\n";
	 out << "   {\n";
	 out << "      e->print();\n";
	 out << "      return 1;\n";
	 out << "   }\n";
	 out << "   catch (...) {\n";
	 out << "      cerr<<\"Unhandled exception in \"<<argv[0]<<endl;\n";
	 out << "      cerr<<\"Exiting\"<<endl;\n";
	 out << "      return 1;\n";
	 out << "   }\n";
	 out << "   return 0;\n";
	 out << "}\n";

      }

      if (copyDepend)
      {
	 set<string> fileList;
	 for (set<string>::iterator it=nodeList.begin();it!=nodeList.end();it++)
	 {
	    NodeInfo *info = UINodeRepository::Find(*it);
	    if (info)
	       fileList.insert(fileList.begin(), info->sourceFile);
	    //fileList.insert(fileList.begin(), UIDocument::externalDocInfo[*it]->sourceFile);
	 }
	 UINodeRepository::ProcessDependencies(fileList);

	 set<string>::iterator file = fileList.begin();
	 while (file != fileList.end())
	 {
	    string fullPath = UIDocument::findExternal(*file, "FLOWDESIGNER_SOURCE", false);
	    if (fullPath == "")
	    {
	       cerr << "cannot find " << *file << endl;
	       file++;
	       continue;
	    }
	    
	    /*Copy the source files to the right directory, adding a license reminder*/
	    string outName = string(dirname) + "/" + *file;
	    FILE *fin = fopen (fullPath.c_str(), "r");
	    if (!fin)
	    {
	       cerr << "cannot open " << fullPath << endl;
	       file++;
	       continue;
	    }
	    FILE *fout = fopen (outName.c_str(), "w");
	    if (!fout)
	    {
	       fclose(fin);
	       cerr << "cannot create " << outName << endl;
	       file++;
	       continue;		  
	    }
	    fprintf (fout, "//This file is a copy used for static linking of Overflow applications. If it is\n");
	    fprintf (fout, "//part of the Overflow code base, then it is released under the LGPL license.\n");
	    fprintf (fout, "//For more information, see the COPYING file in the Overflow source directory.\n\n");
	    char buff[1024];
	    int bytesRead;
	    do {
	       bytesRead = fread(buff, 1, 1024, fin);
	       if (bytesRead)
		  fwrite(buff, 1, bytesRead, fout);
	    } while (bytesRead == 1024);
	    fclose(fin);
	    fclose(fout);
	    

	    //string cmd = string("\\cp -f ") + fullPath + " " + dirname;
	    //system(cmd.c_str());
	    //cerr << cmd << endl;
	    file++;
	 }
      }

      if (createMakefile)
      {
	 cerr << "Makefile generation not implemented yet" << endl;
      }
      /*if (compile)
      {
	 out.flush();
	 string source_name = string(filename) + ".cc";
	 string cmd = string("g++ -O3 -o ") + filename + " " + source_name + " `flowdesigner-config config libflow --cflags --libs` `gnome-config xml --cflags --libs` -lrfftw -lfftw &";
	 cerr << cmd << endl;
	 system(cmd.c_str());
	 }*/

   } catch (BaseException *e)
   {
      ostringstream str;
      e->print(str);
      doc->less_print(str.str());
   }
}

void GUIDocument_codegen(GUIDocument *doc)
{
   new CodeGenState(doc);
}



static void codegen_ok(GtkButton *button, CodeGenState *gen)
{
   gen->ok();
   delete gen;
}

static void codegen_cancel(GtkButton *button, CodeGenState *gen)
{
   gen->cancel();
   delete gen;
}

CodeGenState::CodeGenState(GUIDocument *_doc)
   : doc(_doc)
{
   GtkWidget *window1;
   GtkWidget *vbox1;
   GtkWidget *label1;
   GtkWidget *hseparator1;
   GtkWidget *table1;
   GtkWidget *entry1;
   GtkWidget *entry2;
   GtkWidget *combo_entry3;
   GtkWidget *label2;
   GtkWidget *label3;
   GtkWidget *label4;
   GtkWidget *vbox2;
   GSList *vbox2_group = NULL;
   GtkWidget *hseparator2;
   GtkWidget *hbuttonbox1;
   GtkWidget *button1;
   GtkWidget *button2;


   window1 = gtk_window_new (GTK_WINDOW_TOPLEVEL);
   gtk_object_set_data (GTK_OBJECT (window1), "window1", window1);
   gtk_window_set_title (GTK_WINDOW (window1), _("Code generation"));

   vbox1 = gtk_vbox_new (FALSE, 0);
   gtk_widget_ref (vbox1);
   gtk_object_set_data_full (GTK_OBJECT (window1), "vbox1", vbox1,
			     (GtkDestroyNotify) gtk_widget_unref);
   gtk_widget_show (vbox1);
   gtk_container_add (GTK_CONTAINER (window1), vbox1);

   label1 = gtk_label_new (_("Code generator"));
   gtk_widget_ref (label1);
   gtk_object_set_data_full (GTK_OBJECT (window1), "label1", label1,
			     (GtkDestroyNotify) gtk_widget_unref);
   gtk_widget_show (label1);
   gtk_box_pack_start (GTK_BOX (vbox1), label1, FALSE, FALSE, 0);

   hseparator1 = gtk_hseparator_new ();
   gtk_widget_ref (hseparator1);
   gtk_object_set_data_full (GTK_OBJECT (window1), "hseparator1", hseparator1,
			     (GtkDestroyNotify) gtk_widget_unref);
   gtk_widget_show (hseparator1);
   gtk_box_pack_start (GTK_BOX (vbox1), hseparator1, TRUE, TRUE, 0);

   table1 = gtk_table_new (3, 2, FALSE);
   gtk_widget_ref (table1);
   gtk_object_set_data_full (GTK_OBJECT (window1), "table1", table1,
			     (GtkDestroyNotify) gtk_widget_unref);
   gtk_widget_show (table1);
   gtk_box_pack_start (GTK_BOX (vbox1), table1, TRUE, TRUE, 0);

   label2 = gtk_label_new (_("Build function name"));
   gtk_widget_ref (label2);
   gtk_object_set_data_full (GTK_OBJECT (window1), "label2", label2,
			     (GtkDestroyNotify) gtk_widget_unref);
   gtk_widget_show (label2);
   gtk_table_attach (GTK_TABLE (table1), label2, 0, 1, 0, 1,
		     (GtkAttachOptions) (0),
		     (GtkAttachOptions) (0), 0, 0);

   label3 = gtk_label_new (_("Output file name"));
   gtk_widget_ref (label3);
   gtk_object_set_data_full (GTK_OBJECT (window1), "label3", label3,
			     (GtkDestroyNotify) gtk_widget_unref);
   gtk_widget_show (label3);
   gtk_table_attach (GTK_TABLE (table1), label3, 0, 1, 1, 2,
		     (GtkAttachOptions) (0),
		     (GtkAttachOptions) (0), 0, 0);

   label4 = gtk_label_new (_("Directory"));
   gtk_widget_ref (label4);
   gtk_object_set_data_full (GTK_OBJECT (window1), "label4", label4,
			     (GtkDestroyNotify) gtk_widget_unref);
   gtk_widget_show (label4);
   gtk_table_attach (GTK_TABLE (table1), label4, 0, 1, 2, 3,
		     (GtkAttachOptions) (0),
		     (GtkAttachOptions) (0), 0, 0);

   entry1 = gnome_entry_new (NULL);
   gtk_widget_ref (entry1);
   gtk_object_set_data_full (GTK_OBJECT (window1), "entry1", entry1,
			     (GtkDestroyNotify) gtk_widget_unref);
   gtk_widget_show (entry1);
   gtk_table_attach (GTK_TABLE (table1), entry1, 1, 2, 0, 1,
		     (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
		     (GtkAttachOptions) (0), 0, 0);

   combo_entry1 = gnome_entry_gtk_entry (GNOME_ENTRY (entry1));
   gtk_widget_ref (combo_entry1);
   gtk_object_set_data_full (GTK_OBJECT (window1), "combo_entry1", combo_entry1,
			     (GtkDestroyNotify) gtk_widget_unref);
   gtk_widget_show (combo_entry1);
   gtk_entry_set_text (GTK_ENTRY (combo_entry1), _("buildFunct"));

   entry2 = gnome_entry_new (NULL);
   gtk_widget_ref (entry2);
   gtk_object_set_data_full (GTK_OBJECT (window1), "entry2", entry2,
			     (GtkDestroyNotify) gtk_widget_unref);
   gtk_widget_show (entry2);
   gtk_table_attach (GTK_TABLE (table1), entry2, 1, 2, 1, 2,
		     (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
		     (GtkAttachOptions) (0), 0, 0);

   combo_entry2 = gnome_entry_gtk_entry (GNOME_ENTRY (entry2));
   gtk_widget_ref (combo_entry2);
   gtk_object_set_data_full (GTK_OBJECT (window1), "combo_entry2", combo_entry2,
			     (GtkDestroyNotify) gtk_widget_unref);
   gtk_widget_show (combo_entry2);
   gtk_entry_set_text (GTK_ENTRY (combo_entry2), _("build_doc.cc"));

   fileentry1 = gnome_file_entry_new (NULL, NULL);
   gtk_widget_ref (fileentry1);
   gtk_object_set_data_full (GTK_OBJECT (window1), "fileentry1", fileentry1,
			     (GtkDestroyNotify) gtk_widget_unref);
   gtk_widget_show (fileentry1);
   gtk_table_attach (GTK_TABLE (table1), fileentry1, 1, 2, 2, 3,
		     (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
		     (GtkAttachOptions) (0), 0, 0);

   combo_entry3 = gnome_file_entry_gtk_entry (GNOME_FILE_ENTRY (fileentry1));
   gtk_widget_ref (combo_entry3);
   gtk_object_set_data_full (GTK_OBJECT (window1), "combo_entry3", combo_entry3,
			     (GtkDestroyNotify) gtk_widget_unref);
   gtk_widget_show (combo_entry3);

   checkbutton1 = gtk_check_button_new_with_label (_("Generate main"));
   gtk_widget_ref (checkbutton1);
   gtk_object_set_data_full (GTK_OBJECT (window1), "checkbutton1", checkbutton1,
			     (GtkDestroyNotify) gtk_widget_unref);
   gtk_widget_show (checkbutton1);
   gtk_box_pack_start (GTK_BOX (vbox1), checkbutton1, FALSE, FALSE, 0);

   checkbutton2 = gtk_check_button_new_with_label (_("Static linkage (copy dependencies)"));
   gtk_widget_ref (checkbutton2);
   gtk_object_set_data_full (GTK_OBJECT (window1), "checkbutton2", checkbutton2,
			     (GtkDestroyNotify) gtk_widget_unref);
   gtk_widget_show (checkbutton2);
   gtk_box_pack_start (GTK_BOX (vbox1), checkbutton2, FALSE, FALSE, 0);

   checkbutton3 = gtk_check_button_new_with_label (_("Generate makefile"));
   gtk_widget_ref (checkbutton3);
   gtk_object_set_data_full (GTK_OBJECT (window1), "checkbutton3", checkbutton3,
			     (GtkDestroyNotify) gtk_widget_unref);
   gtk_widget_show (checkbutton3);
   gtk_box_pack_start (GTK_BOX (vbox1), checkbutton3, FALSE, FALSE, 0);

   hseparator2 = gtk_hseparator_new ();
   gtk_widget_ref (hseparator2);
   gtk_object_set_data_full (GTK_OBJECT (window1), "hseparator2", hseparator2,
			     (GtkDestroyNotify) gtk_widget_unref);
   gtk_widget_show (hseparator2);
   gtk_box_pack_start (GTK_BOX (vbox1), hseparator2, TRUE, TRUE, 0);

   hbuttonbox1 = gtk_hbutton_box_new ();
   gtk_widget_ref (hbuttonbox1);
   gtk_object_set_data_full (GTK_OBJECT (window1), "hbuttonbox1", hbuttonbox1,
			     (GtkDestroyNotify) gtk_widget_unref);
   gtk_widget_show (hbuttonbox1);
   gtk_box_pack_start (GTK_BOX (vbox1), hbuttonbox1, TRUE, TRUE, 0);
   gtk_button_box_set_layout (GTK_BUTTON_BOX (hbuttonbox1), GTK_BUTTONBOX_END);

   button1 = gtk_button_new_from_stock ("gtk-ok");
   gtk_widget_ref (button1);
   gtk_object_set_data_full (GTK_OBJECT (window1), "button1", button1,
			     (GtkDestroyNotify) gtk_widget_unref);
   gtk_widget_show (button1);
   gtk_container_add (GTK_CONTAINER (hbuttonbox1), button1);
   GTK_WIDGET_SET_FLAGS (button1, GTK_CAN_DEFAULT);

   gtk_signal_connect (GTK_OBJECT (button1), "clicked",
		       GTK_SIGNAL_FUNC( codegen_ok), this);


   button2 = gtk_button_new_from_stock ("gtk-cancel");
   gtk_widget_ref (button2);
   gtk_object_set_data_full (GTK_OBJECT (window1), "button2", button2,
			     (GtkDestroyNotify) gtk_widget_unref);
   gtk_widget_show (button2);
   gtk_container_add (GTK_CONTAINER (hbuttonbox1), button2);
   GTK_WIDGET_SET_FLAGS (button2, GTK_CAN_DEFAULT);

   gtk_signal_connect (GTK_OBJECT (button2), "clicked",
		       GTK_SIGNAL_FUNC( codegen_cancel), this);

   dialog=window1;

   gtk_widget_show(dialog);

}

}//namespace FD



syntax highlighted by Code2HTML, v. 0.9.1