*! Date    : 29 Sep 2004
*! Version : 1.06
*! Author  : Adrian Mander
*! Email   : adrian.p.mander@gsk.com

*! e.g.  gipf, m(l1*l2+l4*l8+l3+l2*l6*l7+l5)

prog def gipf
syntax , Model(string) [ NOlegend Gap(integer 0) Order(string) Nodelabel(string asis) Saving(passthru) LWidth(integer 1)]

preserve
clear

/*
  Parse the model syntax and get the unique varlist
  Then nloc holds the number of nodes in the dag
*/

local mod "`model'"
while "`model'"~="" {
  gettoken term model: model , parse("+*")
  if "`term'"~="*" & "`term'"~="+" local vlist "`vlist' `term'"
}
local vlist: list uniq vlist
local nloc : list sizeof vlist
local vlist: list sort vlist

if `"`nodelabel'"'~="" {
  local nolab:list sizeof nodelabel
  if `nloc'~=`nolab' {
    di as error "Number of labels (`nolab') does not equal number of nodes (`nloc')!"
    exit(198)
  }
}

/*
  if the user specifies the order then replace the vlist with a list that the user specifies
  NOTE: No check is made on whether the order is sensible or whether the variables exist...!
*/

if "`order'"~="" local vlist "`order'"

/* Just create dataset of size number of nodes */

local nloc `nloc'
qui set obs `nloc'

/*
 To create a gap the number of loci increases... hence gaps occur at the top of the plot
*/

local nloc_gap = `nloc'+`gap'
qui gen x = sin(_n*2*_pi/`nloc_gap')
qui gen y = cos(_n*2*_pi/`nloc_gap')


/*
 Generate the labels for the graph nodes.. either from vlist OR the order() option OR nodelabel option
 Put node names  in var name
 Put node labels in var nlab
*/

qui gen name = ""
qui gen nlab = ""

local  i 1
foreach nam of local vlist {
  qui replace name = "`nam'" in `i++'
}

if `"`nodelabel'"'~="" {
  local  i 1
  foreach nam of local nodelabel {
    qui replace nlab = "`nam'" in `i++'
  }
}
else qui replace nlab = name

/* Now create the text statement for the future graph Note it will use node labels if specified*/

forv i=1/`nloc' {
  if `"`nodelabel'"'=="" {
    local x = x[`i']*1.25
    local y = y[`i']*1.25
    local name = name[`i']
    local text `"`text' text(`y' `x' "`name'")"'
  }
  else {
    local x = x[`i']*1.3
    local y = y[`i']*1.3
    local name = nlab[`i']
    local text `"`text' text(`y' `x' "`name'")"'
  }
}


/* Now drawing lines between points -- initialise the nodes*/

local graphi 1
local legord ""
local leglab ""


local model "`mod'"
while "`model'"~="" {
  gettoken term model:model, parse("+")
  /* this gets the independence out now need to join up all these variables */
  local list ""
  while "`term'"~="" {
    gettoken l term:term, parse("*")
    if "`l'"~="*" {
      if "`list'"=="" local list "`l'"
      else local list "`list' `l'"
    }
  }
  local slist : list sizeof list
  _binary `slist'
  local temp "`r(bin)'"
  local size = (`slist'-1)*`lwidth'-(`lwidth'-1)

  if `slist'>3 local color "black" /* Might want maroon */
  else local color "black"
  if `slist'>3 local style "######_"
  else local style "solid"

  else local color "black"
  foreach blin of local temp {
    local first = index("`blin'","1")
    local blin = subinstr("`blin'","1","0",1)
    local sec = index("`blin'","1")
    local var1 : word `first' of `list'
    local var2 : word `sec' of `list'
    local graph `"`graph'(line y x if name=="`var1'" | name=="`var2'", clw(*`size') clc(`color') clp(`"`style'"')  graphregion(c(white)) ) || "'
    if "``color'`slist''"=="" {
      local legord "`legord' `graphi'"
      local leglab "`leglab' label(`graphi' "`slist'-way interaction")"
      local `color'`slist' "done"
    }
    local `graphi++'
  }
}


if "`nolegend'"=="" local legend "legend(order(`legord') `leglab')"
else local legend "legend(off)"

twoway `graph' scatter y x, msize(*5) m(O) mc(emidblue) `text' xscale(noline range(-1.4,1.4)) yscale(noline range(-1.4,1.4)) `legend' graphr(margin(l+13 r+13) fc(white)) xmtick(none, notick) ytick(none, nolab) xlab(none, nolab notick) ylab(none, nolab notick) xti(" ") yti(" ") `saving'

restore

end

prog def _binary, rclass
args n

local last = 2^`n'-1
forv nb =1/`last' {
  local bin ""
  local sum 0
  local ade `nb'
  forv j = 1/`n' {
   if mod(`nb',2)==1 {
     local bin "1`bin'"
     local `sum++'
   }
   else local bin "0`bin'"
   local nb = (`nb'-mod(`nb',2))/2
 }
if `sum'==2 local allbin "`allbin' `bin'"
}
return local bin "`allbin'"

end