/*  File: pephomolcol.c
 *  Author: Clive Brown (cgb@sanger.ac.uk)
 *  Copyright (C) J Thierry-Mieg and R Durbin, 1995
 * -------------------------------------------------------------------
 * Acedb 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 * or see the on-line version at http://www.gnu.org/copyleft/gpl.txt
 * -------------------------------------------------------------------
 * This file is part of the ACEDB genome database package, written by
 * 	Richard Durbin (MRC LMB, UK) rd@sanger.ac.uk, and
 *	Jean Thierry-Mieg (CRBM du CNRS, France) mieg@kaa.cnrs-mop.fr
 *
 * SCCS: $Id: pephomolcol.c,v 1.36 2003/05/13 09:55:12 edgrif Exp $
 * Description:
 * Exported functions:
 * HISTORY:
 * Last edited: May 13 10:54 2003 (edgrif)
 *		-	MENU_FUNC_CAST instead of (GraphFunc) in belvuMenu[] MENUOPTS
 * * May 20 18:48 1996 (esr)
 * Created: Tue Nov  7 14:40:54 1995 (cgb)
 *-------------------------------------------------------------------
 */

#include <wh/pepdisp.h>
#include <wh/method.h>
#include <wh/matchtable.h>
#include <wh/call.h>
#include <wh/bump.h>
#include <wh/dbpath.h>
#include <wh/graph.h>
#include <wh/gex.h>
#include <wh/pref.h>
#include <wh/blxview.h>


Stack BelvuMatchStack ;

typedef struct homolColPriv {
  Array segs;
  int homolBox; /* to diff between homol of the same key */
  float x;
  BOOL bump;
  int width;
  } *HOMOLPRIV;

/*********** Configure code for the pep cols.. ****************/

struct configLocals{
  BOOL bump;
};

static BOOL homolConfigure(COLINSTANCE instance)
     
{
  HOMOLPRIV private = instance->private;
  struct configLocals *cf = (struct configLocals *) messalloc(sizeof(struct configLocals));
  float line = 2.0;

  if(controlCreateConfig(instance,cf,"Configure pepdisp name column",0.5,0.15)){
    /* initialise data */
    cf->bump = private->bump;

    graphToggleEditor("Bump",&cf->bump,4.0,line);
  
    graphRedraw();
  }
  return FALSE;

}

static void pepConfigFinal(COLINSTANCE instance, void *locals, BOOL ok){
  struct configLocals *cf = locals;
  HOMOLPRIV private = instance->private;

  if(ok){
    private->bump = cf->bump;
  }
  else
    messfree(cf);
}


/************************ homol columns ******************************/

typedef struct { 
  KEY key ;		/* subject, i.e. target for match */
  KEY meth ;		/* type of match, e.g. BLASTP - controls display etc. */
  float score ;
  int qstart ;		/* query start and end, i.e. in self */
  int qend ;
  int sstart ;		/* subject start and end */
  int send ;
} HOMOL ;

static int homolOrder (void *va, void *vb)
{
  HOMOL *a = (HOMOL*) va, *b = (HOMOL*) vb ;
  return ((a->qstart + a->qend)/2 > (b->qstart + b->qend)/2) ? 1 : -1 ;
}

extern void * homolConvert (MAPCONTROL map, void *params)
{ 
  OBJ obj ;
  Array flatA, homols ;
  HOMOL *homol ;
  int i ;
 
  homols = arrayHandleCreate (8, HOMOL, map->handle) ;
  
  flatA = arrayCreate (8, BSunit) ;
  obj = bsCreate (map->key);
  
  if (bsFindTag (obj, _Homol) && bsFlatten (obj, 8, flatA))   /* flatten tree in steps of 8 */
    /* The model for the Homol tag in ?Alignment is :
     * ?Alignment ...
     *     Homol Pep_homol ?Protein XREF Align_homol ?Method Float Int UNIQUE Int Int UNIQUE Int #Homol_info
     */
    for (i = 0 ; i < arrayMax (flatA) ; i += 8) 
      {
	if(arr(flatA, i+2, BSunit).k != 0){/* will need to something else ??? temp fix */
	  homol = arrayp(homols, arrayMax(homols), HOMOL) ;
	  homol->key = arr(flatA, i+1, BSunit).k ;
	  homol->meth = arr(flatA, i+2, BSunit).k ;
	  homol->score  = arr(flatA, i+3, BSunit).f ;
	  homol->qstart = arr(flatA, i+4, BSunit).i ;
	  homol->qend   = arr(flatA, i+5, BSunit).i ;
	  homol->sstart = arr(flatA, i+6, BSunit).i ;
	  homol->send   = arr(flatA, i+7, BSunit).i ;
	  methodAdd (homol->meth) ;
	}
      } 

  { KEY key ;
    MATCH *m ;
    Array ma ;

    if (bsGetKey (obj, str2tag("Match_table"), &key) &&
	(ma = arrayGet (key, MATCH, matchFormat)))
      { for (i = 0 ; i < arrayMax(ma) ; ++i)
	  { m = arrp (ma, i, MATCH) ;
	    homol = arrayp(homols, arrayMax(homols), HOMOL) ;
	    homol->key    = m->key ;
	    homol->meth   = m->meth ;
	    homol->score  = m->score ;
	    homol->qstart = m->q1 ;
	    homol->qend   = m->q2 ;
	    homol->sstart = m->t1 ;
	    homol->send   = m->t2 ;
	    methodAdd (homol->meth) ;
	  }
	arrayDestroy (ma) ;
      }
  }
  
  bsDestroy (obj) ;
  arrayDestroy (flatA) ;
  arraySort(homols, homolOrder); /* just trying it */
  return homols ;
}

static void pepMapShowText(int box) 
{
  MAPCONTROL map;
  HOMOL *homol;

  map = currentMapControl();
  homol = arr(map->control->boxIndex2, box, void *);

  display(homol->key,map->key,"TREE");
}

/****************************************************************************************************************/

static void bsPushIntData(OBJ obj, int queryInt)
{
  int searchInt;

  bsGetData (obj, _bsRight, _Int, &searchInt);
  while (searchInt != queryInt && bsGetData (obj, _bsDown, _Int, &searchInt));
  if (searchInt != queryInt) messcrash("Could not find Int %d", queryInt);
  bsPushObj(obj);
}


/****************************************************************************************************************/
static void pepMapPfamWWW(int box) 
{
  MAPCONTROL map;
  HOMOL *homol;
  char *script = dbPathFilName(WSCRIPTS, "PfamWWW_script", "", "x", 0);

  map = currentMapControl();
  homol = arr(map->control->boxIndex2, box, void *);

  if (script)
    {
      callScript (script, name(homol->key)) ;
      messfree(script);
    }
}


/****************************************************************************************************************/
static void pepMapShowBelvu(int box) 
{
  MAPCONTROL map;
  PEPLOOK *look;
  HOMOL *homol;
  OBJ obj;
  KEY key, _Align_homol, _Alignment, _Segs;
  char *cp, *cpep, *pep;
  int i, searchInt;
  float searchFloat;

  map = currentMapControl();
  look = (PEPLOOK*)map->look;
  homol = arr(map->control->boxIndex2, box, void *);
  obj = bsCreate(map->key);

  BelvuMatchStack = stackReCreate (BelvuMatchStack, 10);

  /* Pass the stuff below on to Belvu */
  pushText(BelvuMatchStack, 
	   messprintf("%s/%d-%d %.1f", name(map->key), homol->qstart, homol->qend, homol->score));

  /* The sequence segment */
  pep = messalloc(homol->qend+1);
  cpep = pep;
  cp = arrp(look->pep, 0, char);
  for (i = homol->qstart; i <= homol->qend; i++, cpep++)
      *cpep = pepDecodeChar[(int)*(cp+i-1)];
  pushText(BelvuMatchStack, pep);
  messfree(pep);
  
  /* The Segs */
  lexaddkey("Alignment", &_Alignment, 0);
  lexaddkey("Align_homol", &_Align_homol, 0);
  lexaddkey("Segs", &_Segs, 0);

  bsGetKey (obj, _Align_homol, &key);
  while (key != homol->key && bsGetKey (obj, _bsDown, &key));
  if (key != homol->key) messcrash("Could not find key to %s", name(homol->key));
  bsPushObj(obj);

  bsGetKey (obj, _bsRight, &key);
  while (key != homol->meth && bsGetKey (obj, _bsDown, &key));
  if (key != homol->meth) messcrash("Could not find key to %s", name(homol->meth));
  bsPushObj(obj);

  bsGetData (obj, _bsRight, _Float, &searchFloat);
  while (searchFloat != homol->score && bsGetData (obj, _bsDown, _Float, &searchFloat));
  if (searchFloat != homol->score) messcrash("Could not find score %f", homol->score);
  bsPushObj(obj);

  bsPushIntData(obj, homol->qstart);
  bsPushIntData(obj, homol->qend);
  bsPushIntData(obj, homol->sstart);
  bsPushIntData(obj, homol->send);

  /* Cannot use bsFlatten or bsGetArray, which uses bsFlatten, since I then have to give a
     maximum number of segs.  Instead iterate till all are found */

  bsFindTag (obj, _Segs);
  bsPushObj(obj);

  while (bsGetData (obj, _bsRight, _Int, &searchInt)) {
    pushText(BelvuMatchStack, messprintf("%d ", searchInt));
    bsPushObj(obj);
  }

  alignDisplay (homol->key, 0, 0);
}

/****************************************************************************************************************/
static void pepMapShowBlixemPext(int box) 
{
#if !defined(NO_POPEN)
  HOMOL *homol ;
  Array homols;
  MAPCONTROL currentMap = currentMapControl();
  PEPLOOK *look;
  METHOD *meth ;
  int i;
  FILE *pipe ;
  char *script, *qseq, *cp;
  COLCONTROL control = currentMap->control ;
  COLINSTANCE instance = array(control->boxIndex,box,COLINSTANCE);
 
  homols = *(instance->proto->convertResults);

  /* Open pipe to Blixem */
  /* Can't call callScriptPipe since we want write access and buildCommand 
     is not an exported function in the graph library */
   script = dbPathFilName(WSCRIPTS, "blixem_script", "", "x", 0) ;
   if (!script)
     {
       messout("Could not find an executable blixem_script");
       return;
     }
  printf("Calling \"%s\"\n", script);
  fflush(stdout);
  pipe = (FILE *)popen(script, "w");
  messfree(script);

  look = (PEPLOOK*) currentMap->look;
  qseq = messalloc(arrayMax(look->pep)+1);
  for (cp = qseq, i = 0; i < arrayMax(look->pep);)
      *cp++ = pepDecodeChar[(int)arr(look->pep, i++, char)] ;

  fprintf (pipe, "%s\n%s\n", currentMap->name, qseq);
  fprintf (pipe, "# exblx\n# BLASTP\n");
  for (i = 0 ; i < arrayMax (homols) ; i++)
  { 
    homol = arrp(homols, i, HOMOL) ;
    meth = method(homol->meth) ;
    if (meth->flags & METHOD_BLIXEM_P)
      fprintf (pipe, "%.0f (+1) %d %d %d %d %s\n",
	       (meth->flags & METHOD_BELVU ? -3 : homol->score),  
	       homol->qstart, 
	       homol->qend,   
	       homol->sstart, 
	       homol->send,   
	       (meth->flags & METHOD_BELVU ? "GREEN" : name(homol->key)));
  }

  fflush(stdout);
  fprintf (pipe, "%c\n", EOF) ; /* To close the pipe, sigh */
  fflush(pipe);
  /* pclose is no good - waits till Blixem is finished. */

  messfree(qseq);
#endif  /* not NO_POPEN */
}

/****************************************************************************************************************/

static void pepMapShowBlixemPint(int box) 
{
  HOMOL *homol ;
  Array homols, a;
  MAPCONTROL currentMap = currentMapControl();
  PEPLOOK *look;
  METHOD *meth ;
  MSP MSPlist, *msp, *msp2;
  KEY key; 
  COLCONTROL control = currentMap->control ; 
  COLINSTANCE instance = array(control->boxIndex,box,COLINSTANCE);
  int i;
  char *cp, *qseq, opts[] = "P";
  BOOL pfetch = FALSE ;
  PfetchParams pfetch_params = {NULL, 0} ;


  homols = *(instance->proto->convertResults);

  look = (PEPLOOK*) currentMap->look;
  qseq = messalloc(arrayMax(look->pep)+1);
  for (cp = qseq, i = 0; i < arrayMax(look->pep);)
      *cp++ = pepDecodeChar[(int)arr(look->pep, i++, char)] ;

  MSPlist.next = 0;
  msp = &MSPlist ; 
  for (i = 0 ; i < arrayMax (homols) ; i++)
  { 
    homol = arrp(homols, i, HOMOL) ;
    meth = method(homol->meth) ;

    if (meth->flags & METHOD_BLIXEM_P) {
      msp->next = (MSP*)messalloc(sizeof(MSP));
      msp = msp->next;

      msp->score = homol->score;
      msp->qstart = homol->qstart;
      msp->qend = homol->qend;
      msp->sstart = homol->sstart;
      msp->send = homol->send;
      strcpy(msp->qframe, "(+1)");
      if (meth->flags & METHOD_BELVU) {
	  msp->score = -3;
	  msp->id = GREEN;
      }
      else strncpy(msp->sname, name(homol->key), FULLNAMESIZE);
    }
  }

  /* Get sequences */
  for (msp = MSPlist.next; msp ; msp = msp->next) {
    if (msp->sseq) continue;
      
    if (lexword2key (msp->sname, &key, _VPeptide) && (a = arrayGet(key, char, "c"))) { 
      pepDecodeArray (a) ;
      msp->sseq = arrp(a, 0, char) ;
      a->base = 0 ;
      arrayDestroy(a) ;

      /* Avoid duplication of sequence */
      for (msp2 = msp->next; msp2 ; msp2 = msp2->next)
	  if (!strcmp(msp->sname, msp2->sname)) 
	      msp2->sseq = msp->sseq;
    }
  }

  if ((pfetch = prefValue(BLIXEM_PFETCH)))
    {
      pfetch_params.net_id = prefString(BLIXEM_NETID) ;
      pfetch_params.port = prefInt(BLIXEM_PORT_NUMBER) ;
    }

  blxview(qseq, currentMap->name, 1, 0, MSPlist.next, opts,
	  (pfetch ? &pfetch_params : NULL), FALSE) ;
	  /* FALSE means it's not an external call */

}

static MENUOPT belvuMenu[] = {
  { MENU_FUNC_CAST pepMapShowText, "Show as Text" },
  { MENU_FUNC_CAST pepMapShowBelvu, "Analyse in Belvu" },
  { MENU_FUNC_CAST pepMapPfamWWW, "Pfam WWW page" },
  { MENU_FUNC_CAST pepMapShowBlixemPint, "Analyse in Blixem, internal" },
  { MENU_FUNC_CAST pepMapShowBlixemPext, "Analyse in Blixem, external" },
  { 0, 0 }
} ;

static MENUOPT blixemPMenu[] = {
  { MENU_FUNC_CAST pepMapShowText, "Show as Text"},
  { MENU_FUNC_CAST pepMapShowBlixemPint, "Analyse in Blixem, internal"},
  { MENU_FUNC_CAST pepMapShowBlixemPext, "Analyse in Blixem, external"},
  { 0, 0 }
} ;


static int strCaseStr(char *s1, char *s2)
{
  char *cp;
  int s1len = strlen(s1), 
  s2len = strlen(s2);

  for (cp = s1; cp <= s1+s1len-s2len; cp++)
    if (!strncasecmp(cp, s2, s2len)) return 1;

  return 0;
  /* Does this function really not exist ? There must be a better way */
}

/****************************************************************************************************************/
static void homolDraw (COLINSTANCE instance, float *offset) 
{ 
  float y1, y2, fmax = 0;
  PEPLOOK *look = (PEPLOOK*) instance->map->look ;
  COLCONTROL control = instance->map->control ;
  int i, box ,xoff;
  BUMP bump = 0 ;
  HOMOL *homol ;
  Array homols;
  METHOD *meth ;
  HOMOLPRIV private = instance->private;
  MAPCONTROL currentMap;

  currentMap = currentMapControl();
  
  homols = *(instance->proto->convertResults);
       
  if (private->bump)
    bump = bumpCreate (1000, 0) ;
  for (i = 0 ; i < arrayMax (homols) ; i++)
    { 
      homol = arrp(homols, i, HOMOL) ;

      /* Make sure it's the right method for this column */
      if (!strCaseStr(instance->name, name(homol->meth))) continue;

      meth = method(homol->meth) ;
	  
      /* checks to prevent arithmetic crash */
    
      if (meth->flags & METHOD_SCORE_BY_OFFSET && !meth->minScore)
	meth->minScore = 1 ;
      if (meth->flags & METHOD_SCORE_BY_WIDTH && meth->maxScore == meth->minScore)
	meth->maxScore = meth->minScore + 1 ;

      y1 = MAP2GRAPH(instance->map, homol->qstart);
      y2 = MAP2GRAPH(instance->map, homol->qend);

      if(y2 > control->graphHeight -0.5){
	if(y1 > control->graphHeight -0.5)
	  continue;
	else
	  y2 = control->graphHeight -0.5;
      }
      if (y1 < control->topMargin+0.5){
	if(y2 < control->topMargin + 0.5)
	  continue; 
	else
	  y1 = control->topMargin+0.5;
      }
      box = graphBoxStart() ;
      if (meth->flags & METHOD_SCORE_BY_OFFSET)
	{ float dx = 6 - 4*log10((double)(homol->score/meth->minScore)) ;
	  if (dx < 0)
	    dx = 0 ;
	  graphRectangle (*offset + dx, y1, *offset + dx + .85, y2) ;
	  if (fmax < dx)
	    fmax = dx ;
	}
      else if (meth->flags & METHOD_SCORE_BY_WIDTH)
	{ float dx = 0.5 + 0.5 * (homol->score - meth->minScore) / 
	    				(meth->maxScore - meth->minScore) ;
	  if (dx < 0.5) dx = 0.5 ;
	  if (dx > 1) dx = 1 ;
          xoff = 1 ;
          if (bump)
	    {
	      if (look->map->mag < 0)
		{
		  y1 = -y1 ; y2 = -y2 ;
		  bumpItem (bump, 2, (y2-y1), &xoff, &y1) ;
		  y1 = -y1 ; y2 = -y2 ;
		}
	      else
		bumpItem (bump, 2, (y2-y1), &xoff, &y1) ;
	    }
          graphRectangle (*offset + (xoff - dx), y1, 
                          *offset + (xoff + dx), y2) ;
          if (fmax < xoff+dx) fmax = xoff+dx ;

	}
      else
	{ graphRectangle (*offset + 0.25, y1, *offset + 1.75, y2) ;
	  if (!fmax) fmax = 1;
	}
      graphBoxEnd() ;

      graphBoxDraw (box, BLACK, meth->colour) ;
      controlRegBox (instance, box, homol) ;
      if (meth->flags & METHOD_BELVU)
	graphBoxMenu (box, belvuMenu) ;
      else if (meth->flags & METHOD_BLIXEM_P)
	graphBoxMenu (box, blixemPMenu) ;

    }
 
  if (fmax) *offset += fmax + 2 ;

  if(bump)
    bumpDestroy(bump);
}

/**************************************************************************************************/

static void homolPrivDestroy(void * p)
{
 HOMOLPRIV private = (HOMOLPRIV)p;

 if(arrayExists(private->segs)) arrayDestroy(private->segs);
}

/**************************************************************************************************/

static BOOL homolUnSetSelect(COLINSTANCE instance, int box)
{
  MAPCONTROL map = instance->map;
  COLCONTROL control = map->control;
  PEPLOOK *look = map->look;

  control->activeKey = 0;
  look->startcol = 0;
  look->endcol = 0;
  
  *look->messageText = 0;
  
  if(look->messageBox)
    graphBoxDraw(look->messageBox,-1,-1);

  return FALSE;
}

static BOOL homolSetSelect(COLINSTANCE instance, int box, double x, double y)
{
  MAPCONTROL map = instance->map;
  COLCONTROL control = map->control;
  HOMOLPRIV private = instance->private;
  PEPLOOK *look = map->look;
  HOMOL *homol =(HOMOL *) arr(control->boxIndex2,box,void *);

  control->activeKey = homol->key;
  control->activeBox = box;
  look->startcol = homol->qstart;
  look->endcol = homol->qend;

  graphBoxDim(box,&private->x,0,0,0);
  return FALSE;

}

static void homolDoColour(COLINSTANCE instance, int box)
{
  MAPCONTROL map = instance->map;
  HOMOLPRIV private = instance->private;
  COLCONTROL control = map->control;
  PEPLOOK *look = map->look;
  HOMOL *homol =(HOMOL *) arr(control->boxIndex2,box,void *);
  METHOD *meth ;
  float x1;

  meth = method(homol->meth) ;
  graphBoxDim(box,&x1,0,0,0);
  if(homol->key == control->activeKey && instance == control->activeInstance){
    if( x1 == private->x && 
     look->startcol == homol->qstart && look->endcol == homol->qend){
      graphBoxDraw(box, BLACK,activecol);
      strncpy(look->messageText, name(homol->key),100);
      strcat(look->messageText, messprintf(" %d  %d ",homol->sstart,homol->send));
      strcat(look->messageText, name(homol->meth));
      strcat(look->messageText,messprintf(" %4.2f ",homol->score));
      strcat(look->messageText, messprintf(" (%d - %d) ",homol->qstart,homol->qend));
      if(look->messageBox)
	graphBoxDraw(look->messageBox,-1,-1);
      control->activeBox = box;
    }
    else
      graphBoxDraw(box, BLACK,keyfriendcol);
  }
  else if(homol->key == control->activeKey )
    graphBoxDraw(box, BLACK,friendcol);
  else{
    if(look->startcol <= homol->qstart && look->endcol >= homol->qend)
      graphBoxDraw(box, BLACK, friendcol);
    else if((look->endcol == 0)&&(look->startcol >= homol->qstart && look->startcol <= homol->qend))
      graphBoxDraw(box, BLACK, friendcol);
    else
      graphBoxDraw(box, BLACK, meth->colour);
  }
}
/*************************************************************************************************/
static void homolFollowBox(COLINSTANCE instance, int box,double x, double y)
{
  MAPCONTROL map = instance->map;
  COLCONTROL control = map->control;
  HOMOL *homol =(HOMOL *) arr(control->boxIndex2,box,void *);
  PEPLOOK *look = map->look;

  if(look->block){
    look->activeStart = homol->qstart;
    look->activeEnd = homol->qend;
  }
  display(homol->key, map->key, 0);
}
/*************************************************************************************************/
static void pepHomolSave(COLINSTANCE instance, OBJ init) 
{
  HOMOLPRIV private = instance->private;
  
  if(private->bump)
    bsAddTag(init,str2tag("HOM_bump"));
}

/*************************************************************************************************/
extern  BOOL homolCreate (COLINSTANCE instance, OBJ init) 
{
  HOMOLPRIV private;
  
  instance->draw = homolDraw ;
  instance->configure = homolConfigure;
  instance->doColour = homolDoColour; 
  instance->unSelectBox = homolUnSetSelect; 
  instance->setSelectBox =  homolSetSelect;
  instance->followBox = homolFollowBox;
  instance->save = pepHomolSave;
  instance->configFinal = pepConfigFinal;

  private = (HOMOLPRIV) handleAlloc(homolPrivDestroy, instance->handle , sizeof(struct homolColPriv));
  private->bump = FALSE;
  instance->private = private;

  if(init){
    if(bsFindTag(init,str2tag("HOM_bump")))
      private->bump = TRUE;
  }

  return TRUE ;
}

/*********************************** END **********************************************************/
/* put the names colomn stuff here to share the homol data */

static void homolNameDraw (COLINSTANCE instance, float *offset) 
{ 
  float y1, y2, fmax = 0, namemax = 0 ,y3;
  PEPLOOK *look = (PEPLOOK*) instance->map->look ;
  COLCONTROL control = instance->map->control ;
  int i, box ,xoff;
  BUMP bump = 0 ;
  HOMOL *homol ;
  Array homols;
  METHOD *meth ;
  HOMOLPRIV private = instance->private;
  MAPCONTROL currentMap;

  currentMap = currentMapControl();
  
  homols = *(instance->proto->convertResults);
 
  if (private->bump)
    bump = bumpCreate (private->width, 0) ;
  for (i = 0 ; i < arrayMax (homols) ; i++)
    { 
      homol = arrp(homols, i, HOMOL) ;
      
      if (!strCaseStr(instance->name, name(homol->meth)))
	continue;
      meth = method(homol->meth) ;
      
      y1 = MAP2GRAPH(instance->map, homol->qstart);
      y2 = MAP2GRAPH(instance->map, homol->qend);
      
      if(y2 > control->graphHeight -0.5){
	if(y1 > control->graphHeight -0.5)
	  continue;
	else
	  y2 = control->graphHeight -0.5;
      }
      if (y1 < control->topMargin+0.5){
	if(y2 < control->topMargin + 0.5)
	  continue; 
	else
	  y1 = control->topMargin+0.5;
      }
      /* Show name of homologous object - either here or in text-area to the right */
      xoff = 0 ;
      fmax = 0;
      y3 = (y1+y2)/2;
      if (bump)
	{
	  if (look->map->mag < 0)
	    {
	      y1 = -y1 ; y2 = -y2 ;
	      bumpItem (bump,strlen(name(homol->key))+1,1, &xoff, &y3) ;
	      y1 = -y1 ; y2 = -y2 ;
	    }
	  else
	    bumpItem (bump,strlen(name(homol->key))+1,1, &xoff, &y3) ; 
	}
      box = graphBoxStart();
      graphText(name(homol->key), *offset + xoff, y3);
      if (strlen(name(homol->key))+2 > namemax)
	namemax = strlen(name(homol->key))+2; 
      if (fmax < xoff + namemax)
	fmax = xoff +namemax;
      graphBoxEnd();
      controlRegBox (instance, box, homol) ;
    }
  *offset += fmax+4;
  if(private->bump)
    bumpDestroy(bump);
  
}

static void pepHomolNameSave(COLINSTANCE instance, OBJ init) 
{
  HOMOLPRIV private = instance->private;
  
  if(private->bump)
    bsAddTag(init,str2tag("HOM_NAME_bump"));
  if(private->width)
    bsAddData(init,str2tag("HOM_NAME_width"),_Int,&private->width);
}

struct configLocalsName{
  int width;
  BOOL bump;
};

static BOOL homolNameConfigure(COLINSTANCE instance)
     
{
  HOMOLPRIV private = instance->private;
  struct configLocalsName *cf = (struct configLocalsName *) messalloc(sizeof(struct configLocalsName));
  float line = 2.0;

  if(controlCreateConfig(instance,cf,"Configure pepdisp name column",0.5,0.15)){
    /* initialise data */
    cf->width = private->width;
    cf->bump = private->bump;

    graphIntEditor("HomolName Display Width :",&cf->width,4.0,line++,0);
    graphToggleEditor("Bump",&cf->bump,4.0,line++);
  
    graphRedraw();
  }

  return FALSE;
}

static void pepNameConfigFinal(COLINSTANCE instance, void *locals, BOOL ok){
  struct configLocalsName *cf = locals;
  HOMOLPRIV private = instance->private;

  if(ok){
    private->bump = cf->bump;
    private->width = cf->width;
  }
  else
    messfree(cf);
}

extern  BOOL homolNameCreate (COLINSTANCE instance, OBJ init) 
{
  HOMOLPRIV private;
  int x;
  
  instance->draw = homolNameDraw ;
  instance->configure = homolNameConfigure;
  instance->doColour = homolDoColour; 
  instance->unSelectBox = homolUnSetSelect; 
  instance->setSelectBox =  homolSetSelect;
  instance->followBox = homolFollowBox;
  instance->save = pepHomolNameSave;
  instance->configFinal = pepNameConfigFinal;

  private = (HOMOLPRIV) handleAlloc(homolPrivDestroy, instance->handle , sizeof(struct homolColPriv));
  private->bump = FALSE;
  private->width = 30;
  instance->private = private;

  if(init){
    if(bsFindTag(init,str2tag("HOM_NAME_bump")))
      private->bump = TRUE;
    if(bsGetData(init,str2tag("HOM_NAME_width"),_Int,&x))
      private->width = x;
  }
  
  return TRUE ;
}




 
 
 
 
 
 
 
 
 
 
 
 
