/**************DO NOR REMOVE THIS BANNER***************/
/*  FreeFEM : Language for a Finite Element Method    */
/*  -------    Release 1.0:  June 1994.               */
/*  Authors: D. Bernardi, Y. Darmaillac F. Hecht,     */
/*           O. Pironneau P. Parole                   */
/*  You may copy freely these files and use it for    */
/* teaching or research. These or part of these may   */
/* not be sold or used for a commercial purpose with- */
/* out our consent : fax (33)1 44 27 44 11            */
/* (fax)    Olivier.Pironneau@ann.jussieu.fr          */
/******************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
#include <setjmp.h>

#include <new.h>
#include <iostream.h>

/*
** Windows includes
*/
#include <windows.h>
#include <commdlg.h>
#include <direct.h>
#include <memory.h>
/*
 * freefem includes
 */
#include "OPclass.h"
#include "disk.h"
#include "rgraph.h"
#include "lexical.h"
#include "syntaxic.h"
#include "rgraph.h"

HWND        hWnd1;
WNDCLASS    rClass;
HDC hdc;
extern char errbuf[];
float rayon;
static float aspx, aspy, echx,echy,ech,rxmin,rxmax,rymin,rymax;
static int Ax,Ay,Lx,Ly,currx,curry;	 /// both put to static
int end;
extern float xfmin,xfmax;

static int carre, lacouleur;
extern triangulation t;
int NbPlotTotal;
char FreeFemCache[256],shortName[256],fullName[256];

/* Function definitions */
BOOL Init(HANDLE hInstance,   HANDLE hPrevInstance,
	  LPSTR  lpszCmdLine, int    CmdShow);

int  DoMain(HANDLE hInstance);
long FAR PASCAL OpenWindowProc1 (HWND     hWnd,
				       unsigned msgID,
				       unsigned wParam,
				LONG     lParam);

int getcolor();
void putpixel(int ix,int iy, int couleur);
int scalx(float x);
int scaly(float y);
void rattente (int);
void compile (char *);

/*
 * WinMain:
 *     Parameters:
 *         hInstance     - Handle to current Data Segment
 *         hPrevInstance - Handle to previous Data Segment (NULL if none)
 *         lpszCmdLine   - Long pointer to command line info
 *         nCmdShow      - Integer value specifying how to start program
 *                            (Iconic [7] or Normal [1,5])
 */
 void postexit()
 {
  FILE *temp;
  char chemin[256];
 if (strcmp(FreeFemCache,"")==0) return;
  strcpy(chemin,FreeFemCache);
  strcat(chemin,"temp.tmp");
  temp=fopen(chemin,"r");
  if (temp!=NULL)
     {
	  fclose(temp);
	  int alors=remove(chemin);
	 }
 }

int PASCAL WinMain (HANDLE hInstance,
		    HANDLE hPrevInstance,
		    LPSTR  lpszCmdLine,
		    int    nCmdShow)
{
  int nReturn;

  if (Init(hInstance, hPrevInstance,lpszCmdLine,nCmdShow))
      nReturn = DoMain(hInstance);

  return nReturn;
}

FILE *projet;

BOOL CreateProjetFile(char *fileName)
{
 char chemin[256];

 strcpy(chemin,FreeFemCache);
 strcat(chemin,fileName);
 if (projet=fopen(chemin,"w"),!projet)
     return FALSE;
 fprintf(projet,"FFF@PCgFEM@FFF");
 return TRUE;
}

char *ChangePdeToExt(char *fileName,char *ext)
{
 int len;
 char *file;

 file=strdup(fileName);
 len=strlen(fileName);
 file[strlen(fileName)-4]='.';
 file[strlen(fileName)-3]=ext[0];
 file[strlen(fileName)-2]=ext[1];
 file[strlen(fileName)-1]=ext[2];
 return file;
}

BOOL TestProjetPresence(char *fileName)
{
 if (strcmp(FreeFemCache,"")==0) return FALSE;
 char chemin[256];
 strcpy(chemin,FreeFemCache);
 strcat(chemin,fileName);
 FILE *file;
 if (file=fopen(chemin,"r"),!file)
  return FALSE;
 fclose(file);
 return TRUE;
}

int ShowFreefemView()
{
 char prjName[256];

 strcpy(prjName,ChangePdeToExt(shortName,"prj"));

 if (TestProjetPresence(prjName)==TRUE)
  if (MessageBox(NULL,"ALREADY SOLVED PCgFEM's PROBLEM !\n            RUN
PCgFEM SOLVER ?         ","FREEFEM
INFORMATION",MB_YESNO|MB_SYSTEMMODAL|MB_ICONQUESTION)!=6)
     {
      DestroyWindow(hWnd1);
      postexit();
      return 0;
     }
 char m[256],c[256];
 strcpy(m,"Unable to CREATE PCgFEM's Project in :!\n");
 strcpy(c,FreeFemCache);
 strcat(c,prjName);
 strcat(m,c);
 if (strcmp(FreeFemCache,"")!=0)
  if (CreateProjetFile(prjName)==FALSE)
   MessageBox(NULL,c,"FREEFEM
INFORMATION",MB_OK|MB_SYSTEMMODAL|MB_ICONEXCLAMATION);

 if (projet!=NULL)
  fprintf(projet,"\n0 %s",shortName);

 compile(fullName);
 if (projet!=NULL)
  fclose(projet);

 end=0;
 TextOut(hdc,0,0,"                     ",20);
 TextOut(hdc,0,0,"Click to exit...               ",30);
 return 1;
}

BOOL ShowOpenDialogBox(char *fileName)
{
OPENFILENAME ofn;
char szDirName[256];
char *strFilter="PCgFEM Files (*.pde)\0*.pde\0All Files (*.*)\0*.*\0\0";

memset(&ofn, 0, sizeof(OPENFILENAME));
getcwd(szDirName,sizeof(szDirName));
ofn.lStructSize = sizeof(OPENFILENAME);
ofn.hwndOwner = NULL;
ofn.lpstrFilter = strFilter;
ofn.lpstrFileTitle = fileName;
ofn.nMaxFileTitle = 80;
ofn.lpstrInitialDir=szDirName;
ofn.lpstrTitle ="Choose you PCgFEM File";
ofn.Flags=OFN_SHOWHELP|OFN_PATHMUSTEXIST|OFN_FILEMUSTEXIST;

return GetOpenFileName(&ofn);
}


/*
 * Init
 *     Initialization for the program is done here:
 *     1)  Register the window class (if this is the first instance)
 *     2)  Create the desktop window for the app.
 *     3)  Show the desktop window in the manner requested by the User.
 *
 */
BOOL Init(HANDLE hInstance,   HANDLE hPrevInstance,
	  LPSTR  lpszCmdLine, int    nCmdShow)
{
 int i,j,k;
    if (!hPrevInstance)
    {
	/*  Register Class for First Overlapped Window  */
	rClass.lpszClassName = "OPENMAIN";
	rClass.hInstance     = hInstance;
	rClass.lpfnWndProc   = OpenWindowProc1;
	rClass.hCursor       = LoadCursor(NULL, IDC_ARROW);
	rClass.hIcon         = LoadIcon(NULL, IDI_APPLICATION);
	rClass.hbrBackground = GetStockObject(WHITE_BRUSH);
	rClass.style         = 0x4000;
	rClass.cbClsExtra    = 0;
	rClass.cbWndExtra    = 0;

	if (!RegisterClass( &rClass))
	    return FALSE;
    }

    hWnd1 = CreateWindow("OPENMAIN",
	    "FREEFEM for Windows",
	    WS_OVERLAPPEDWINDOW,
	    CW_USEDEFAULT,
	    CW_USEDEFAULT,
	    CW_USEDEFAULT,
	    CW_USEDEFAULT,
	    NULL,
	    NULL,
	    hInstance,
	    NULL);

if ((lpszCmdLine[0] != '\0')&&(strncmp("just solve :",lpszCmdLine,12)==0))
 {
  i=0;
  while (lpszCmdLine[12+i]!=' ')
   FreeFemCache[i++]=lpszCmdLine[12+i];

  j=0;
  while (lpszCmdLine[12+i+1+j]!=' ')
   shortName[j++]=lpszCmdLine[12+i+1+j];

  for (k=14+i+j;k<(int)strlen(lpszCmdLine);k++)
   fullName[k-14-i-j]=lpszCmdLine[k];

  }

 else
   {
   if (ShowOpenDialogBox(shortName)==FALSE)
      {
	   postexit();
       exit(0);
      }
    strcpy(fullName,shortName);
   }

 if (ShowFreefemView()==0)
    return NULL;
 else
    return TRUE;


}

/*
 * DoMain:
 *     This is the main loop for the application, often called the message
 *     pump.
 */
int  DoMain(HANDLE hInstance)
{
MSG msg;

    while (GetMessage(&msg,NULL,0,0))
    {
	TranslateMessage(&msg);
	DispatchMessage(&msg);
    }
    return msg.wParam;
}

/* OpenWindowProc1 - Handles messages for the main window.
 *     Parameters:
 *         hWnd    - Handle to Window which message is delivered to.
 *         msgID   - ID number of message
 *         wParam  - 16-bit parameter
 *         lParam  - 32-bit parameter
 *
 */
long FAR PASCAL OpenWindowProc1 (HWND     hWnd,
				       unsigned wMsgID,
				       unsigned wParam,
				       LONG     lParam)
{
 char fileName[256];
                              switch (wMsgID)
   {

    case WM_DESTROY:
	PostQuitMessage(0);
	break;

	case WM_LBUTTONDOWN:
	if (end==1)
	 {
	  if (ShowOpenDialogBox(fileName)==FALSE)
      {
	   postexit();
       exit(0);
      }
 	  ShowFreefemView();
	  postexit();
	 }
	else
	{
	 postexit();
	 exit(0);
	}
	break;


    default:
	return DefWindowProc(hWnd, wMsgID, wParam, lParam);
    }

return 0;
}
/******************************/
#if defined(MVC)
int
out_of_memory(unsigned int err)
#else
void
out_of_memory ()
#endif /* MVC */
{
  cerr << "FreeFEM error: operator new failed; not enough memory" << endl;
  postexit();
  exit (-1);
#if defined (MVC)
  return err=0;
#endif /* MVC */
}
void
NEW_HANDLER (void)
{
#if defined(MVC)
  _set_new_handler (&out_of_memory);
#else
  set_new_handler (&out_of_memory);
#endif /* MVC */
}

void erreur(char *s)
{
 rattente(2);
 char se[256],prj[256];
 strcpy(se,shortName);
 strcat(se," : Syntax Error\n");
 strcat(se,s);
 MessageBox(NULL,se,"FREEFEM SOLVER",MB_OK|MB_SYSTEMMODAL|MB_ICONEXCLAMATION);
 strcpy(prj,ChangePdeToExt(shortName,"prj"));
 strcpy(se,FreeFemCache);
 strcat(se,prj);
 if (projet!=NULL)
  fclose(projet);
  if (strcmp(FreeFemCache,"")!=0)
  if (remove(se)!=0)
   {
    strcpy(se,"Unable to remove ");
    strcat(se,prj);
    strcat(se," in projet folder !");
    MessageBox(NULL,se,"FREEFEM
SOLVER",MB_OK|MB_SYSTEMMODAL|MB_ICONEXCLAMATION);
   }
 postexit();
 exit(0);
}

void initgraphique(void)
{
 RECT rc;
 GetClientRect(hWnd1, &rc);
 hdc=GetDC(hWnd1);
 aspx = (float)(rc.right - rc.left);
 aspy = (float)(rc.bottom - rc.top);
 carre = aspx == aspy;
}

void closegraphique(void)
{
	ReleaseDC(hWnd1,hdc);
}

void rattente(int waitm)
{
 char c=' ';
/*    you may prefer to use carriage return to move to the next graph */
/*	 getc(stdin);
*/

if (waitm>1) return;
TextOut(hdc,0,0,"                     ",20);
TextOut(hdc,0,0,"Click to continue...",19);
MSG msg;
if (waitm)
do
{
GetMessage(&msg,hWnd1,WM_MOUSEFIRST,WM_MOUSELAST);
if (msg.message==WM_RBUTTONDOWN)
    {
	 postexit();
     exit(0);
	}
}
while (msg.message!=WM_LBUTTONDOWN);

TextOut(hdc,0,0,"                     ",20);
TextOut(hdc,0,0,"FreeFem works...",17);
}

void reffecran(void)
{
 HBRUSH hbr;
 RECT rc;

 GetClientRect(hWnd1, &rc);
 hbr = CreateSolidBrush(RGB(255, 255, 255));
 FillRect(hdc,&rc,hbr);
 DeleteObject(hbr);
}

int getcolor(void)
{
 return 0;
}

void putpixel(int ix,int iy, int couleur)
{
}

void couleur(int c)
{
}

/*void cadre(float xmin,float xmax,float ymin,float ymax)
{
  rxmin = xmin;
  rxmax = xmax;
  rymin = ymin;
  rymax = ymax;
  echx = aspx / (xmax - xmin);
  echy = aspy / (ymax - ymin);
}
*/

void cadre(float xmin,float xmax,float ymin,float ymax)
{
RECT rc;
int a,b,le,Ex,Ey;
le=20;
float px,py;
GetClientRect(hWnd1, &rc);
rxmin = xmin;
rxmax = xmax;
rymin = ymin;
rymax = ymax;
px=xmax-xmin;
py=ymax-ymin;
 if ( px > py)
    {/* Our Object larger than long */
     Ax=le; Lx=((rc.right-rc.left)-2*le);
     Ex=Lx; Ey=(int)(Ex*(py/px));
     b=((rc.bottom-rc.top)-Ey-2*le)/2;
     Ay=b+le; Ly=Ey;
     if (Ey>(rc.bottom-rc.top)-2*le){Ay=le; Ly=((rc.bottom-rc.top)-2*le);
     						          Ey=Ly;
Ex=(int)(Ey*(px/py));

a=((rc.right-rc.left)-Ex-2*le)/2;
     								  Ax=a+le;
Lx=Ex;
                                     }
    }
else
    {/* Our Object longer than large */
     Ay=le; Ly=((rc.bottom-rc.top)-2*le);
     Ey=Ly; Ex=(int)(Ey*(px/py));
     a=((rc.right-rc.left)-Ex-2*le)/2;
     Ax=a+le; Lx=Ex;
     if (Ex>(rc.right-rc.left)-2*le){Ax=le; Lx=((rc.right-rc.left)-2*le);
     								 Ex=Lx;
Ey=(int)(Ex*(py/px));

b=((rc.bottom-rc.top)-Ey-2*le)/2;
     								 Ay=b+le;
Ly=Ey;
     								}

    }
echx=1/(xmax-xmin);
echy=1/(ymax-ymin);

}

int scalx(float x)
{
 int test;
 test=(int)(Ax+Lx*(x-rxmin)*echx);
 return test;
}

int scaly(float y)
{
int test;
 test=(int)(Ay+Ly*(rymax-y)*echy);
 return test;
}

void pointe(float x, float y)
{
  putpixel(scalx(x), scaly(y), lacouleur);
}

void rmoveto(float x, float y)
{
 currx = scalx(x);
 curry = scaly(y);
 //MoveTo(hdc,scalx(x), scaly(y));
}

void rlineto(float x, float y)
{
  int newx = scalx(x), newy = scaly(y);
  MoveToEx(hdc,currx,curry,NULL);
  LineTo(hdc,newx,newy);
  currx = newx; curry = newy;
}

void cadreortho(float centrex, float centrey, float ray)
{								  ///
  cadre(centrex-ray, centrex+ray, centrey-ray, centrey+ray);
}
void raffpoly(int n, float *poly)
{
}

int getprog(char* fn,int argc, char** argvptr)
{
return 0;
}

void execute(char* what)
{
// exec(what); link with unix lib
}

void compile(char *fname)
{
 arbre f;
 char* prog=NULL;
 OPTION=0;
 prog = readprog(fname);	 ///
/*    {
   	   sprintf(errbuf, "Can't find %s\n Please assure it's present or saved
!\n", fname);
   	   erreur(errbuf);
   	}
*/
 initlex(prog);
 initsyntax();
 f = instruction();
/*    	showtree(f);   use this to debug */
 chvar();
 initgraphique();
 if (f==NULL)
  erreur ("Line 1: expecting any symbol");
 ShowWindow(hWnd1,SW_SHOW);
 eval(f);
/*   	safefree(&prog); bucheron(f);   libere();  cleans heap: not needed
here because we  exit */
 closegraphique();
}

void SaveMesh()
{
 FILE *mesh;
 char chemin[256],meshName[256];
 int i,j;
 if (strcmp(FreeFemCache,"")==0) return;
 strcpy(chemin,FreeFemCache);
 strcpy(meshName,ChangePdeToExt(shortName,"msh"));
 strcat(chemin,meshName);
 if (mesh=fopen(chemin,"w"),!mesh)
  {
   MessageBox(NULL,"Unable to SAVE MESH for PCgFEM !","FREEFEM
INFORMATION",MB_OK|MB_SYSTEMMODAL|MB_ICONEXCLAMATION);
   return;
  }
 fprintf(projet,"\n1 %s",meshName);
 fprintf(mesh, "FFF@PCgFEM_MESH@FFF\n");
 fprintf( mesh, "%ld %ld \n", t.np, t.nt );
 if (t.ngt!=NULL)
  for ( i=0; i<t.np; i++ )
   fprintf( mesh, "%d %f %f %d\n", t.ng[i], t.rp[i].x, t.rp[i].y , t.ngt[i]);
 else
  for ( i=0; i<t.np; i++ )
   fprintf( mesh, "%d %f %f 0\n", t.ng[i], t.rp[i].x, t.rp[i].y);

 for ( i=0; i<t.nt; i++ )
  {
   for( j=0; j<3; j++ ) fprintf( mesh, "%ld ", t.tr[i][j]);
   fprintf( mesh, "\n" );
  }
 fclose(mesh);
 NbPlotTotal=0;
}

void SavePlot(int D,float *f)
{
 FILE *plot;
 char chemin[256],plotName[256];
 int i;
 if (strcmp(FreeFemCache,"")==0) return;
 strcpy(chemin,FreeFemCache);
 strcpy(plotName,ChangePdeToExt(shortName,"dta"));
 strcat(chemin,plotName);

 if (plot=fopen(chemin,"w"),!plot)
  {
   MessageBox(NULL,"Unable to SAVE PLOT for PCgFEM !","FREEFEM
INFORMATION",MB_OK|MB_SYSTEMMODAL|MB_ICONEXCLAMATION);
   return;
  }
 if (NbPlotTotal==0)
  fprintf(projet,"\n%d %s",2,plotName);
 fprintf(plot, "FFF@PCgFEM_PLOT@FFF\n");

 fprintf(plot,"%s\n",ChangePdeToExt(shortName,"msh"));
 fprintf(plot,"%d\n",D);
 fprintf(plot,"%d\n",t.np);
 for (i=0; i<t.np; i++)
  fprintf(plot,"%d %f\n", t.ng[i], f[i]);
 fclose(plot);

 NbPlotTotal++;
}
