/****************************************************************************
    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 Tue Dec  2 12:32:44 2003
****************************************************************************/
#include "tkgate.h"

#define MUX_IN 0
#define MUX_SEL 1
#define MUX_OUT 2

#define F_IN 0x1

void Mux_Delete(GCElement *g,GModuleDef *env,int drawp);
void Mux_Draw(GCElement *g,int md);
GCElement *Mux_Make(EditState **es,GModuleDef *env,int GType,
		    int x,int y,int r,const char *Name,int noWires,const char**,int);
void Mux_PSWrite(FILE *f,GModLayout*,GCElement *g);

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

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

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

struct locate mux_sel_loc[] = {
	{-23,0,-23,0,D_LEFT},
	{0,-23,0,-23,D_UP},
	{23,0,23,0,D_RIGHT},
	{0,23,0,23,D_DOWN}};

static char *psMux[] = {
  "%",
  "% x y r mux",
  "%",
  "/mux {",
  "    dup /mrot exch def",
  "    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",
  "    mrot -90 eq mrot -180 eq or {",
  "      3 -1 roll 1 sub 50 string cvs exch (0) exch	% d1 (n) (0) dn",
  "      -29 add 7 rCT				% d1",
  "      exch -29 add 7 rCT",
  "    } {",
  "      3 -1 roll 1 sub 50 string cvs exch	% d1 (n) dn",
  "      -29 add 7 rCT				% d1",
  "      (0) exch -29 add 7 rCT",
  "    } ifelse",
  "    grestore",
  "} def",
  0
};

GGateInfo gate_mux_info = {
  0,
  "MUX",
  "mux",0x0,
  "mux",psMux,

 { {"m",	{"gmmsi",0},		{"gm21mux",0,"mux",100},		"gat_make mux "},
   {"M 2",	{0,0},			{0,0,0,0},				"gat_make mux -pins I=2"},
   {"M 3",	{0,0},			{0,0,0,0},				"gat_make mux -pins I=3"},
   {"M 4",	{"gmmsi",0},		{"gm41mux",0,"mux",200},		"gat_make mux -pins I=4"},
   {"M 5",	{0,0},			{0,0,0,0},				"gat_make mux -pins I=5"},
   {"M 6",	{0,0},			{0,0,0,0},				"gat_make mux -pins I=6"},
   {"M 7",	{0,0},			{0,0,0,0},				"gat_make mux -pins I=7"},
   {"M 8",	{"gmmsi",0},		{"gm81mux",0,"mux",300},		"gat_make mux -pins I=8"},
   {"M 9",	{0,0},			{0,0,0,0},				"gat_make mux -pins I=9"},
   {0}},

  mux_iconDims,

  3,{{"I",IN,1,2,mux_in_loc,1},
       {"S",IN,1,1,mux_sel_loc,0},
       {"Z",OUT,1,1,mux_out_loc,0}},
  {{23,8,LJ},{0,40,CT},{-23,0,RJ},{0,-33,CT}},
  {1},
  
  {"S-Z","I-Z",0},

  Mux_Make,
  Generic_Init,
  Mux_Delete,
  Generic_GetExtents,
  Generic_HitDistance,
  Mux_Draw,
  Generic_Move,
  Generic_Replicate,
  Generic_AddInput,
  Err_AddOutput,
  Err_AddInOut,
  Err_ChangePin,
  Nop_SimStateFunc,
  Nop_SimHitFunc,
  Mux_PSWrite,
  Generic_EditProps,
  Generic_VerSave
};

GCElement *Mux_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[MUX_IN];w;w = w->next,i++);

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

  return g;
}

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

  if (!(w0 = g->wires[MUX_IN])) 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,
		   AtTop|BetweenLeftAndRight,"0");
    dce_DrawString(XGate.instGC,
		   w->nodes->x,w->nodes->y + 2,
		   AtTop|BetweenLeftAndRight,n);
    break;
  case 1 :
    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;
  case 2 :
    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 3:
    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;
  }
}

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

void Mux_Draw(GCElement *g,int md)
{
  Generic_Draw(g,md);
  Mux_Draw_Special(g);
}

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

    Generic_PSLabels(f,g);

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

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

void init_mux()
{
  Pixmap P;

  P = Pixmap_registerFromFile("mux","mux.b");
  gateinfo_iconInit(&gate_mux_info,P,mux_iconDims,mux_iconBoldOffset);
  RegisterGate(&gate_mux_info);
}
