/*
**	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_ifaces;
 struct MinList dxo_iedges;
 struct MinList dxo_points;
 UWORD		dxo_color;
};

struct DXFFace
{
 struct MinNode	dxf_node;
 struct DXFPoint *dxf_pa;
 struct DXFPoint *dxf_pb;
 struct DXFPoint *dxf_pc;
 struct DXFPoint *dxf_pd;
 UWORD		dxf_id;
 UWORD		dxf_color;
};

struct INTERFace
{
 struct MinNode	if_node;
 struct DXFPoint *if_pa;
 struct DXFPoint *if_pb;
 struct DXFPoint *if_pc;
 UWORD		if_id; 
};

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

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

static const char Intro[]={"\nDxf2Wabl 1.5\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 DoublePnts[]={"\nPacking double points.\0"};
static const char CreatePnts[]={"\nCreating points.\0"};
static const char DoubleFaces[]={"\nPacking and splitting faces (4 edges to 3).\0"};
static const char CreateFaces[]={"\nCreating faces and packing edges.\0"};
static const char AddEdges[]={"\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 RemapPoint[]={"\nRemap point : xxxx into xxxx \0"};
#define	RMP_IT	15
#define RMP_INTO 25
static const char OriginalFace[]={"\nOriginal DXF face points : xxxx xxxx xxxx xxxx \0"};
#define ORF_PA 28
#define ORF_PB 33
#define ORF_PC 38
#define ORF_PD 43
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;

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 *HaveObjFromColor(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_ifaces);
 NewList(cob->dxo_iedges);
 NewList(cob->dxo_points);
 AddTail(&dxf->dxg_objs,&cob->dxo_node);
}

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

ULONG *HaveRemapPoint(struct DXFPoint *pnt)
{
 if (pnt->dxp_remap)
  {
   return(HaveRemapPoint(pnt->dxp_remap));
  }
 else
  {
   return(pnt);
  }
}

ULONG *AddINTERFace(struct DXFObj *obj,struct DXFPoint *pa,struct DXFPoint *pb,struct DXFPoint *pc)
{
 if ((pa==pb) | (pa==pc) | (pb==pc)) return(0L);
 {
  struct INTERFace *cif,*nif;
  cif=obj->dxo_ifaces.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;
  AddTail(&obj->dxo_ifaces,&cif->if_node);
  return (cif);
 }
}

ULONG *AddINTEREdge(struct DXFObj *obj,struct DXFPoint *pa,struct DXFPoint *pb)
{
 struct INTEREdge *cie,*nie;
 if (pa==pb) return(0L);
 cie=obj->dxo_iedges.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_iedges,&cie->ie_node);
 return (cie);
}

ULONG *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);
}

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

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

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;
       struct DXFFace	*face;
       struct DXFPoint	*pa,*pb,*pc,*pd;
       NewList(dxf.dxg_objs);
       Say(Loading);
       if (use=AllocPooled(wabl->WABL_Pool,16384))
        {
         UBYTE doing=DOING_WAITFACE;
         ULONG idface=NULL,idedge=NULL,idpoint=NULL;
         while (FGets(fh,use,16384))
          {
	   if (doing==DOING_WAITFACE)
	    {
	     if (StrCmp(use,&TDFACE))
              {
               doing=DOING_FNDFACE;
               SayV(FndFace);
	       face=AllocPooled(wabl->WABL_Pool,sizeof(struct DXFFace));
               face->dxf_pa=(pa=AllocPooled(wabl->WABL_Pool,sizeof(struct DXFPoint)));
               face->dxf_pb=(pb=AllocPooled(wabl->WABL_Pool,sizeof(struct DXFPoint)));
               face->dxf_pc=(pc=AllocPooled(wabl->WABL_Pool,sizeof(struct DXFPoint)));
               face->dxf_pd=(pd=AllocPooled(wabl->WABL_Pool,sizeof(struct DXFPoint)));
               if (arg[ARG_NOCOLORS]!=0)
                {
		 struct DXFObj *obj;
		 obj=HaveObjFromColor(&dxf,1);
		 AddTail(&obj->dxo_faces,&face->dxf_node);
		 AddTail(&obj->dxo_points,&pa->dxp_node);
		 AddTail(&obj->dxo_points,&pb->dxp_node);
		 AddTail(&obj->dxo_points,&pc->dxp_node);
		 AddTail(&obj->dxo_points,&pd->dxp_node);
	        }
	      }
            }
	   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:  {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: {pa->dxp_x=num;break;}
		   case DOING_VALUEYA: {pa->dxp_y=num;break;}
		   case DOING_VALUEZA: {pa->dxp_z=num;break;}
		   case DOING_VALUEXB: {pb->dxp_x=num;break;}
		   case DOING_VALUEYB: {pb->dxp_y=num;break;}
		   case DOING_VALUEZB: {pb->dxp_z=num;break;}
		   case DOING_VALUEXC: {pc->dxp_x=num;break;}
		   case DOING_VALUEYC: {pc->dxp_y=num;break;}
		   case DOING_VALUEZC: {pc->dxp_z=num;break;}
		   case DOING_VALUEXD: {pd->dxp_x=num;break;}
		   case DOING_VALUEYD: {pd->dxp_y=num;break;}
		   case DOING_VALUEZD: {pd->dxp_z=num;break;}
		   case DOING_VALUECOLOR: 
		    {
		     if (arg[ARG_NOCOLORS]==0) 
		      {
		       struct DXFObj *obj;
		       obj=HaveObjFromColor(&dxf,num);
		       AddTail(&obj->dxo_faces,&face->dxf_node);
		       AddTail(&obj->dxo_points,&pa->dxp_node);
		       AddTail(&obj->dxo_points,&pb->dxp_node);
		       AddTail(&obj->dxo_points,&pc->dxp_node);
		       AddTail(&obj->dxo_points,&pd->dxp_node);
		      }
		    }
		  }
                }
               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))
                {		                                  
		 idnebula++;LongToHexStr(idnebula,&NebulaName[3],3);
		 if (nebula=HaveWABLObject(wabl,&NebulaType,&NebulaName,sector))
		  {
		   struct DXFPoint *cpo,*npo;
		   ULONG fakeida=NULL,fakeidb=NULL;		// to see remaps
		   Say(DoublePnts);
		   cpo=cob->dxo_points.mlh_Head;
		   fakeida++;fakeidb=fakeida;
		   while (npo=cpo->dxp_node.mln_Succ)
		    {
		     struct DXFPoint *icpo,*inpo;
		     fakeidb++;
  		     cpo->dxp_remap=NULL;
		     icpo=npo;
		     while (inpo=icpo->dxp_node.mln_Succ)
		      {
		       if ((cpo->dxp_x==icpo->dxp_x) & (cpo->dxp_y==icpo->dxp_y) & (cpo->dxp_z==icpo->dxp_z))
		        {
		         Remove(&cpo->dxp_node);
		         cpo->dxp_remap=icpo;
		         LongToHexStr(fakeida,&RemapPoint[RMP_IT],4);
		         LongToHexStr(fakeidb,&RemapPoint[RMP_INTO],4);
		         SayV(RemapPoint);
		        }
		       icpo=inpo;
		      } // INTERNALCYCLE
		     cpo=npo;
		    } // POINTDOUBLECHECK

		   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

		 idshell++;LongToHexStr(idshell,&ShellName[3],3);
		 if (shell=HaveWABLObject(wabl,&ShellType,&ShellName,sector))
		  {
		   struct DXFFace *cfa,*nfa;
		   struct INTERFace *cif,*nif;
		   Say(DoubleFaces);
		   cfa=cob->dxo_faces.mlh_Head;
		   while (nfa=cfa->dxf_node.mln_Succ)
		    {
  		     cfa->dxf_pa=HaveRemapPoint(cfa->dxf_pa);
  		     cfa->dxf_pb=HaveRemapPoint(cfa->dxf_pb);
  		     cfa->dxf_pc=HaveRemapPoint(cfa->dxf_pc);
  		     cfa->dxf_pd=HaveRemapPoint(cfa->dxf_pd);

		     LongToHexStr(cfa->dxf_pa->dxp_id,&OriginalFace[ORF_PA],4);
		     LongToHexStr(cfa->dxf_pb->dxp_id,&OriginalFace[ORF_PB],4);
		     LongToHexStr(cfa->dxf_pc->dxp_id,&OriginalFace[ORF_PC],4);
		     LongToHexStr(cfa->dxf_pd->dxp_id,&OriginalFace[ORF_PD],4);
		     SayV(OriginalFace);		     

		     if (cif=AddINTERFace(cob,cfa->dxf_pa,cfa->dxf_pb,cfa->dxf_pc)) {idface++;cif->if_id=idface;}
		     if (cif=AddINTERFace(cob,cfa->dxf_pa,cfa->dxf_pc,cfa->dxf_pd)) {idface++;cif->if_id=idface;}

		     cfa=nfa;
		    } // FACEINTECONV
		   cif=cob->dxo_ifaces.mlh_Head;
		   Say(CreateFaces);
		   while (nif=cif->if_node.mln_Succ)
		    {
		     struct INTEREdge *edga,*edgb,*edgc;
		     if ((edga=AddINTEREdge(cob,cif->if_pa,cif->if_pb))->ie_id==0) {idedge++;edga->ie_id=idedge;}
		     if ((edgb=AddINTEREdge(cob,cif->if_pa,cif->if_pb))->ie_id==0) {idedge++;edgb->ie_id=idedge;}
		     if ((edgc=AddINTEREdge(cob,cif->if_pa,cif->if_pb))->ie_id==0) {idedge++;edgc->ie_id=idedge;}

#define	NameFace(fac) LongToHexStr(fac->if_id,&FaceName[3],4); 
#define	NameEdge(edg) LongToHexStr(edg->ie_id,&EdgeName[3],4); 
		     
		     NameFace(cif);
		     if (face=HaveWABLObject(wabl,&FaceType,&FaceName,shell))
		      {
		       NamePoint(cif->if_pa);
  		       SetWABLAttr(wabl,&FacePA,&PointName,face);
		       NamePoint(cif->if_pb);
  		       SetWABLAttr(wabl,&FacePB,&PointName,face);
		       NamePoint(cif->if_pc);
  		       SetWABLAttr(wabl,&FacePC,&PointName,face);		      
		       NameEdge(edga);
  		       SetWABLAttr(wabl,&FaceEA,&EdgeName,face);
		       NameEdge(edgb);
  		       SetWABLAttr(wabl,&FaceEB,&EdgeName,face);
		       NameEdge(edgc);
  		       SetWABLAttr(wabl,&FaceEC,&EdgeName,face);		       
		      } // SAVEFACE
		     cif=nif;
		    } // SAVEFACES
		   
		  } // SHELL
		  
                 idwire++;LongToHexStr(idwire,&WireName[3],3);
		 if (wire=HaveWABLObject(wabl,&WireType,&WireName,sector))
		  {
		   struct INTEREdge *cie,*nie;
		   Say(AddEdges);
		   cie=cob->dxo_iedges.mlh_Head;
		   while (nie=cie->ie_node.mln_Succ)
		    {
		     NameEdge(cie);
		     if (edge=HaveWABLObject(wabl,&EdgeType,&EdgeName,wire))
		      {
		       NamePoint(cie->ie_pa);
  		       SetWABLAttr(wabl,&EdgePA,&PointName,edge);
		       NamePoint(cie->ie_pb);
  		       SetWABLAttr(wabl,&EdgePB,&PointName,edge);
		      } // SAVEEDGE
		     cie=nie;
		    }
		  } // WIRE
                } // 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
}

