/* 
 * $Id: main.c,v 1.10 2003/02/16 12:43:37 isizaka Exp isizaka $
 * 
 * This file is part of "Ngraph for X11".
 * 
 * Copyright (C) 2002, Satoshi ISHIZAKA. isizaka@msa.biglobe.ne.jp
 * 
 * "Ngraph for X11" 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.
 * 
 * "Ngraph for X11" 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.
 * 
 */

/**
 *
 * $Log: main.c,v $
 * Revision 1.10  2003/02/16 12:43:37  isizaka
 * for release 6.13.18
 *
 * Revision 1.9  2002/07/06 08:57:25  isizaka
 * change to GPL.
 *
 * Revision 1.8  2001/03/23 12:17:43  isizaka
 * for 6.3.13
 *
 * Revision 1.7  1999/07/31 11:12:30  isizaka
 * about stderr
 *
 * Revision 1.6  1999/05/31 10:33:13  isizaka
 * for release 6.03.03
 *
 * Revision 1.5  1999/05/08 13:31:30  isizaka
 * for release 6.03.02
 *
 * Revision 1.4  1999/04/15 12:14:26  isizaka
 * for release 6.03.01
 *
 * Revision 1.3  1999/04/11 06:08:57  isizaka
 * *** empty log message ***
 *
 * Revision 1.2  1999/03/20 12:32:54  isizaka
 * minor change
 *
 * Revision 1.1  1999/03/17 13:27:48  isizaka
 * Initial revision
 *
 *
 **/

#include <Xm/XmAll.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdarg.h>

#include "ngraph.h"
#include "object.h"
#include "ioutil.h"
#include "nstring.h"
#include "config.h"

#define TRUE  1
#define FALSE 0

#define SYSCONF "[Ngraph]"
#ifndef LIBDIR
#define LIBDIR "/usr/local/lib/Ngraph"
#endif

int consolecol=80;
int consolerow=25;


char **mainenviron;
char *systemname;
int consolefdout;
int consolefdin;
int consoleac=FALSE;

void *addobjectroot(void);
void *addint(void);
void *adddouble(void);
void *addstring(void);
void *addiarray(void);
void *adddarray(void);
void *addsarray(void);
void *addsystem(void);
void *addshell(void);
void *adddraw(void);
void *addfile(void);
void *addmath(void);
void *addfit(void);
void *addgra(void);
void *addgra2(void);
void *addgra2null(void);
void *addgra2file(void);
void *addgra2prn(void);
void *addmerge(void);
void *addlegend(void);
void *addline(void);
void *addcurve(void);
void *addrectangle(void);
void *addarc(void);
void *addpolygon(void);
void *addmark(void);
void *addtext(void);
void *addaxis(void);
void *addagrid(void);
void *addprm(void);

void *addgra2x11(void);
void *addmenu(void);
void *adddialog(void);

void resizeconsole(int col,int row);

XtAppContext Application=NULL;
Display *Disp=NULL;
char *AppName="Ngraph";
char *AppClass="Ngraph";
extern Widget TopLevel;
static String fallbacks[] = {
  "Ngraph*title: Ngraph",
  NULL
};

int Xerrorhandler(Display *d,XErrorEvent *e)
{
  char buf[256];

  XGetErrorText(d,e->error_code,buf,sizeof(buf));
  fprintf(stderr,"%s\n",buf);
  return 0;
}

int OpenApplication()
{
  int argc;
  char *argv[2];

  if (Application==NULL) {
    XtToolkitInitialize();
    Application=XtCreateApplicationContext();
    XtSetLanguageProc(NULL,NULL,NULL);
    XtAppSetFallbackResources(Application,fallbacks);
  }
  if (Disp==NULL) {
    argc=1;
    argv[0]="Ngraph";
    argv[1]="NULL";
    Disp=XtOpenDisplay(Application,NULL,AppName,AppClass,NULL,0,&argc,argv);
    if (Disp==NULL) {
      fprintf(stderr,"Cannot open display.\n");
      return FALSE;
    }
    XSetErrorHandler(Xerrorhandler);
  }
  return TRUE;
}

int putconsole(char *s)
{
  int len;

  len=strlen(s);
  write(consolefdout,s,len);
  write(consolefdout,"\n",1);
  return len+1;
}

int printfconsole(char *fmt,...)
{
  int len;
  char buf[1024];
  va_list ap;

  va_start(ap,fmt);
  len=vsprintf(buf,fmt,ap);
  va_end(ap);
  write(consolefdout,buf,len);
  return len;
}

int interruptconsole(void)
{
  return FALSE;
}

int inputynconsole(char *mes)
{
  int len;
  char buf[10];

  len=strlen(mes);
  write(consolefdout,mes,len);
  do {
    read(consolefdin,buf,1);
  } while ((buf[0]!='y') && (buf[0]!='Y') && (buf[0]!='n') && (buf[0]!='N'));
  if ((buf[0]=='y') || (buf[0]=='Y')) return TRUE;
  return FALSE;
}

void displaydialogconsole(char *str)
{
  putconsole(str);
}

void displaystatusconsole(char *str)
{
}

char *terminal=NULL;
struct savedstdio consolesave;
int consolefd[3];
int pipefd=-1;
pid_t consolepid=-1;

void resizeconsole(int col,int row)
{
}

int nallocconsole()
{
  int fd[3],fdi[2],fdo[2],len,i;
  pid_t pid;
  char buf[256],ttyname[256];
  char *s,*s2;
  char **argv;
  struct objlist *sys;
  char *sysname;
  char *version;

  if (consoleac) return FALSE;
  if (terminal==NULL) return FALSE;
  if (pipe(fdi)==-1) return FALSE;
  if (pipe(fdo)==-1) {
    close(fdi[0]);
    close(fdi[1]);
    return FALSE;
  }
  if ((pid=fork())==-1) {
    close(fdi[0]);
    close(fdi[1]);
    close(fdo[0]);
    close(fdo[1]);
    return FALSE;
  } else if (pid==0) {
    sprintf(buf,"%s %d %d %d %d",terminal,fdi[0],fdi[1],fdo[0],fdo[1]);
    argv=NULL;
    s=buf;
    while ((s2=getitok2(&s,&len," \t"))!=NULL) {
      arg_add(&argv,s2);
    }
    execvp(argv[0],argv);
    exit(1);
  }
  close(fdi[1]);
  close(fdo[0]);
  sys=chkobject("system");
  getobj(sys,"name",0,0,NULL,&sysname);
  getobj(sys,"version",0,0,NULL,&version);
  sprintf(buf,"%c]2;Ngraph shell%c%s version %s. Script interpreter.\n",
               0x1b,0x07,sysname,version);
  write(fdo[1],buf,strlen(buf)+1);
  pipefd=fdo[1];
  consolepid=pid;
  i=0;
  while ((read(fdi[0],buf,1)==1) && (buf[0]!='\0')) {
    ttyname[i]=buf[0];
    i++;
  }
  ttyname[i]='\0';
  close(fdi[0]);
  if (i==0) return FALSE;
  fd[0]=open(ttyname,O_RDONLY);
  fd[1]=open(ttyname,O_WRONLY);
  fd[2]=open(ttyname,O_WRONLY);
  consolefd[0]=dup(0);
  close(0);
  dup2(fd[0],0);
  consolefd[1]=dup(1);
  close(1);
  dup2(fd[1],1);
  consolefd[2]=dup(2);
  close(2);
  dup2(fd[2],2);
  close(fd[0]);
  close(fd[1]);
  close(fd[2]);
  consolefdin=dup(0);
  consolefdout=dup(2);
  consoleac=TRUE;
  savestdio(&consolesave);
  putstderr=putconsole;
  printfstderr=printfconsole;
  ninterrupt=interruptconsole;
  inputyn=inputynconsole;
  ndisplaydialog=displaydialogconsole;
  ndisplaystatus=displaystatusconsole;
  return TRUE;
}

void nfreeconsole()
{
  char buf[1];

  if (consoleac) {
    close(0);
    if (consolefd[0]!=-1) {
      dup2(consolefd[0],0);
      close(consolefd[0]);
    }
    close(1);
    if (consolefd[1]!=-1) {
      dup2(consolefd[1],1);
      close(consolefd[1]);
    }
    close(2);
    if (consolefd[2]!=-1) {
      dup2(consolefd[2],2);
      close(consolefd[2]);
    }
    buf[0]='\0';
    write(pipefd,buf,1);
    close(pipefd);
    pipefd=-1;
    consolepid=-1;
    close(consolefdin);
    close(consolefdout);
    consolefdin=0;
    consolefdout=2;
    consoleac=FALSE;
    loadstdio(&consolesave);
  }
}

void nforegroundconsole()
{
}

int main(int argc,char **argv,char **environ)
{
  char *homedir,*libdir,*home,*lib,*inifile,*loginshell;
  char *inst;
  struct objlist *sys,*obj,*lobj;
  int i,id;
  char *sarg[2];
  struct narray sarray;
  FILE *fp;
  char *tok,*str,*s2;
  char *f1,*endptr;
  int len,val;
  int allocnow,allocconsole;
  struct narray iarray;
  char *arg;

  mainenviron=environ;

  ignorestdio(NULL);
  inputyn=vinputyn;
  ninterrupt=vinterrupt;
  printfstderr=seprintf;
  putstderr=seputs;
  consolefdin=0;
  consolefdout=2;

  if ((lib=getenv("NGRAPHLIB"))!=NULL) {
    if ((libdir=(char *)memalloc(strlen(lib)+1))==NULL) exit(1);
    strcpy(libdir,lib);
  } else {
    if ((libdir=(char *)memalloc(strlen(LIBDIR)+1))==NULL) exit(1);
    strcpy(libdir,LIBDIR);
  }
  if ((home=getenv("NGRAPHHOME"))!=NULL) {
    if ((homedir=(char *)memalloc(strlen(home)+1))==NULL) exit(1);
    strcpy(homedir,home);
  } else if ((home=getenv("HOME"))!=NULL) {
    if ((homedir=(char *)memalloc(strlen(home)+1))==NULL) exit(1);
    strcpy(homedir,home);
  } else {
    if ((homedir=(char *)memalloc(strlen(libdir)+1))==NULL) exit(1);
    strcpy(homedir,libdir);
  }

  if (addobjectroot()==NULL) exit(1);
  if (addsystem()==NULL) exit(1);

  newobj(getobject("system"));
  if ((sys=getobject("system"))==NULL) exit(1);
  inst=chkobjinst(sys,0);
  if (_putobj(sys,"lib_dir",inst,libdir)) exit(1);
  if (_putobj(sys,"home_dir",inst,homedir)) exit(1);
  if (_getobj(sys,"lib_dir",inst,&libdir)==-1) exit(1);
  if (_getobj(sys,"home_dir",inst,&homedir)==-1) exit(1);
  if (_getobj(sys,"name",inst,&systemname)==-1) exit(1);

  if (addshell()==NULL) exit(1);

  if (addgra()==NULL) exit(1);
  if (addgra2()==NULL) exit(1);
  if (addgra2null()==NULL) exit(1);
  if (addgra2file()==NULL) exit(1);
  if (addgra2prn()==NULL) exit(1);

  if (addgra2x11()==NULL) exit(1);

  if (addint()==NULL) exit(1);
  if (adddouble()==NULL) exit(1);
  if (addstring()==NULL) exit(1);
  if (addiarray()==NULL) exit(1);
  if (adddarray()==NULL) exit(1);
  if (addsarray()==NULL) exit(1);
  if (addmath()==NULL) exit(1);
  if (addfit()==NULL) exit(1);
  if (addprm()==NULL) exit(1);

  if (adddraw()==NULL) exit(1);
  if (addagrid()==NULL) exit(1);
  if (addaxis()==NULL) exit(1);
  if (addfile()==NULL) exit(1);
  if (addmerge()==NULL) exit(1);
  if (addlegend()==NULL) exit(1);
  if (addrectangle()==NULL) exit(1);
  if (addline()==NULL) exit(1);
  if (addcurve()==NULL) exit(1);
  if (addarc()==NULL) exit(1);
  if (addpolygon()==NULL) exit(1);
  if (addmark()==NULL) exit(1);
  if (addtext()==NULL) exit(1);

  if (addmenu()==NULL) exit(1);
  if (adddialog()==NULL) exit(1);

  loginshell=NULL;
  if ((fp=openconfig(SYSCONF))!=NULL) {
     while ((tok=getconfig(fp,&str))!=NULL) {
      s2=str;
      if (strcmp(tok,"login_shell")==0) {
        f1=getitok2(&s2,&len," \t,");
        if (_putobj(sys,"login_shell",inst,f1)) exit(1);
      } else if (strcmp(tok,"create_object")==0) {
        while ((f1=getitok2(&s2,&len," \t,"))!=NULL) {
          newobj(getobject(f1));
          memfree(f1);
        }
      } else if (strcmp(tok,"alloc_console")==0) {
        f1=getitok2(&s2,&len," \t,");
        val=strtol(f1,&endptr,10);
        if (endptr[0]=='\0') {
          if (val==0) allocconsole=FALSE;
          else allocconsole=TRUE;
        }
        memfree(f1);
      } else if (strcmp(tok,"console_size")==0) {
        f1=getitok2(&s2,&len," \x09,");
        val=strtol(f1,&endptr,10);
        if (endptr[0]=='\0') consolecol=val;
        memfree(f1);
        f1=getitok2(&s2,&len," \x09,");
        val=strtol(f1,&endptr,10);
        if (endptr[0]=='\0') consolerow=val;
        memfree(f1);
      } else if (strcmp(tok,"terminal")==0) {
        terminal=getitok2(&s2,&len,"");
      }
      memfree(tok);
      memfree(str);
    }
    closeconfig(fp);
  }

  putstderr=putconsole;
  printfstderr=printfconsole;
  inputyn=inputynconsole;
  ndisplaydialog=displaydialogconsole;
  ndisplaystatus=displaystatusconsole;
  if (allocconsole) nallocconsole();
  if (isatty(0) && isatty(1) && isatty(2)) {
    consoleac=TRUE;
    if (!allocconsole) {
      consolefdin=dup(0);
      consolefdout=dup(2);
    }
  } else consoleac=FALSE;

  inifile=NULL;
  id=newobj((obj=getobject("shell")));
  for (i=1;i<argc;i++) {
    if (argv[i][0]=='-') {
      if (argv[i][1]=='i') {
        i++;
        if (i<argc) {
          if ((inifile=(char *)memalloc(strlen(argv[i])+1))==NULL) exit(1);
          strcpy(inifile,argv[i]);
          changefilename(inifile);
        } else break;
      } else break;
    } else break;
  }
  if (inifile==NULL) {
    if (findfilename(homedir,CONFTOP,systemname))
      inifile=getfilename(homedir,CONFTOP,systemname);
    else if (findfilename(libdir,CONFTOP,systemname))
      inifile=getfilename(libdir,CONFTOP,systemname);
  }
  if (inifile!=NULL) {
    arrayinit(&sarray,sizeof(char *));
    if (arrayadd(&sarray,&inifile)==NULL) exit(1);
    for (;i<argc;i++)
      if (arrayadd(&sarray,&(argv[i]))==NULL) exit(1);
    sarg[0]=(char *)&sarray;
    sarg[1]=NULL;
    exeobj(obj,"shell",id,1,sarg);
    arraydel(&sarray);
    memfree(inifile);
  }
  if (getobj(sys,"login_shell",0,0,NULL,&loginshell)) exit(1);
  do {
    if (_putobj(sys,"login_shell",inst,NULL)) exit(1);
    if (loginshell==NULL) {
      allocnow=nallocconsole();
      exeobj(obj,"shell",id,0,NULL);
      if (allocnow) nfreeconsole();
    } else {
      arrayinit(&iarray,sizeof(int));
      arg=loginshell;
      if (getobjilist2(&arg,&lobj,&iarray,TRUE)) return -1;
      arraydel(&iarray);
      if (lobj==obj) allocnow=nallocconsole();
      else allocnow=FALSE;
      sexeobj(loginshell);
      if (allocnow) nfreeconsole();
    }
    memfree(loginshell);
    if (getobj(sys,"login_shell",0,0,NULL,&loginshell)) exit(1);
  } while (loginshell!=NULL);
  if (consoleac && (consolepid!=-1)) nfreeconsole();
  memfree(terminal);
  delobj(getobject("system"),0);
  return 0;
}
