/***************************************************************************
 *   Copyright (C) 2005 by Juergen Thies                                   *
 *   layout@juergenthies.de                                                *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/
#include "macro.h"
#include <qfile.h>
#include <qtextstream.h>
#include <qstring.h>
#include "parservalue.h"
#include "keywords.h"
#include "variant.h"
#include "includes.h"
#include "layout.h"
#ifdef SCHEMATIC
#include "schematic/schematic.h"
#include "schematic/elements/componentplacement.h"
#endif
#include <QDir>
#include <QTextCodec>

macro::macro()
{
layoutWindow=NULL;
globals=NULL;
fileName="";
tmpVarCounter=0;
includeCount=0;
error=NULL;
codec="";
#ifdef SCHEMATIC
   schematicWindow=NULL;
#endif
   //keywords *globals;
   //layoutLock=false;
   //schematicLock=false;
}

macro::macro(layout *main)
{
layoutWindow=main;
globals=NULL;
fileName="";
tmpVarCounter=0;
includeCount=0;
#ifdef SCHEMATIC
   schematicWindow=NULL;
#endif
   //keywords *globals;
   //layoutLock=false;
   //schematicLock=false;
}

macro::~macro()
{
  keywords *help;
  while (globals!=NULL) {
	help=globals;
	globals=globals->next;
  	delete help;
  }
}
#include "generalhandler.cpp"
//#include <QMessageBox>


void macro::load(QString *filename){
  code="";
  fileName=(*filename);
  QFile f( *filename );
  if ( !f.open( QIODevice::ReadOnly ) )
	return ;
  QTextStream ts( &f );
  //ts.setAutoDetectUnicode(true);
  //ts.setCodec(QTextCodec::codecForName("UTF-8"));
  code=ts.readAll();
  codec="";
  if (code.contains("#codec=")){
    int p1=code.indexOf("#codec=",0);
    int p2=code.indexOf("\n",p1+4);
    if (p1<100){
      codec=code.mid(p1+7,p2-p1-7).trimmed();
      //printf("codec (%s)\n",codec.toAscii().data());
      ts.setCodec(QTextCodec::codecForName(codec.toAscii().data()));
      ts.seek(0);
      code=ts.readAll();
    }
  }
  //QMessageBox::information( NULL,"macro",code);
  f.close();
  QDir::setCurrent(QFileInfo(*filename).path());
  include[0].start=1;
  include[0].fileName=(*filename);
  include[0].offset=0;
  includeCount=1;
}

void macro::define(QString s1,QString s2){
s2.replace("\"","\\\"");
code.replace(s1,s2);
}

int macro::execute(){
   error=new errorreport();
   int i=execute(error);
   delete error;
   return i;
}
     
int macro::execute(errorreport *e, QString parameter){
  //printf("parameter %s\n",parameter.toAscii().data());
#ifdef PYTHON
  QString firstLine=code.left(code.indexOf("\n"));
  if (firstLine.contains("python")){
	  if (layoutWindow!=NULL) layoutWindow->callPython(code);
	  else if (schematicWindow!=NULL) schematicWindow->callPython(code);
	  else return 1;
	  return 0;
	  }
#endif
  error=e;
  returnValue r;
  r.setInt(0);
  if (code=="") {
	error->addItem(tr("Unexpected end of File/File not found."),1);
	return 1;
	}
  //create internal keywords;
  if (globals!=NULL) { 
  	keywords *help;
	while (globals!=NULL) {
		help=globals;
		globals=globals->next;
  		delete help;
	}
  	}
  try {
  registerKeywords();
  //create globals
  int prgCounter;
  prgCounter=registerGlobals();
  //run main
  if (prgCounter>0) {
    if (parameter!=""){
	//printf("parameter (%s)\n",parameter.toAscii().data());
	int endPos=code.size()+2;
	code+="\r\n ( "+parameter+" ) \r\n";
	r=funcHandler (&endPos, &prgCounter, &globals->parameter, globals, varInt);
    }
    else run(&prgCounter,&r,globals);
    error->addItem(tr("Macro completed."),4);
    return r.getInt();
    }
  else {
    error->addItem(tr("main function (\"int main(){...}\") not found."),1);
    return 1;
  }}
  catch (int i){
    errorMessage(i,error);
    error->addItem(tr("Executing abort."),1);
    return 1;
  }
}

void macro::executeSingle(QString line,errorreport *e){
  error=e;
  includeCount=0;
  try {
   	code=line+"\n";
  	registerKeywords();
  	variant r;
  	int prgCounter;
  	prgCounter=0;
  	run(&prgCounter,&r,globals,true);
  }
  catch (int i){
  	errorMessage(i,error);
  }
}

 
bool macro::isMacro(QString *filename, QString *name,QString *help){
  QFile f( *filename );
  if ( !f.open( QIODevice::ReadOnly ) )
	return false;
  QTextStream ts( &f );
  ts.setAutoDetectUnicode(true);
  QString s;
  s=ts.readLine();
#ifdef PYTHON
  if ((s.left(2)=="#!") && (s.indexOf("python",1)!=(-1))) {;}
  else 
#endif
  if ((s.left(2)!="#!") || (s.indexOf("layout",1)==(-1))) return false;
  s=ts.readLine();
  int i=s.indexOf("codec",1);
  int k=s.indexOf("=",i);
  if ((s.left(1)=="#")&&(i!=-1)&&(k!=-1)) {
    ts.setCodec(QTextCodec::codecForName(s.mid(k+1).trimmed().toAscii().data()));
    s=ts.readLine();
  }
  i=s.indexOf("name",1);
  k=s.indexOf("=",i);
  if ((s.left(1)=="#")&&(i!=-1)&&(k!=-1)) (*name)=s.mid(k+1);
  s=ts.readLine();
  i=s.indexOf("help",1);
  k=s.indexOf("=",i);
  if ((s.left(1)=="#")&&(i!=-1)&&(k!=-1)) (*help)=s.mid(k+1);
  f.close();
  return true;
}
int macro::registerGlobals(){
  parserValue parser;
  QString s;
  int counter=0;
  bool exit=false;
  do {  
	parser=next(&counter);
	lastCounter=counter;
	switch (parser.type){
	case keyword:{
		keywords *help=globals;
		bool found=false;
		while ((help!=NULL)&&(found==false)){
		 	if (help->keyword==parser.value) found=true;
		 	else help=help->next;
		  }
		if (found) {
			if (help->type==type) {
				(this->*help->typeHandler)(&counter,&globals,false);
				if (globals->keyword=="main") exit=true;
				}
			else throw 2;}
		break;}
	default:
		throw 2;
	}
 }
 while (exit==false);
 if (globals->type==func) return globals->counter;
return 0; // code.find("int main(){");
}

void macro::registerKeywords(){
  voidHandler_registerKeywords(&globals);
  intHandler_registerKeywords(&globals);
  stringHandler_registerKeywords(&globals);
  stringListHandler_registerKeywords(&globals);
  boolHandler_registerKeywords(&globals);
  doubleHandler_registerKeywords(&globals);
  layersHandler_registerKeywords(&globals);
  cellHandler_registerKeywords(&globals);
  cellListHandler_registerKeywords(&globals);
  drawingFieldHandler_registerKeywords(&globals);
  layoutHandler_registerKeywords(&globals,layoutWindow);
  setupHandler_registerKeywords(&globals);
  elementHandler_registerKeywords(&globals);
  elementListHandler_registerKeywords(&globals);
  pointHandler_registerKeywords(&globals);
  pointArrayHandler_registerKeywords(&globals);
  rectHandler_registerKeywords(&globals);
  fileHandler_registerKeywords(&globals);
  mathHandler_registerKeywords(&globals);
  stdlibHandler_registerKeywords(&globals);
  layerTranslatorHandler_registerKeywords(&globals);
  processHandler_registerKeywords(&globals);
#ifdef netlistutility
  netListModuleHandler_registerKeywords(&globals);
  netListHandler_registerKeywords(&globals);
  netListDeviceHandler_registerKeywords(&globals);
#endif
#ifdef barcodeutility
  barcodeModuleHandler_registerKeywords(&globals);
#endif
#ifdef backgroundutility
  backgroundModuleHandler_registerKeywords(&globals);
#endif
#ifdef USE_3d
  view3dModuleHandler_registerKeywords(&globals);
#endif
#ifdef SCHEMATIC
  schematicHandler_registerKeywords(&globals,schematicWindow);
  schematicDisplayHandler_registerKeywords(&globals);
  sheetHandler_registerKeywords(&globals);
  sheetListHandler_registerKeywords(&globals);
  sElementHandler_registerKeywords(&globals);
  sElementListHandler_registerKeywords(&globals);
#endif
#ifdef TEXTEDIT
 textDisplayHandler_registerKeywords(&globals);
 textEditHandler_registerKeywords(&globals);
#endif
}
 

void macro::errorMessage(int num,errorreport *error){
    switch (num) {
    case 0:break;
    case 1: error->addItem(tr("Error."),1,message(lastCounter));break;
    case 2: error->addItem(tr("Syntax error."),1,message(lastCounter));break;
    case 3: error->addItem(tr("while expected."),1,message(lastCounter));break;
    case 4: error->addItem(tr("Unexpected end of file."),1,message(lastCounter));break;
    case 5: error->addItem(tr("Comment did not end."),1,message(lastCounter));break;
    case 6: error->addItem(tr("Operator expected."),1,message(lastCounter));break;
    case 7: error->addItem(tr("Unknown operator."),1,message(lastCounter));break;
    case 8: error->addItem(tr("Identifier expected."),1,message(lastCounter));break;
    case 9: error->addItem(tr("( expected."),1,message(lastCounter));break;
    case 10: error->addItem(tr(") expected."),1,message(lastCounter));break;
    case 11: error->addItem(tr("[ expected."),1,message(lastCounter));break;
    case 12: error->addItem(tr("] expected."),1,message(lastCounter));break;
    case 13: error->addItem(tr(". expected."),1,message(lastCounter));break;
    case 14: error->addItem(tr("-> expected."),1,message(lastCounter));break;
    case 15: error->addItem(tr("; expected."),1,message(lastCounter));break;
    case 16: error->addItem(tr(", expected."),1,message(lastCounter));break;
    case 17: error->addItem(tr("unknown member."),1,message(lastCounter));break;
    case 18: error->addItem(tr("member expected"),1,message(lastCounter));break;
    case 19: error->addItem(tr("Class layers has only static variables."),1,message(lastCounter));break;
    case 20: error->addItem(tr("Operator not valid for this type."),1,message(lastCounter));break;
    case 21: error->addItem(tr("Can't convert to required class."),1,message(lastCounter));break;
    case 22: error->addItem(tr("Can't convert to string."),1,message(lastCounter));break;
    case 23: error->addItem(tr("Can't convert to int."),1,message(lastCounter));break;
    case 24: error->addItem(tr("Can't convert to double."),1,message(lastCounter));break;
    case 25: error->addItem(tr("Can't convert to bool."),1,message(lastCounter));break;
    case 26: error->addItem(tr("type expected."),1,message(lastCounter));break;
    case 27: error->addItem(tr("Double pointer are not allowed."),1,message(lastCounter));break;
    case 28: error->addItem(tr("* operator only work on pointers."),1,message(lastCounter));break;
    case 29: error->addItem(tr("Can't convert to * int."),1,message(lastCounter));break;
    case 30: error->addItem(tr("Can't convert to * double."),1,message(lastCounter));break;
    case 31: error->addItem(tr("Divide by zero"),1,message(lastCounter));break;
    case 32: error->addItem(tr("Class math has only static functions."),1,message(lastCounter));break;
    case 33: error->addItem(tr("Class stdlib has only static functions."),1,message(lastCounter));break;
    case 34: error->addItem(tr("File not found"),1,message(lastCounter));break;
    case 35: error->addItem(tr(""),1,message(lastCounter));break;
    default: ;
    }
}
#include "inthandler.cpp"
#include "doublehandler.cpp"
#include "voidhandler.cpp"
#include "stringhandler.cpp"
#include "stringlisthandler.cpp"
#include "boolhandler.cpp"
#include "layouthandler.cpp"
#include "cellhandler.cpp"
#include "celllisthandler.cpp"
#include "drawingfieldhandler.cpp"
#include "recthandler.cpp"
#include "elementhandler.cpp"
#include "elementlisthandler.cpp"
#include "pointhandler.cpp"
#include "pointarrayhandler.cpp"
#include "filehandler.cpp"
#include "drchandler.cpp"
#include "layershandler.cpp"
#include "setuphandler.cpp"
#include "mathhandler.cpp"
#include "stdlibhandler.cpp"
#include "layertranslatorhandler.cpp"
#include "processhandler.cpp"
#ifdef netlistutility
#include "netlistmodulehandler.cpp"
#include "netlistdevicehandler.cpp"
#include "netlisthandler.cpp"
#endif
#ifdef barcodeutility
#include "barcodemodulehandler.cpp"
#endif
#ifdef backgroundutility
#include "backgroundmodulehandler.cpp"
#endif
#ifdef USE_3d
#include "view3dmodulehandler.cpp"
#endif
#ifdef SCHEMATIC
#include "schematichandler.cpp"
#include "schematicdisplayhandler.cpp"
#include "sheethandler.cpp"
#include "sheetlisthandler.cpp"
#include "selementhandler.cpp"
#include "selementlisthandler.cpp"
#include "celhandler.cpp"
#endif
#ifdef TEXTEDIT
#include "textedithandler.cpp"
#include "textdisplayhandler.cpp"
#endif
