/****************************************************************************
    Copyright (C) 1987-2005 by Jeffery P. Hansen

    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., 675 Mass Ave, Cambridge, MA 02139, USA.

    Last edit by hansen on Mon Dec  8 13:44:13 2003
****************************************************************************/
#include "tkgate.h"

#define DEMUX_IN 0
#define DEMUX_EN 1
#define DEMUX_OUT 2

#define F_IN 0x1

void Demux_Delete(GCElement *g,GModuleDef *env,int drawp);
void Demux_Draw(GCElement *g,int md);
GCElement *Demux_Make(EditState **es,GModuleDef *env,int GType,
		    int x,int y,int r,const char *Name,int noWires,const char**,int);
void Demux_PSWrite(FILE *f,GModLayout*,GCElement *g);

static iconDimensions demux_iconDims[] = {
  {29, 60, 59, 29, 30, 12},
  {0,  29, 29, 59, 12, 30},
  {0,  0,  59, 29, 30, 15},
  {60, 0,  29, 59, 15, 30},
};
static int demux_iconBoldOffset = 89;

struct locate demux_out_loc[] = {
	{-30,16,30,16,D_DOWN},
	{16,-30,16,30,D_RIGHT},
	{-30,-16,30,-16,D_UP},
	{-16,-30,-16,30,D_LEFT},
};

struct locate demux_in_loc[] = {
	{0,-13,0,-13,D_UP},
	{-13,0,-13,0,D_LEFT},
	{0,13,0,13,D_DOWN},
	{13,0,13,0,D_RIGHT},
};

struct locate demux_en_loc[] = {
	{-24,0,-24,0,D_LEFT},
	{0,-24,0,-24,D_UP},
	{22,0,22,0,D_RIGHT},
	{0,22,0,22,D_DOWN},
};

static char *psDemux[] = {
  "%",
  "% x y r demux",
  "%",
  "/demux {",
  "    180 sub neg 360 mod neg",
  "    startgate",
  "    8 rfont",
  "    -29.5 15.5 moveto",
  "    29.5 15.5 lineto",
  "    16.5 -12.5 lineto",
  "    -16.5 -12.5 lineto",
  "    closepath stroke",
  "    dup					% n n",
  "    1 add 58 exch div			% n d1",
  "    2 copy mul				% n d1 dn",
  "    3 -1 roll 1 sub 50 string cvs exch	% d1 (n) dn",
  "    -29 add 7 rCT				% d1",
  "    (0) exch -29 add 7 rCT",
  "    grestore",
  "} def",
  0
};

GGateInfo gate_demux_info = {
  0,
  "DEMUX",
  "demux",0x0,
  "demux",psDemux,

 { {"D 2",	{"gmmsi",0},		{"gm12dec",0,"xdemux",100},		"gat_make demux "},
   {"D 3",	{0,0},			{0,0,0,0},				"gat_make demux -pins Z=3"},
   {"D 4",	{"gmmsi",0},		{"gm14dec",0,"xdemux",200},		"gat_make demux -pins Z=4"},
   {"D 5",	{0,0},			{0,0,0,0},				"gat_make demux -pins Z=5"},
   {"D 6",	{0,0},			{0,0,0,0},				"gat_make demux -pins Z=6"},
   {"D 7",	{0,0},			{0,0,0,0},				"gat_make demux -pins Z=7"},
   {"D 8",	{"gmmsi",0},		{"gm18dec",0,"xdemux",300},		"gat_make demux -pins Z=8"},
   {"D 9",	{0,0},			{0,0,0,0},				"gat_make demux -pins Z=9"},
   {0}},

  demux_iconDims,

  3,{{"I",IN,1,1,demux_in_loc,0},
       {"E",IN,1,1,demux_en_loc,0},
       {"Z",OUT,1,2,demux_out_loc,1}},
  {{23,0,LJ},{0,40,CT},{-23,8,RJ},{0,-33,CT}},
  {1},
  
  {"E-Z","I-Z",0},

  Demux_Make,
  Generic_Init,
  Demux_Delete,
  Generic_GetExtents,
  Generic_HitDistance,
  Demux_Draw,
  Generic_Move,
  Generic_Replicate,
  Err_AddInput,
  Generic_AddOutput,
  Err_AddInOut,
  Err_ChangePin,
  Nop_SimStateFunc,
  Nop_SimHitFunc,
  Demux_PSWrite,
  Generic_EditProps,
  Generic_VerSave
};

GCElement *Demux_Make(EditState **es,GModuleDef *env,int GType,
		    int x,int y,int r,const char *Name,int noWires,const char **options,int nOptions)
{
  int i,nbits;
  struct celemnt *g;
  struct wire *w;

  if (!(g = Generic_Make(es,env,GType,x,y,r,Name,noWires,options,nOptions)))
    return NULL;

  if (!noWires) {
    for (i = 0,w = g->wires[DEMUX_OUT];w;w = w->next,i++);

    nbits = required_bits(i);
    net_setSize(g->wires[DEMUX_IN]->net,nbits);
  }

  return g;
}

void Demux_Draw_Special(GCElement *g)
{
  GWire *w,*w0;
  char n[STRMAX];
  int i;

  if (g->selected)
    XSetFont(XGate.D,XGate.instGC,XGate.textbXF);
  else
    XSetFont(XGate.D,XGate.instGC,XGate.textXF);

  dce_DrawString(XGate.instGC,g->xpos,g->ypos+4,AtBottom|BetweenLeftAndRight,"D");

  if (!(w0 = g->wires[DEMUX_OUT])) return;
  for (i = 0,w = w0;w->next;w = w->next,i++);
  sprintf(n,"%d",i);

  if (g->selected)
    XSetFont(XGate.D,XGate.instGC,XGate.stextbXF);
  else
    XSetFont(XGate.D,XGate.instGC,XGate.stextXF);

  switch (g->orient) {
  case 0 :
    dce_DrawString(XGate.instGC,
		   w0->nodes->x,w0->nodes->y - 2,
		   AtBottom|BetweenLeftAndRight,"0");
    dce_DrawString(XGate.instGC,
		   w->nodes->x,w->nodes->y - 2,
		   AtBottom|BetweenLeftAndRight,n);
    break;
  case 1 :
    dce_DrawString(XGate.instGC,
		   w0->nodes->x - 2,w0->nodes->y,
		   BetweenTopAndBottom|AtRight,"0");
    dce_DrawString(XGate.instGC,
		   w->nodes->x - 2,w->nodes->y,
		   BetweenTopAndBottom|AtRight,n);
    break;
  case 2 :
    dce_DrawString(XGate.instGC,
		   w0->nodes->x,w0->nodes->y + 2,
		   AtTop|BetweenLeftAndRight,"0");
    dce_DrawString(XGate.instGC,
		   w->nodes->x,w->nodes->y + 2,
		   AtTop|BetweenLeftAndRight,n);
    break;
  case 3:
    dce_DrawString(XGate.instGC,
		   w0->nodes->x + 3,w0->nodes->y,
		   BetweenTopAndBottom|AtLeft, "0");
    dce_DrawString(XGate.instGC,
		   w->nodes->x + 3,w->nodes->y,
		   BetweenTopAndBottom|AtLeft,n);
    break;
  }
}


void Demux_Delete(GCElement *g,GModuleDef *env,int drawp)
{
  Generic_Delete(g,env,drawp);
}

void Demux_Draw(GCElement *g,int md)
{
  Generic_Draw(g,md);
  Demux_Draw_Special(g);
}

void Demux_PSWrite(FILE *f,GModLayout *L,GCElement *g)
{
    int N;
    struct wire *w;

    Generic_PSLabels(f,g);

    for (N = 0, w = g->wires[DEMUX_OUT];w;w = w->next) N++;

    fprintf(f,"%d %d %d %d %s\n",
	N,g->xpos,g->ypos,-g->orient*90,g->typeinfo->psprint);
}

void init_demux()
{
  Pixmap P;

  P = Pixmap_find("mux");
  gateinfo_iconInit(&gate_demux_info,P,demux_iconDims,demux_iconBoldOffset);
  RegisterGate(&gate_demux_info);
}
