/*
**	Dxf2WABL: Converts a DXF (with 3DFace statements) into a WABL file.
**		  Multiple colors give multiple sectors of the same alien.
**		  No relative origin calc: do it in editWABLAlien.
*/

#include <wabl.h>
#include <exec/exec.h>
#include <exec/libraries.h>
#include <dos/dos.h>
#include <utility/tagitem.h>
#include <utility/hooks.h>
#include <inline/dos.h>
#include <inline/exec.h>
#include <exec/lists.h>

extern struct ExecBase *SysBase;
extern struct Library *DOSBase;

#define ARG_DXFINPUT	0
#define	ARG_WABLOUTPUT	1
#define	ARG_NOCOLORS	2
#define ARG_QUIET	3
#define ARG_VERBOSE	4

#define DOING_WAITFACE	50
#define DOING_FNDFACE	51
#define	DOING_VALUEXA	0
#define	DOING_VALUEXB	1
#define	DOING_VALUEXC	2
#define	DOING_VALUEXD	3
#define	DOING_VALUEYA	4
#define	DOING_VALUEYB	5
#define	DOING_VALUEYC	6
#define	DOING_VALUEYD	7
#define	DOING_VALUEZA	8
#define	DOING_VALUEZB	9
#define	DOING_VALUEZC	10
#define	DOING_VALUEZD	11
#define DOING_VALUECOLOR 12
#define DOING_VALUENULL	99

struct DXFGlobal
{
 struct MinList dxg_objs;
};

struct DXFObj
{
 struct MinNode	dxo_node;
 struct MinList dxo_faces;
 struct MinList dxo_edges;
 struct MinList dxo_points;
 UWORD		dxo_color;
};

struct INTEREdge
{
 struct MinNode ie_node;
 struct DXFPoint *ie_pa;
 struct DXFPoint *ie_pb; 
 UWORD		ie_id;
};

struct INTERFace
{
 struct MinNode	if_node;
 struct DXFPoint *if_pa;
 struct DXFPoint *if_pb;
 struct DXFPoint *if_pc;
 struct INTEREdge *if_ea;
 struct INTEREdge *if_eb;
 struct INTEREdge *if_ec;
 UWORD		if_id; 
};

struct DXFPoint
{
 struct MinNode dxp_node;
 int		dxp_x;
 int		dxp_y;
 int		dxp_z;
 UWORD		dxp_id;
};

static const char Intro[]={"\nDxf2Wabl 1.7\n\0"};
static const char Loading[]={"\nLoadind DXF file.\0"};
static const char NewObj[]={"\nFound new object (color).\0"};
static const char Converting[]={"\nConverting formats.\0"};
static const char CreatePnts[]={"\nCreating points.\0"};
static const char CreateFaces[]={"\nCreating faces.\0"};
static const char CreateEdges[]={"\nCreating edges.\0"};
static const char Saving[]={"\nSaving WABL file.\0"};
static const char Bye[]={"\nEnjoy WILD using !!\n\n\0"};
static const char FndFace[]={"\nFac \0"};
static const char TDFACE[]={"3DFACE\n\0"};
static const char FndXA[]={"XA:\0"};
static const char FndXB[]={"XB:\0"};
static const char FndXC[]={"XC:\0"};
static const char FndXD[]={"XD:\0"};
static const char FndYA[]={"YA:\0"};
static const char FndYB[]={"YB:\0"};
static const char FndYC[]={"YC:\0"};
static const char FndYD[]={"YD:\0"};
static const char FndZA[]={"ZA:\0"};
static const char FndZB[]={"ZB:\0"};
static const char FndZC[]={"ZC:\0"};
static const char FndZD[]={"ZD:\0"};
static const char FndCL[]={"C:\0"};
static const char NumFmt[]={'%','l','d',9,0};
static const char AlienType[]={"Alien\0"};
static const char AlienName[]={"Unnamed\0"};
static const char SectorType[]={"Sector\0"};
             char SectorName[7]={'S','e','c','X','X','X',0};
static const char ShellType[]={"Shell\0"};
             char ShellName[7]={'S','h','e','X','X','X',0};
static const char WireType[]={"Wire\0"};
             char WireName[7]={'W','i','r','X','X','X',0};
static const char NebulaType[]={"Nebula\0"};
             char NebulaName[7]={'N','e','b','X','X','X',0};
static const char FaceType[]={"Face\0"};
             char FaceName[8]={'F','a','c','X','X','X','X',0};
static const char EdgeType[]={"Edge\0"};
             char EdgeName[8]={'E','d','g','X','X','X','X',0};
static const char PointType[]={"Point\0"};
             char PointName[8]={'D','o','t','X','X','X','X',0};
static const char PointX[]={"X\0"};
static const char PointY[]={"Y\0"};
static const char PointZ[]={"Z\0"};
static const char FacePA[]={"PA\0"};
static const char FacePB[]={"PB\0"};
static const char FacePC[]={"PC\0"};
static const char FaceEA[]={"EA\0"};
static const char FaceEB[]={"EB\0"};
static const char FaceEC[]={"EC\0"};
#define EdgePA FacePA
#define EdgePB FacePB

ULONG 	*outfh=NULL,arg[6];
struct WABL *wabl=NULL;

void SayV(char *str)
{
 if (arg[ARG_VERBOSE])
  {
   FPuts(outfh,str);
  }
}

void Say(char *str)
{
 if (arg[ARG_QUIET]==0)
  {
   FPuts(outfh,str);
  }
}

ULONG WriteHook( register struct Hook* hook __asm("a0"), register ULONG object __asm("a2"), register ULONG message __asm("a1"))
{
 return(FPutC(object,message));
}

ULONG RawDoFmtOut( register ULONG car __asm("d0"), register ULONG output __asm("a3") )
{
 FPutC(output,car);
}

struct DXFObj *AddDXFObj(struct DXFGlobal *dxf,UWORD col)
{
 struct DXFObj *cob,*nob;
 cob=dxf->dxg_objs.mlh_Head;
 while (nob=cob->dxo_node.mln_Succ)
  {
   if (cob->dxo_color==col) return(cob);
   cob=nob;
  }
 cob=AllocPooled(wabl->WABL_Pool,sizeof(struct DXFObj));
 cob->dxo_color=col;
 Say(NewObj);
 NewList(&cob->dxo_faces);
 NewList(&cob->dxo_edges);
 NewList(&cob->dxo_points);
 AddTail(&dxf->dxg_objs,&cob->dxo_node);
 return(cob);
}

void Val(int num,char *str)
{
 int a;
 if ((a=LongToStr(num,str,-1))>0)
  {
   str[a]=0;
  }
 else
  {
   str[0]=0;
  }
}

struct INTERFace *AddINTERFace(struct DXFObj *obj,struct DXFPoint *pa,struct DXFPoint *pb,struct DXFPoint *pc,struct INTEREdge *ea,struct INTEREdge *eb,struct INTEREdge *ec)
{
 if ((pa==pb) | (pa==pc) | (pb==pc)) return(0L);
 {
  struct INTERFace *cif,*nif;
  cif=obj->dxo_faces.mlh_Head;
  while (nif=cif->if_node.mln_Succ)
   {
    if (((cif->if_pa==pa) & (cif->if_pb==pb) & (cif->if_pc==pc))|
        ((cif->if_pa==pa) & (cif->if_pb==pc) & (cif->if_pc==pb))|
        ((cif->if_pa==pb) & (cif->if_pb==pa) & (cif->if_pc==pc))|
        ((cif->if_pa==pb) & (cif->if_pb==pc) & (cif->if_pc==pa))|
        ((cif->if_pa==pc) & (cif->if_pb==pa) & (cif->if_pc==pb))|
        ((cif->if_pa==pc) & (cif->if_pb==pb) & (cif->if_pc==pa))) return(0L);
    cif=nif;
   }
  cif=AllocPooled(wabl->WABL_Pool,sizeof(struct INTERFace));
  cif->if_pa=pa;
  cif->if_pb=pb;
  cif->if_pc=pc;
  cif->if_ea=ea;
  cif->if_eb=eb;
  cif->if_ec=ec;
  AddTail(&obj->dxo_faces,&cif->if_node);
  return (cif);
 }
}

struct INTEREdge *AddINTEREdge(struct DXFObj *obj,struct DXFPoint *pa,struct DXFPoint *pb)
{
 struct INTEREdge *cie,*nie;
 if (pa==pb) return(0L);
 cie=obj->dxo_edges.mlh_Head;
 while (nie=cie->ie_node.mln_Succ)
  {
   if (((cie->ie_pa==pa) & (cie->ie_pb==pb))|
       ((cie->ie_pa==pb) & (cie->ie_pb==pa))) return(cie);
   cie=nie;
  }
 cie=AllocPooled(wabl->WABL_Pool,sizeof(struct INTEREdge));
 cie->ie_pa=pa;
 cie->ie_pb=pb;
 cie->ie_id=NULL;
 AddTail(&obj->dxo_edges,&cie->ie_node);
 return (cie);
}

struct DXFPoint *AddDXFPoint(struct DXFObj *obj,int x,int y,int z)
{
 struct DXFPoint *cpo,*npo;
 cpo=obj->dxo_points.mlh_Head;
 while (npo=cpo->dxp_node.mln_Succ)
  {
   if ((cpo->dxp_x==x) & (cpo->dxp_y==y) & (cpo->dxp_z==z)) return(cpo);
   cpo=npo;
  }
 cpo=AllocPooled(wabl->WABL_Pool,sizeof(struct DXFPoint));
 cpo->dxp_x=x;
 cpo->dxp_y=y;
 cpo->dxp_z=z;
 AddTail(&obj->dxo_points,&cpo->dxp_node);
 return(cpo);
}

int main()
{
 ULONG *rda;
 outfh=Output();
 Say(Intro);
 if (rda=ReadArgs("DXFIN/A,WABLOUT/A,NOCOLORS/S,QUIET/S,VERBOSE/S",&arg,0))
  {
   ULONG *fh;
   if (fh=Open(arg[ARG_DXFINPUT],MODE_OLDFILE))
    {
     struct Hook puthook;
     if (wabl=NewWABL())
      {
       char *use;
       struct DXFGlobal dxf;
       NewList(&dxf.dxg_objs);
       Say(Loading);
       if (use=AllocPooled(wabl->WABL_Pool,16384))
        {
         int   xa,xb,xc,xd,ya,yb,yc,yd,za,zb,zc,zd;
         UWORD col;
         UBYTE doing=DOING_WAITFACE;
         while (FGets(fh,use,16384))
          {
	   if (doing==DOING_WAITFACE)
	    {
	     if (StrCmp(use,&TDFACE))
              {
               doing=DOING_FNDFACE;
               SayV(FndFace);
	       col=1;
	      }
            }
	   else
	    {
	     if (doing==DOING_FNDFACE)
	      {ULONG num;
	       if ((StrToLong(use,&num))>0) 
	        {
	         switch (num)
	          {
	           case 10: {doing=DOING_VALUEXA;SayV(FndXA);break;}
	           case 11: {doing=DOING_VALUEXB;SayV(FndXB);break;}
	           case 12: {doing=DOING_VALUEXC;SayV(FndXC);break;}
	           case 13: {doing=DOING_VALUEXD;SayV(FndXD);break;}
	           case 20: {doing=DOING_VALUEYA;SayV(FndYA);break;}
	           case 21: {doing=DOING_VALUEYB;SayV(FndYB);break;}
	           case 22: {doing=DOING_VALUEYC;SayV(FndYC);break;}
	           case 23: {doing=DOING_VALUEYD;SayV(FndYD);break;}
	           case 30: {doing=DOING_VALUEZA;SayV(FndZA);break;}
	           case 31: {doing=DOING_VALUEZB;SayV(FndZB);break;}
	           case 32: {doing=DOING_VALUEZC;SayV(FndZC);break;}
	           case 33: {doing=DOING_VALUEZD;SayV(FndZD);break;}
	           case 62: {doing=DOING_VALUECOLOR;SayV(FndCL);break;}
	           case 0:  {
	            	     struct DXFObj *obj;
	            	     struct DXFPoint *pa,*pb,*pc,*pd;
	            	     struct INTEREdge *eab,*ebc,*eca,*edc,*ead;
	            	     struct INTERFace *faca,*facb;
	                     obj=AddDXFObj(&dxf,col);
	            	     pa=AddDXFPoint(obj,xa,ya,za);
	            	     pb=AddDXFPoint(obj,xb,yb,zb);
	            	     pc=AddDXFPoint(obj,xc,yc,zc);
	            	     pd=AddDXFPoint(obj,xd,yd,zd);
	            	     eab=AddINTEREdge(obj,pa,pb);
	            	     ebc=AddINTEREdge(obj,pb,pc);
	            	     eca=AddINTEREdge(obj,pc,pa);
	            	     edc=AddINTEREdge(obj,pd,pc);
	            	     ead=AddINTEREdge(obj,pa,pd);	            	     
	            	     faca=AddINTERFace(obj,pa,pb,pc,eab,ebc,eca);
	            	     facb=AddINTERFace(obj,pa,pc,pd,eca,ead,edc);	            	           	     
	                     doing=DOING_WAITFACE;
	                     break;
	                    }
	           default: {doing=DOING_VALUENULL;break;}
	          }
	        }
              } // DOINGFOUNDFACE
             else
              {ULONG num;
               if ((StrToLong(use,&num))>0)
                {
		 if ((doing!=DOING_VALUENULL) & (arg[ARG_VERBOSE]!=0)) RawDoFmt(NumFmt,&num,&RawDoFmtOut,outfh);
		 switch (doing)
		  {
		   case DOING_VALUEXA: {xa=num;break;}
		   case DOING_VALUEYA: {ya=num;break;}
		   case DOING_VALUEZA: {za=num;break;}
		   case DOING_VALUEXB: {xb=num;break;}
		   case DOING_VALUEYB: {yb=num;break;}
		   case DOING_VALUEZB: {zb=num;break;}
		   case DOING_VALUEXC: {xc=num;break;}
		   case DOING_VALUEYC: {yc=num;break;}
		   case DOING_VALUEZC: {zc=num;break;}
		   case DOING_VALUEXD: {xd=num;break;}
		   case DOING_VALUEYD: {yd=num;break;}
		   case DOING_VALUEZD: {zd=num;break;}
		   case DOING_VALUECOLOR: {if (arg[ARG_NOCOLORS]==0) col=num;}
		  }
                }
               doing=DOING_FNDFACE;
              } // VALUEHAVE
	    }
          } // INPUT PART
          Close(fh);
          
          {
           struct WABLObject *alien,*sector,*shell,*wire,*nebula,*point,*face,*edge;
           ULONG idsector=NULL,idshell=NULL,idwire=NULL,idnebula=NULL,
           	 idpoint=NULL,idedge=NULL,idface=NULL;
           Say(Converting);
           if (alien=HaveWABLObject(wabl,&AlienType,&AlienName,wabl))
            {
             struct DXFObj *cob,*nob;
             cob=dxf.dxg_objs.mlh_Head;
             
             while (nob=cob->dxo_node.mln_Succ)
              {
               idsector++;LongToHexStr(idsector,&SectorName[3],3);
               if (sector=HaveWABLObject(wabl,&SectorType,&SectorName,alien))
                {
                 struct DXFPoint *cpo,*npo;		                                  
		 idnebula++;LongToHexStr(idnebula,&NebulaName[3],3);
		 if (nebula=HaveWABLObject(wabl,&NebulaType,&NebulaName,sector))
		  {
		   Say(CreatePnts);
		   cpo=cob->dxo_points.mlh_Head;
		   while (npo=cpo->dxp_node.mln_Succ)
		    {
		     idpoint++;cpo->dxp_id=idpoint;
		    
#define	NamePoint(pnt) LongToHexStr(pnt->dxp_id,&PointName[3],4); 
		    
		     NamePoint(cpo);
		     if (point=HaveWABLObject(wabl,&PointType,&PointName,nebula))
		      {
		       Val(cpo->dxp_x,use);
  		       SetWABLAttr(wabl,&PointX,use,point);
		       Val(cpo->dxp_y,use);
  		       SetWABLAttr(wabl,&PointY,use,point);
		       Val(cpo->dxp_z,use);
  		       SetWABLAttr(wabl,&PointZ,use,point);
  		      } // POINT
		     cpo=npo;
		    } 
		  } // NEBULA

                 idwire++;LongToHexStr(idwire,&WireName[3],3);
		 if (wire=HaveWABLObject(wabl,&WireType,&WireName,sector))
		  {
		   struct INTEREdge *cie,*nie;
		   Say(CreateEdges);
		   cie=cob->dxo_edges.mlh_Head;
		   while (nie=cie->ie_node.mln_Succ)
		    {
		     idedge++;cie->ie_id=idedge;

#define	NameEdge(edg) LongToHexStr(edg->ie_id,&EdgeName[3],4); 

		     NameEdge(cie);
		     if (edge=HaveWABLObject(wabl,&EdgeType,&EdgeName,wire))
		      {
		       NamePoint(cie->ie_pa);
  		       SetWABLFriend(wabl,&EdgePA,&PointType,&PointName,edge);
		       NamePoint(cie->ie_pb);
  		       SetWABLFriend(wabl,&EdgePB,&PointType,&PointName,edge);
		      } // SAVEEDGE
		     cie=nie;
		    }
		  } // WIRE

		 idshell++;LongToHexStr(idshell,&ShellName[3],3);
		 if (shell=HaveWABLObject(wabl,&ShellType,&ShellName,sector))
		  {
		   struct INTERFace *cif,*nif;
		   Say(CreateFaces);
		   cif=cob->dxo_faces.mlh_Head;
		   while (nif=cif->if_node.mln_Succ)
		    {
		     idface++;cif->if_id=idface;
		     
#define	NameFace(fac) LongToHexStr(fac->if_id,&FaceName[3],4); 
		     
		     NameFace(cif);
		     if (face=HaveWABLObject(wabl,&FaceType,&FaceName,shell))
		      {
		       NamePoint(cif->if_pa);
  		       SetWABLFriend(wabl,&FacePA,&PointType,&PointName,face);
		       NamePoint(cif->if_pb);
  		       SetWABLFriend(wabl,&FacePB,&PointType,&PointName,face);
		       NamePoint(cif->if_pc);
  		       SetWABLFriend(wabl,&FacePC,&PointType,&PointName,face);
		       NameEdge(cif->if_ea);
  		       SetWABLFriend(wabl,&FaceEA,&EdgeType,&EdgeName,face);
		       NameEdge(cif->if_eb);
  		       SetWABLFriend(wabl,&FaceEB,&EdgeType,&EdgeName,face);
		       NameEdge(cif->if_ec);
  		       SetWABLFriend(wabl,&FaceEC,&EdgeType,&EdgeName,face);
		      } // SAVEFACE
		     cif=nif;
		    } // SAVEFACES
		   
		  } // SHELL
                } // SECTOR
               cob=nob;
              } // SECTORS 
            } // ALIEN 
	  } // ELABORATION PART        

	  {
	   if (fh=Open(arg[ARG_WABLOUTPUT],MODE_NEWFILE))
	    {
	     struct Hook puthook;
             struct TagItem savetags[3]={{WABL_FileHandle,fh},{WABL_PutCharHook,&puthook},{0,0}};
	     Say(Saving);
             puthook.h_Entry=&WriteHook;
             SaveWABL(wabl,&savetags[0]);             
             Close(fh);
    	     Say(Bye);
	    } // OUTHAD 
	  } // SAVEPART
        } // USE
       FreeWABL(wabl);
      } // WABL
    } // DXFOPEN
  } // READARGS
}

