/*  File: o2m.c
 *  Written by Jo Dicks (jld@bioch.ox.ac.uk)
 * -------------------------------------------------------------------
 * 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 comparative mapping package, 
 * written by Jo Dicks and Michelle Kirby
 * The original ACeDB system was written by :
 * 	Richard Durbin (MRC LMB, UK) rd@mrc-lmba.cam.ac.uk, and
 *	Jean Thierry-Mieg (CRBM du CNRS, France) mieg@kaa.cnrs-mop.fr
 *      Copyright (C) J Thierry-Mieg and R Durbin, 1991
 *
 * Description:  to display One-2-Many chromosome maps
 * Exported functions: o2mDisplay () only
 * HISTORY:
 * Last edited: May  6 13:35 2003 (edgrif)
 *	- change NULL's to 0's to please MS Visual C++ compiler
 * * Dec  2 10:13 1996 (srk)
 * Created: August 1994
 *-------------------------------------------------------------------
 */

/* $Id: o2m.c,v 1.15 2003/05/06 13:14:00 edgrif Exp $ */

#include "acedb.h"

#include "display.h"
#include "lex.h"
#include "bs.h"
#include "oxgrid.h"
#include "keysetdisp.h"

#include "whooks/systags.h"
#include "whooks/classes.h"
#include "whooks/sysclass.h"
#include "whooks/tags.h"

BOOL o2mDisplay (void) ;
int o2mConvert (OX ox) ;   
int pOrder (void *a, void *b) ;  
static void o2mDraw (OX ox) ;
static void o2mDestroy (void) ;
static void drawChromosome (OX ox, float xlen) ;
static void drawPoints (OX ox, float xscale) ;
static void drawLines (OX ox, float xscale) ;
static void o2mPick (int box, double x_unused, double y_unused, int modifier_unused) ;
static void o2mSelect (OX ox, int box) ;
static void o2mFollow (OX ox) ;
static void drawScale (OX ox) ;
static void toggleCells (void) ;
static void toggleChroms (void) ;
static void noChroms (void) ;
static void o2mClear (void) ;
static void o2mLightAll (void) ;
static void o2mLight (void) ;
static void o2mUnLight (void) ;
static void o2mHide (void) ;
static void o2mHideLight (void) ;
static void o2mUnHide (void) ;
static void o2mExport (void) ;
static void o2mLightHom (void) ;
static void o2mUnLightHom (void) ;
static void o2mFindHom (char *string) ;
static void o2mFindLoc (char *string) ;
static int o2mhomolCompletion (char *cp, int len) ;
static int o2mlocusCompletion (char *cp, int len) ;
static void o2mZoomIn (void) ;
static void o2mZoomOut (void) ;


BOOL COLUMN = FALSE ;
BOOL ROW = FALSE ;

KEY _Prefix ;
int _VPrefix ;

enum BoxNames { BACKGROUND=0, 
                O2MEQ_BOX, CHROM_BOX, HIDE_BOX,
                FINDHOM_BOX, FINDHOM2_BOX,
                FINDLOC_BOX, FINDLOC2_BOX,
                ZOOM_IN, ZOOM_OUT,
		MESS2_BOX, MIN_BOX } ;  /* MIN_BOX must be last */

static MENUOPT o2mMenu[] =
            { {graphDestroy, "Quit"},
	      {help, "Help"},
	      {graphPrint, "Print"},
	      {displayPreserve, "Preserve"},
	      {0, 0}
            } ;

static MENUOPT Highlight2Menu[] =
            { {o2mClear, "Clear and show all"},
              {o2mLightAll, "Highlight all"},
              {o2mLightHom, "Highlight homology"},
              {o2mUnLightHom, "Unhighlight homology"},
              {o2mLight, "Highlight selected keyset"},
              {o2mUnLight,"Unhighlight selected keyset"},
              {o2mHide, "Restrict to keyset"},
              {o2mHideLight, "Hide highlit items"},
              {o2mUnHide, "Unhide hidden items"},
              {o2mExport, "Export highlit keyset"},
              {0, 0}
            } ;

static float xOff, yOff ;

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

void o2mCreate (void)
{ 
  BOX *bx ;
  int box ;
  OXGET("o2mCreate") ;

  ox->size3 = arrayCreate (64, int) ;
  ox->axis3 = arrayCreate (64, KEY) ;
  COLUMN = FALSE ; ROW = FALSE ; 

  if (!(ox->gridBox))
    {messout ("You have not selected a cell");
     return;}
  else
    {box = ox->gridBox ;
     if (box >= ox->mlb + ox->map_labels)
      {bx = arrayp (ox->boxes, (box - ox->mlb + 1), BOX) ;
       if (messQuery ("Column (y) or Row (n)"))
         {ox->c3 = bx->map1 ;
          ox->s5 = ox->s2 ;
          COLUMN = TRUE ;
          ox->size3 = arrayCopy (ox->size2) ;
          ox->axis3 = arrayCopy (ox->axis2) ;
         }
       else
         {ox->c3 = bx->map2 ;
          ox->s5 = ox->s1 ;
          ROW = TRUE ;
          ox->size3 = arrayCopy (ox->size1) ;
          ox->axis3 = arrayCopy (ox->axis1) ;
         }
          
       if (!o2mDisplay ()) return ; ;
       }
     }
 
}


BOOL o2mDisplay (void)
{
  int h ;
  OXGET("o2mDisplay") ;

  h = o2mConvert (ox) ;
  if (!(h > 0)) 
    {messout ("Not enough data to draw a O2MMap") ;
     return FALSE ;}

  if (graphExists (ox->manyGraph))
    { graphActivate (ox->manyGraph) ;
      graphPop () ;
    }
  else 
    { if (!displayCreate ("O2MMAP"))
	return FALSE ;
      ox->manyGraph = graphActive () ;
    
      graphAssociate (&OX_MAGIC, ox) ;
      graphRegister (DESTROY, o2mDestroy) ;      
      graphRegister (MESSAGE_DESTROY, displayUnBlock) ;
      graphRegister (PICK, (GraphFunc) o2mPick) ;
      graphMenu (o2mMenu) ;
      graphTextBounds (180, 120) ;
    }

  
  o2mDraw (ox) ;

  return TRUE ;
}

/************************************************************/
/***************** Registered routines *********************/

/*************************************************/
/************* conversion and drawing ************/

static void o2mDestroy (void)
{
  OXGET ("o2mDestroy") ;

  arrayDestroy (ox->many)   ;
  arrayDestroy (ox->csegs)  ;
  arrayDestroy (ox->c3segs) ;
  arrayDestroy (ox->axis3)  ;
  arrayDestroy (ox->size3)  ;
  ox->s5 = 0 ;
  ox->c3 = 0 ;

}


int o2mConvert (OX ox)
{  
  KEY band, col, chr, key ;
  KEY map1, map2 ;
  OBJ Band, Chr, yChrom, yBand ;
  OBJ loc1, loc2 ;
  float x1, x2, ymin = 0, ymax = 0;
  float min2 = 0, max2 = 0 ;
  float f1, f2, f3, f4 ;
  int box, c, h, i, j, m ;
  int cmin=0, cmax=0, null3=0 ;
  CHROMS *c3seg ;
  BANDS *cseg = 0;
  char *sym ;
  SEG *mseg ;
  HOMOL *seg ;
  Array bands, sizes ;
  static BSMARK mark1 = 0 ;
  static BSMARK mark2 = 0 ;

  ox->flag |= FLAG_O2M_CHROM ;
  ox->flag |= FLAG_O2M_EQUAL ;

  ox->o2mwide = 95 ;
  ox->o2mhigh = 50 ;

  if (!(yChrom = bsCreate (ox->c3)))
    { messout ("No data for chromosome %s", name (ox->c3)) ;
      return 0 ;
    }
  if(bsFindTag (yChrom, _Non_graphic))
    { bsDestroy (yChrom) ;
      ox->flag |= ~FLAG_O2M_CHROM ;
      return 0 ;
    }
  bsDestroy (yChrom) ;

  bands = arrayCreate (8, BSunit);
  sizes = arrayCreate (8, KEY) ;
  ox->c3segs = arrayCreate (8, CHROMS) ;
  ox->csegs = arrayCreate (8, BANDS) ;

  null3 = 0 ;
  for (i = 1 ; i < arrayMax (ox->size3) ; i++)
    {if (array (ox->size3, i, int) == 0) null3++ ;}
  
  if (null3 > 0) 
   {ox->flag |= FLAG_O2M_SIZE ;}

/* BANDS data not yet utilised but can be used to draw points */
/* at their relative position along the y axis as in the TRANSGRID */

  for (j = 1 ; j < arrayMax (ox->axis3) ; j++) 
     {c = 0 ;
      chr = array (ox->axis3, j, KEY) ;
      if ((Chr = bsCreate (chr)))
       {if (bsFindTag (Chr, _Chrom_Band) && bsFlatten (Chr, 1 , bands))
         {for (i = 0 ; i < arrayMax (bands) ; ++i )
           {band = array (bands, i, BSunit).k ;
            Band = bsCreate (band) ; 
            if (bsFindTag (Band, _Map) && bsGetKey (Band, _bsRight, &key))
              if (bsPushObj (Band))
                if (bsGetData (Band, _Left, _Float, &x1) &&
                    bsGetData (Band, _Right, _Float, &x2))
                  {cseg = arrayp (ox->csegs, j, BANDS) ;
                   cseg->chrom = j ;
                   cseg->key = key ;
                   cseg->bands = arrayCreate (8, BSunit) ;
                   array (cseg->bands, c, BSunit).k = band ;
                   array (cseg->bands, c+1, BSunit).f = x1 ;
                   array (cseg->bands, c+2, BSunit).f = x2 ;
                   c += 3 ;}
             bsDestroy (Band) ;
             if (x1 < cmin)
               cmin = x1 ;
             if (x2 > cmax)
             cmax = x2 ;
             }
          cseg->xmin = cmin ;
          cseg->xmax = cmax ;
          }
        }
      bsDestroy (Chr) ;
     }

  arrayDestroy (bands) ;
  bands = arrayCreate (8, BSunit) ;

  if ((yChrom = bsCreate(ox->c3)) )
   {if (bsFindTag (yChrom, _Chrom_Band) && bsFlatten (yChrom, 1 , bands))
     {for (i = 0 ; i < arrayMax (bands) ; i++ )
       {band = array (bands, i, BSunit).k; 
        yBand = bsCreate (band);
        if (bsFindTag (yBand, _Map) &&
            bsGetKey (yBand, _bsRight, &key)) 
          if (bsPushObj(yBand))
            if (bsGetData (yBand, _Left, _Float, &x1) &&
                bsGetData (yBand, _Right, _Float, &x2))
           {c3seg = arrayp (ox->c3segs, i, CHROMS) ;
            c3seg->key = band ;
            c3seg->x = 0.5*(x1+ x2) ;
            c3seg->dx = x2 - x1 ;
	    c3seg->flag = 0 ;
            ox->flag |= FLAG_O2M_BANDS ;}
        bsDestroy (yBand) ;
        if (x1 < ymin)
          ymin = x1 ;
        if (x2 > ymax)
	  ymax = x2 ;
       }

      for (i = 0 ; i < arrayMax (bands) ; i++ )
       {band = array (bands, i, BSunit).k ;
        yBand = bsCreate (band);
        c3seg = arrayp (ox->c3segs, i, CHROMS) ;
        if (bsFindTag (yBand,_Centromere))
	    c3seg->flag |= FLAG_CENTROMERE ;
        if (bsFindTag (yBand,_Dark))
	    c3seg->flag |= FLAG_DARK_BAND ;
	if (bsFindTag (yBand,_NOR))
	    c3seg->flag |= FLAG_NOR ;
	if (bsFindTag (yBand,_Colour) &&
	    bsGetKey (yBand, _bsRight, &col))
	    c3seg->flag |= ((col - _WHITE) & 15  ) << 28;
        if (bsFindTag (yBand,_Symbol)) 
           {bsGetData (yBand, _bsRight, _Text, &sym);
            c3seg->sym = sym ;}
        bsDestroy (yBand) ;
       }   
    
      ox->c3min = ymin;
      ox->c3max = ymax; 
      bsDestroy (yChrom) ;
     }
 

  }       

  i = 0 ; m = 0 ; h = 0 ;
  box = ox->gridBox ;
  ox->many = arrayCreate (8, HOMOL) ;

  for (i = 0 ; i < arrayMax (ox->segs) ; i++ )
    {mseg = arrayp (ox->segs, i, SEG) ;
     if (COLUMN)
      {if (mseg->map1 == ox->c3)
        {seg = arrayp (ox->many, m, HOMOL) ;
         seg->hom = mseg->key ;
         seg->key1 = mseg->gene1 ;
         seg->key2 = mseg->gene2 ;
         seg->flag = 0 ;
         if (mseg->flag & FLAG_HIDE) seg->flag |= FLAG_HOMHIDE ;
         seg->y = mseg->y ;
         seg->x1 = 0 ; seg->dx1 = 0 ; 
         seg->x2 = 0 ; seg->dx2 = 0 ;
         m++ ;

         if ((loc1 = bsCreate (seg->key1)))
         {if (bsGetKey (loc1, _Map, &map1)) do
           {mark1 = bsMark (loc1, mark1) ;
            if (chkSpecies (map1, ox->c3))
              {if (bsPushObj (loc1) &&bsGetData (loc1, _Position, _Float, &f1)) 
                {seg->x2 = f1 ;
                 seg->flag |= FLAG_YPOS ;
                 if (bsPushObj (loc1) && bsGetData (loc1, _Error, _Float, &f2))
                   seg->dx2 = f2 ;
                 else seg->dx2 = 0 ;
                 if ((seg->x2-seg->dx2) < min2) 
                   min2 = (seg->x2-seg->dx2) ;
                 if ((seg->x2+seg->dx2) > max2) 
                   max2 = (seg->x2+seg->dx2) ;
                 }
               }
             }while (bsGoto (loc1, mark1), bsGetKey (loc1, _bsDown, &map1)) ;
           }


         if ((loc2 = bsCreate (seg->key2)))
         {if (bsGetKey (loc2, _Map, &map2)) do
           {mark2 = bsMark (loc2, mark2) ;
            if (chkSpecies (map2, ox->c3))
              {if (bsPushObj (loc2) &&bsGetData (loc2, _Position, _Float, &f3)) 
                {seg->x2 = f3 ;
                 seg->flag |= FLAG_YPOS ;
                 if (bsPushObj (loc2) && bsGetData (loc2, _Error, _Float, &f4))
                   seg->dx2 = f4 ;
                 else seg->dx2 = 0 ;
                 if ((seg->x2-seg->dx2) < min2) 
                   min2 = (seg->x2-seg->dx2) ;
                 if ((seg->x2+seg->dx2) > max2) 
                   max2 = (seg->x2+seg->dx2) ;
                 }
               }
             }while (bsGoto (loc2, mark2), bsGetKey (loc2, _bsDown, &map2)) ;
           }

         if (seg->flag & FLAG_YPOS) h++ ;
         }
       }
     else if (ROW)
      {if (mseg->map2 == ox->c3)     
        {seg = arrayp (ox->many, m, HOMOL) ;
         seg->hom = mseg->key ;
         seg->key1 = mseg->gene1 ;
         seg->key2 = mseg->gene2 ;
         seg->flag = 0 ;
         if (mseg->flag & FLAG_HIDE) seg->flag |= FLAG_HOMHIDE ;
         seg->y = mseg->x ;
         seg->x1 = 0 ; seg->dx1 = 0 ; 
         seg->x2 = 0 ; seg->dx2 = 0 ;
         m++ ;

         if ((loc1 = bsCreate (seg->key1)))
          {if (bsGetKey (loc1, _Map, &map1)) do
           {mark1 = bsMark (loc1, mark1) ;
            if (chkSpecies (map1, ox->c3))
              {if (bsPushObj (loc1) &&bsGetData (loc1, _Position, _Float, &f1)) 
                {seg->x2 = f1 ;
                 seg->flag |= FLAG_YPOS ;
                 if (bsPushObj (loc1) && bsGetData (loc1, _Error, _Float, &f2))
                   seg->dx2 = f2 ;
                 else seg->dx2 = 0 ;
                 if ((seg->x2-seg->dx2) < min2) 
                   min2 = (seg->x2-seg->dx2) ;
                 if ((seg->x2+seg->dx2) > max2) 
                   max2 = (seg->x2+seg->dx2) ;
                 }
               }
             }while (bsGoto (loc1, mark1), bsGetKey (loc1, _bsDown, &map1)) ;
           }


         if ((loc2 = bsCreate (seg->key2)))
          {if (bsGetKey (loc2, _Map, &map2)) do
           {mark2 = bsMark (loc2, mark2) ;
            if (chkSpecies (map2, ox->c3))
              {if (bsPushObj (loc2) &&bsGetData (loc2, _Position, _Float, &f3)) 
                {seg->x2 = f3 ;
                 seg->flag |= FLAG_YPOS ;
                 if (bsPushObj (loc2) && bsGetData (loc2, _Error, _Float, &f4))
                   seg->dx2 = f4 ;
                 else seg->dx2 = 0 ;
                 if ((seg->x2-seg->dx2) < min2) 
                   min2 = (seg->x2-seg->dx2) ;
                 if ((seg->x2+seg->dx2) > max2) 
                   max2 = (seg->x2+seg->dx2) ;
                 }
               }
             }while (bsGoto (loc2, mark2), bsGetKey (loc2, _bsDown, &map2)) ;
           }

         if (seg->flag & FLAG_YPOS) h++ ;      
         }
       }
     }

  if (!(ox->flag & FLAG_O2M_BANDS))
    {ox->c3min = min2-5 ;
     ox->c3max = max2+5 ;
    }

arrayDestroy (bands) ;
arrayDestroy (sizes) ;
return h ;
 
}

static void o2mDraw (OX ox)
{
  int   xmax = 0, ymax = 0 ;
  int   box, i, j, k ;
  float xl, yl, xlen = 0, ylen = 0 ;
  float w1, w2, wtot, h1, h2, htot ;
  float xscale, yscale ;
  CHROMS *c3seg ;

  graphClear () ;

  if (!(ox->flag & FLAG_O2M_EQUAL))
   {if (graphButton (" Equal  sizes ", toggleCells, 1, 3) != O2MEQ_BOX)
    messcrash ("box screwup at %d in o2mDraw", O2MEQ_BOX) ;}
  else
   {if (graphButton ("Relative sizes", toggleCells, 1, 3) != O2MEQ_BOX)
    messcrash ("box screwup at %d in o2mDraw", O2MEQ_BOX) ;}

  if (ox->flag & FLAG_O2M_BANDS)
    {if (ox->flag & FLAG_O2M_CHROM)
      {if (graphButton ("Hide Chromosomes", toggleChroms, 17, 3) != CHROM_BOX)
       messcrash ("box screwup at %d in o2mDraw", CHROM_BOX) ;}
    else
      {if (graphButton ("Draw Chromosomes", toggleChroms, 17, 3) != CHROM_BOX)
       messcrash ("box screwup at %d in o2mDraw", CHROM_BOX) ;}
     }
  else
    {if (graphButton ("Draw Chromosomes", noChroms, 17, 3) != CHROM_BOX)
      messcrash ("box screwup at %d in o2mDraw", CHROM_BOX) ;}

  if (graphButton ("Highlight...", o2mClear, 35, 3) != HIDE_BOX)
    messcrash ("box screwup at %d in o2mDraw", HIDE_BOX) ;

  graphBoxMenu (HIDE_BOX, Highlight2Menu) ;  

  graphText ("Find homology :", 1, 5) ;
  *ox->o2mhom = 0 ;
  if (graphCompScrollEntry (o2mhomolCompletion, ox->o2mhom, 20, 20, 17, 5, o2mFindHom) != FINDHOM_BOX)
    messcrash ("box screwup at %d in o2mDraw", FINDHOM_BOX) ;

  graphEntryDisable () ;

  graphText ("Find locus :", 41, 5) ;
  *ox->o2mloc = 0 ;
  if (graphCompScrollEntry (o2mlocusCompletion, ox->o2mloc, 20, 20, 54, 5, o2mFindLoc) != FINDLOC_BOX)
    messcrash ("box screwup at %d in o2mDraw", FINDLOC_BOX) ;

  graphEntryDisable () ;

  if (graphButton ("Zoom in", o2mZoomIn, 49, 3) != ZOOM_IN)
    messcrash ("box screwup at %d in o2mDraw", ZOOM_IN) ;

  if (graphButton ("Zoom out", o2mZoomOut, 58, 3) != ZOOM_OUT)
    messcrash ("box screwup at %d in o2mDraw", ZOOM_OUT) ;

/* Draw the header box to name a selected homology on screen */   

  ox->message2Box = MESS2_BOX ;
 *ox->message2Text = 0 ;
  ox->message2Box = graphBoxStart () ;
  graphTextPtr (ox->message2Text, 1, 7, 112) ;
  graphBoxEnd () ;
  graphBoxDraw (ox->message2Box, BLACK, LIGHTBLUE) ;

/* Now draw the titles */

  xOff = 0 ; yOff = 0 ;

  graphText (messprintf ("One-to-Many Map for map %s and map_set %s", name (ox->c3), name (ox->s5)), 1, 1);
  graphLine (0, 9.5, 200, 9.5) ; 

  xOff += 2 + strlen (name (ox->c3)) ;
  yOff += 10 ;

  xmax = arrayMax (ox->axis3) - 1 ;
  ymax = arrayMax (ox->c3segs) - 1 ;
  wtot = 0 ; htot = 0 ;
  if (!(ox->flag & FLAG_O2M_EQUAL))
   {for ( j = 1 ; j <= xmax ; j++) {wtot += array (ox->size3, j, int) ;}
    }
  else
   {wtot = xmax + 1;
    }
  htot = ox->c3max - ox->c3min ;
  xscale = ox->o2mwide/wtot ; 
  yscale = ox->o2mhigh/htot ;                                     
  graphColor (BLACK) ;


  for ( i = 1 ; i < arrayMax (ox->axis3) ; i++)
    {yl = strlen (name (array (ox->axis3, i, KEY))) ;
     if (yl > ylen) ylen = yl ;
     }
  ylen *= 0.65 ;
  yOff += 5 + ylen ;

  if (ox->flag & FLAG_O2M_BANDS)
   {for (i = 0 ; i < arrayMax (ox->c3segs) ; i++)
      {c3seg = arrayp (ox->c3segs, i, CHROMS) ;
       xl = strlen (name (c3seg->key)) ;
       if (xl > xlen) xlen = xl ;
       }
    xOff += 8 + xlen ;
    }
  else
    xOff += 10 ;

  box = MIN_BOX ;
  if (box != graphBoxStart ())
    messcrash ("minLiveBox wrong in o2mDraw ()") ;
  graphTextFormat (BOLD) ;
  graphText (name (ox->s5), xOff + (ox->o2mwide)/2, 10) ;
  graphBoxEnd () ;
  graphBoxDraw (box, BLACK, WHITE) ;
  box++ ;
  if (box != graphBoxStart ())
    messcrash ("minLiveBox wrong in o2mDraw ()") ;
  graphTextFormat (BOLD) ;
  graphText (name (ox->c3), 1, yOff + (ox->o2mhigh)/2) ;
  graphBoxEnd () ;
  graphBoxDraw (box, BLACK, WHITE) ;
  box ++ ;
  graphTextFormat(PLAIN_FORMAT);
  
  if (ox->flag & FLAG_O2M_BANDS)
    {for (i = 1 ; i <= xmax ; i++)
      {for ( j = 0 ; j <= ymax ; j++)
        {w1 = 0 ; h1 = 0 ; w2 = 0 ; h2 = 0 ;
         if (!(ox->flag & FLAG_O2M_EQUAL))
           {for ( k = 0 ; k <= i ; k++) {w2 += array (ox->size3, k , int) ;}
            for ( k = 1 ; k <= i ; k++) {w1 += array (ox->size3, k-1 , int) ;}
           }
         else
           {w2 = i ;
            w1 = (i - 1) ;
           }
         for ( k = 0 ; k <= j ; k++) {h2 += (arrayp (ox->c3segs, k, CHROMS)->dx) ;}
         for ( k = 1 ; k <= j ; k++) {h1 += (arrayp (ox->c3segs, k-1, CHROMS)->dx) ;}
         graphRectangle (xOff+(w1*xscale), yOff+(h1*yscale), xOff+(w2*xscale), yOff+(h2*yscale)) ;
         }
       } 
     }
  else
    {for (i = 1 ; i <= xmax ; i++)
      {w1 = 0 ; h1 = 0 ; w2 = 0 ; h2 = 0 ;
       if (!(ox->flag & FLAG_O2M_EQUAL))
           {for ( k = 0 ; k <= i ; k++) {w2 += array (ox->size3, k , int) ;}
            for ( k = 1 ; k <= i ; k++) {w1 += array (ox->size3, k-1 , int) ;}
           }
       else
           {w2 = i ;
            w1 = (i - 1) ;
           }
       graphRectangle (xOff+(w1*xscale), yOff+ox->o2mhigh, xOff+(w2*xscale), yOff) ;
      }
    }

  if (ox->flag & FLAG_O2M_BANDS)
    {for (i = 1 ; i <= xmax ; i++)
       {w1 = 0 ; h1 = 0 ; w2 = 0 ; h2 = 0 ;
        if (!(ox->flag & FLAG_O2M_EQUAL))
          {for ( k = 0 ; k <= i ; k++) {w2 += array (ox->size3, k , int) ;}
           for ( k = 1 ; k <= i ; k++) {w1 += array (ox->size3, k-1 , int) ;}
          }
        else
          {w2 = i ;
           w1 = (i - 1) ;
          }
        if (box != graphBoxStart ())
          messcrash ("minLiveBox wrong in o2mDraw ()") ;
        graphTextHeight (0.5) ;
        japanese (name (array (ox->axis3, i, KEY)), xOff+(w1+w2)*0.5*xscale, yOff-3-ylen) ;
        graphBoxEnd () ;
        graphBoxDraw (box, BLUE, WHITE) ;
        box ++ ;
       } 
     }
  else
    {for (i = 1 ; i <= xmax ; i++)
      {w1 = 0 ; h1 = 0 ; w2 = 0 ; h2 = 0 ;
       if (!(ox->flag & FLAG_O2M_EQUAL))
           {for ( k = 0 ; k <= i ; k++) {w2 += array (ox->size3, k , int) ;}
            for ( k = 1 ; k <= i ; k++) {w1 += array (ox->size3, k-1 , int) ;}
           }
         else
           {w2 = i ;
            w1 = (i - 1) ;
           }
       if (box != graphBoxStart ())
         messcrash ("minLiveBox wrong in o2mDraw ()") ;
       graphTextHeight (0.5) ;
       japanese (name (array (ox->axis3, i, KEY)), xOff+(w1+w2)*0.5*xscale, yOff-3-ylen) ;
       graphBoxEnd () ;
       graphBoxDraw (box, BLUE, WHITE) ;
       box ++ ;
      }
    }

  graphTextHeight (1) ;
  
  if (ox->flag & FLAG_O2M_BANDS)
    {if (ox->flag & FLAG_O2M_CHROM)
       {ox->o2m_labels = 2 + xmax + ymax + 1 ;
        drawChromosome (ox, xlen) ;
       }
     else
       {ox->o2m_labels = 2 + xmax ;
        drawScale (ox) ;
       }
    }
  else
    {ox->o2m_labels = 2 + xmax ;
     drawScale (ox) ;
    }

  drawPoints (ox, xscale); 
  drawLines (ox, xscale);

  ox->manyBox = 0 ;

  graphRedraw () ;
}

static void drawChromosome (OX ox, float xlen)
{
  float y0, dy, y, yend ;
  int i, box, xmax ;
  CHROMS *c3seg ;
  BOOL isBands = FALSE ;

  y0 = -(ox->c3min) ;
  yend = (ox->c3max - ox->c3min) / ox->o2mhigh ;
  xmax = arrayMax (ox->axis3) - 1 ;

/* Draw the chromosome alongside the grid */

  box = MIN_BOX + 2 + xmax ;
  for (i = 0 ; i < arrayMax (ox->c3segs) ; ++i)
    {c3seg = arrayp (ox->c3segs, i, CHROMS) ;
     if (class (c3seg->key) == _VChrom_Band)
       {isBands = TRUE ;
	y = yOff + ( y0 + c3seg->x) / yend ;
	dy = ( 0.5 * c3seg->dx) / yend ;
	if (c3seg->flag & FLAG_CENTROMERE)
	  { graphColor (WHITE) ;
	    graphFillRectangle (xOff-4, y-dy, xOff, y+dy) ;
	    graphColor (BLACK) ;
	    graphLine (xOff-4, y-dy, xOff, y+dy) ;
	    graphLine (xOff, y-dy, xOff-4, y+dy) ;
	    graphLine (xOff-4, y-dy, xOff, y-dy) ;
	    graphLine (xOff, y+dy, xOff-4, y+dy) ;
            if (box != graphBoxStart ())
            messcrash ("minLiveBox wrong in o2mDraw () box %d", box) ;
            graphTextHeight (0.5) ;
            graphText (name (c3seg->key), xOff-6-xlen, y-0.25) ;
            graphBoxEnd () ;
            graphBoxDraw (box, BLUE, WHITE) ;
            box++ ; 
            graphTextHeight (1) ;
           }	      
	else 
	  { if (c3seg->flag & FLAG_DARK_BAND)
             graphColor (DARKGRAY) ;
	    else if (c3seg->flag & FLAG_NOR)
	     graphColor (LIGHTGRAY) ;
	    else
	     graphColor (WHITE) ;
	    if (c3seg->flag >> 28)
	     graphColor ((c3seg->flag  >> 28) + WHITE) ;
	    graphFillRectangle (xOff-4, y-dy, xOff, y+dy) ;
	    graphColor (BLACK) ;
	    graphRectangle (xOff-4, y-dy, xOff, y+dy) ;
            if (box != graphBoxStart ())
            messcrash ("minLiveBox wrong in o2mDraw () box %d", box) ;
            graphTextHeight (0.5) ;
            graphText (name (c3seg->key), xOff-6-xlen, y-0.25) ;
            graphBoxEnd () ;
            graphBoxDraw (box, BLUE, WHITE) ;
            box++ ; 
            graphTextHeight (1) ;
	  }
       }
    }

  graphTextHeight (0) ;

}

static void drawScale (OX ox) 
{
  int i, j, k ;
  float unit, y0 ;

/* If no banding data or if the chromosomes are hidden, draw a scale instead */

  graphTextHeight (0.5) ;
  y0 = yOff + ox->o2mhigh * (1-(ox->c3max / (ox->c3max-ox->c3min))) ;
  unit = ox->o2mhigh / (ox->c3max - ox->c3min) ;
  for (i = 0 ; i < (ox->c3max + 1) ; i++)
    graphLine (xOff-3, y0+i*unit, xOff-3.9, y0+i*unit) ;
  for (k = 0 ; k < (ox->c3max + 1) ; k+=10)
   {graphLine (xOff-3, y0+k*unit, xOff-4.5, y0+k*unit) ;
    graphText (messprintf ("%3d",k), xOff - 8, y0+k*unit-0.5) ;
    }
  for (j = 0 ; j < -(ox->c3min - 1) ; j++)
    graphLine (xOff-3, y0-j*unit, xOff-3.9, y0-j*unit) ;
  for (k = 0 ; k < -(ox->c3min - 1) ; k+=10)
   {graphLine (xOff-3, y0-k*unit, xOff-4.5, y0-k*unit) ;
    graphText (messprintf ("%3d",-k), xOff - 8, y0-k*unit-0.5) ;
    }  
  graphLine (xOff-3, y0-(j-1)*unit, xOff-3, y0+(i-1)*unit) ;
  graphTextHeight (1) ;
 
}


static void drawPoints (OX ox, float xscale)
{
  int c, i, k, m, w1, w2 ;
  float x, y, y0, yend ;
  HOMOL *seg ;
   
  y0 = -(ox->c3min) ;
  yend = (ox->c3max - ox->c3min) / ox->o2mhigh ;
  m = MIN_BOX + ox->o2m_labels ;
  for (i = 0 ; i < arrayMax (ox->many) ; i++)
    {seg = arrayp (ox->many, i, HOMOL) ;
     if (seg->flag & FLAG_YPOS)
      {if (!(seg->flag & FLAG_HOMHIDE))
        {w1 = 0 ; w2 = 0 ;
         c = seg->y ; 
         if (!(ox->flag & FLAG_O2M_EQUAL))
           {for ( k = 0 ; k <= c ; k++) {w2 += array (ox->size3, k , int) ;}
            for ( k = 1 ; k <= c ; k++) {w1 += array (ox->size3, k - 1 , int) ;}
           }
         else
           {w2 = c ;
            w1 = (c - 1) ;
           }
         x = xOff + (0.5*(w2+w1)*xscale) ;
         y = yOff + (y0 + seg->x2) / yend ;
         if (m != graphBoxStart ())
           messcrash ("problems with One-to-Many-Map point %d", m) ;
         graphRectangle (x-0.4, y-0.4, x+0.4, y+0.4) ;
         graphBoxEnd () ;
         if (seg->flag & FLAG_HIGHLIGHT) graphBoxDraw (m, WHITE, MAGENTA) ;
         else graphBoxDraw (m, WHITE, BLUE) ;
         seg->pbox = m ;
         m++ ;}  
        }    
     }
}

int pOrder (void *a, void *b)
{ 
  POINT *point = (POINT*)a ;
  POINT *point2 = (POINT*)b ;
  float x ;

  x = point->y - point2->y ;
  if (x == 0) return 0 ;
  else if (x > 0) return 1 ;
  return -1 ;
}

static void drawLines (OX ox, float xscale)
{
  int i, j, k, l, w1, w2 ;
  float x, y0, y1, y2, yend ;
  HOMOL *seg ;
  POINT *point, *point2 ;
  Array tpoints ;

  ox->segsize = 25 ;

  graphColor (MAGENTA) ;
  y0 = -(ox->c3min) ;
  yend = (ox->c3max - ox->c3min) / ox->o2mhigh ;
  for (i = 0 ; i < arrayMax (ox->axis3) ; i++)
    {tpoints = arrayCreate (64, POINT) ;
     k = 0 ;
     for (j = 0 ; j < arrayMax (ox->many) ; j++)
       {seg = arrayp (ox->many, j, HOMOL) ;
        if (seg->y == i && seg->x2 != 0)
	  {point = arrayp (tpoints, k, POINT) ;
           point->y = seg->x2 ;
           k++ ;
          }
       }   

     arraySort (tpoints, pOrder) ;
     for (k = 0 ; k < arrayMax (tpoints) - 1 ; k++)
       {point = arrayp (tpoints, k, POINT) ;
        point2 = arrayp (tpoints, k+1, POINT) ;  
        if ((point2->y - point->y) < ox->segsize) 
          {if (!(ox->flag & FLAG_O2M_EQUAL))
             {w1 = 0 ; w2 = 0 ;
              for ( l = 0 ; l <= i ; l++) {w2 += array (ox->size3, l , int) ;}
              for ( l = 1 ; l <= i ; l++) {w1 += array (ox->size3, l - 1 , int) ;}
             }
           else
             {w2 = i ;
              w1 = (i - 1) ;
             }
           x = xOff + (0.5*(w2+w1)*xscale) ;
           y1 = yOff + (y0 + point->y) / yend ;
           y2 = yOff + (y0 + point2->y) / yend ;
           graphLine (x, y1, x, y2) ;
	  }
       }
     arrayDestroy (tpoints) ;
    }
  graphColor (BLACK) ;
}

extern int ksetClassComplete (char *text, int len, int classe) ;

static int o2mhomolCompletion (char *cp, int len)
{
  return ksetClassComplete (cp, len, _VHomology_group) ;
}

static int o2mlocusCompletion (char *cp, int len)
{
  return ksetClassComplete (cp, len, _VLocus) ;
}

static void o2mFindHom (char* string)
{
  int i ;
  KEY key ;
  HOMOL *seg ;
  BOOL found = FALSE ;

  OXGET ("o2mFindHom") ;

  if (!(lexword2key (string, &key, _VHomology_group)))
    {messout ("Sorry, %s is not a homology name", string) ;
     return ;
    }

  for (i = 0 ; i < arrayMax (ox->many) ; i++)
    {seg = arrayp (ox->many, i, HOMOL) ;
     if (chkSpecies (seg->hom, key)) 
       {found = TRUE ;
        o2mSelect (ox, seg->pbox) ;
       }
     }

  if (found == FALSE) 
   {messout ("Sorry, this homology is not in this grid") ;
    return ;
   }

}

static void o2mFindLoc (char* string)
{
  int i ;
  KEY key ;
  HOMOL *seg ;
  BOOL found = FALSE ;

  OXGET ("o2mFindLoc") ;

  if (!(lexword2key (string, &key, _VLocus)))
    {messout ("Sorry, %s is not a locus name", string) ;
     return ;
    }

  for (i = 0 ; i < arrayMax (ox->many) ; i++)
    {seg = arrayp (ox->many, i, HOMOL) ;
     if (chkSpecies (seg->key1, key) || chkSpecies (seg->key2, key)) 
       {found = TRUE ;
        o2mSelect (ox, seg->pbox) ;
       }
     }

  if (found == FALSE) 
   {messout ("Sorry, this locus is not in this grid") ;
    return ;
   }

}

static void o2mZoomOut (void) 
{
  OXGET ("o2mZoomOut") ;

  if (ox->o2mwide >= 30 && ox->o2mhigh >= 20)
    {ox->o2mwide -= 15 ;
     ox->o2mhigh -= 10 ;

     o2mDraw (ox) ;
    }

}

static void o2mZoomIn (void) 
{
  OXGET ("o2mZoomIn") ;

  if (ox->o2mwide <= 120 && ox->o2mhigh <= 80)
    {ox->o2mwide += 15 ;
     ox->o2mhigh += 10 ;

     o2mDraw (ox) ;
    }

}

static void o2mPick (int box, double x_unused, double y_unused, int modifier_unused) 
{ 
  int xmax ; 

  OXGET ("o2mPick") ;

  xmax = arrayMax (ox->axis3) - 1 ;

  /* The usual - check if the box number is legal, select it if 
     a single click and follow it if a double */

  if (box >= MIN_BOX + ox->o2m_labels && 
      box <= (arrayMax (ox->many) + MIN_BOX + ox->o2m_labels)) /* a seg */
   {if (box == ox->manyBox)
      o2mFollow (ox) ;
    graphActivate (ox->manyGraph) ;
    o2mSelect (ox, box) ; 
   }
  else if (box == MIN_BOX)
    {if (box == ox->manyBox)
       display (ox->s5, 0, 0) ;
     graphActivate (ox->manyGraph) ;
     o2mSelect (ox, box) ;
    }
  else if (box == MIN_BOX + 1)
    {if (box == ox->manyBox)
       display (ox->c3, 0, 0) ;
     graphActivate (ox->manyGraph) ;
     o2mSelect (ox, box) ;
    }
  else if (box >= MIN_BOX + 2 && box < MIN_BOX + 2 + xmax)
    {if (box == ox->manyBox)
       display (array (ox->axis3, box - MIN_BOX - 1, KEY), 0, 0) ;
     graphActivate (ox->manyGraph) ;
     o2mSelect (ox, box) ;
    }
  else if (box >= MIN_BOX + 2 + xmax && box < ox->o2m_labels + MIN_BOX)
    {if (box == ox->manyBox)
       display (arrayp (ox->c3segs, box-MIN_BOX-2-xmax, CHROMS)->key, 0, 0) ;
     graphActivate (ox->manyGraph) ;
     o2mSelect (ox, box) ;
    }
  else if (box == FINDHOM_BOX)
    graphCompScrollEntry (0, ox->o2mhom, 0, 0, 0, 0, 0) ;
  else if (box == FINDLOC_BOX)
    graphCompScrollEntry (0, ox->o2mloc, 0, 0, 0, 0, 0) ;
}

static void o2mSelect (OX ox, int box)
{
  int i, h ;
  KEY group = 0, hit=0, key1 = 0, key2 = 0 ;
  HOMOL *seg ;
  HIDBOX *temp ;
  BOOL HID = FALSE ;
  Array oldhomols = 0 ;
  
  /* The usual - return the old box to normal and colour in the new */
  
  if (ox->manyBox == box) return ;
  
  if (ox->manyBox)
    {oldhomols = arrayCreate (8, HIDBOX) ;
    oldhomols = arrayCopy (ox->ohomols) ;
    ox->ohomols = arrayReCreate (ox->ohomols, 8, HIDBOX) ;
    }
  else 
    ox->ohomols = arrayCreate (8, HIDBOX) ;
  
  for (i = 0 ; i < arrayMax (ox->many) ; ++i)
    {seg = arrp (ox->many, i, HOMOL) ;
    if (seg->pbox == ox->manyBox)
      if (seg->flag & FLAG_HIGHLIGHT) HID = TRUE ;
    if (seg->pbox == box) group = seg->hom ;
    }
  
  h = 0 ;
  for (i = 0 ; i < arrayMax (ox->many) ; ++i)
    {seg = arrp (ox->many, i, HOMOL) ;
    if (chkSpecies (group, seg->hom) && seg->pbox != box)
      {temp = arrayp (ox->ohomols, h, HIDBOX) ;
      temp->box = seg->pbox ;
      if (seg->flag & FLAG_HIGHLIGHT) temp->hid = TRUE ;
      else temp->hid = FALSE ;
      h++ ;
      }
    }
  
  if (ox->manyBox) 
    {if (ox->manyBox >= MIN_BOX + ox->o2m_labels)
      {if (HID == TRUE) graphBoxDraw (ox->manyBox, WHITE, MAGENTA) ;
      else graphBoxDraw (ox->manyBox, WHITE, BLUE) ;
      for (h = 0 ; h < arrayMax (oldhomols) ; h++)
        {temp = arrayp (oldhomols, h, HIDBOX) ;
	if (temp->hid == TRUE) graphBoxDraw (temp->box, WHITE, MAGENTA) ;
	else graphBoxDraw (temp->box, WHITE, BLUE) ;
	}
      }
    else if (ox->manyBox == MIN_BOX || ox->manyBox == MIN_BOX + 1)
      graphBoxDraw (ox->manyBox, BLACK, WHITE) ;
    else if (ox->manyBox >= MIN_BOX + 2 && ox->manyBox < MIN_BOX + ox->o2m_labels)
      graphBoxDraw (ox->manyBox, BLUE, WHITE) ;
    }
  
  ox->manyBox = box ;
  
  if (ox->manyBox >= MIN_BOX + ox->o2m_labels)
    {graphBoxDraw (ox->manyBox, WHITE, GREEN) ;
    for (h = 0 ; h < arrayMax (ox->ohomols) ; h++)
      graphBoxDraw (arrayp (ox->ohomols, h, HIDBOX)->box, WHITE, RED) ;
    }
  else if (ox->manyBox == MIN_BOX || ox->manyBox == MIN_BOX + 1)
    graphBoxDraw (ox->manyBox, WHITE, BLACK) ;
  else if (ox->manyBox >= MIN_BOX + 2 && ox->manyBox < MIN_BOX + ox->o2m_labels)
    graphBoxDraw (ox->manyBox, WHITE, BLUE) ;
  
  graphCompScrollEntry (0, ox->o2mhom, 0, 0, 0, 0, 0) ; 
  graphCompScrollEntry (0, ox->o2mloc, 0, 0, 0, 0, 0) ;
  graphEntryDisable () ;
  
  if (ox->message2Box)
    if (ox->manyBox >= MIN_BOX + ox->o2m_labels)
      {
	for (i=0 ; i < arrayMax (ox->many) ; i++)
	  {
	    seg = arrayp (ox->many, i, HOMOL) ;
	    hit = 0 ;
	    if (seg->pbox == ox->manyBox)
	      {
		hit = seg->hom ;
		key1 = seg->key1 ;
		key2 = seg->key2 ;
	      }
	    
	    if (hit)
	      {
		strncpy (ox->message2Text, messprintf ("Homology "), 80) ; 
		strcat (ox->message2Text, messprintf ("%s ", name (hit))) ;
		strcat (ox->message2Text, 
			messprintf ("between %s and %s", 
				    name (key1), name (key2))) ;
	      }
	  }
      }
    else 
      *ox->message2Text = 0 ;
  
  graphBoxDraw (ox->message2Box, BLACK, LIGHTBLUE) ;
  arrayDestroy (oldhomols) ;
}
  
  static void o2mFollow (OX ox)
{
  int i ;
  KEY hit = 0 ;
  HOMOL *seg ;

  /* Similar to usual - seg->pbox needed to make the keyset option work */

  for (i=0 ; i < arrayMax (ox->many) ; i++)
    {seg = arrayp (ox->many, i, HOMOL) ;
     if (seg->pbox == ox->manyBox)
       hit = seg->hom ;
    }
  if (hit)
    display (hit, 0, 0) ;
}


static void toggleCells (void) 
{
  OXGET ("toggleCells") ;

  if (ox->flag & FLAG_O2M_SIZE)
    {messout ("Maps have not been assigned relative sizes") ;
     return ;}
  else
    {ox->flag ^= FLAG_O2M_EQUAL ;
     o2mDraw (ox) ;}


}

static void toggleChroms (void) 
{
  OXGET ("toggleChroms") ;
  
  if (!(ox->flag & FLAG_O2M_BANDS))
    {messout ("Sorry, there's no band data") ;
     return ;}
  else
    {ox->flag ^= FLAG_O2M_CHROM ;
     o2mDraw (ox) ;}

}

static void noChroms (void) 
{
  OXGET ("noChroms") ;

  messout ("Sorry, there's no band data") ;
  return ;

}

static void o2mClear (void) 
{
  int i ;
  HOMOL *seg ;
 
  OXGET ("o2mClear") ;

  seg = arrayp (ox->many, 0, HOMOL) ;
  i = arrayMax (ox->many) ;
  while(i--)
    {seg->flag &= ~FLAG_HOMHIDE ;  /* bitwise NOT */
     seg->flag &= ~FLAG_HIGHLIGHT ;
     seg++ ;
    }

  o2mDraw (ox) ;

}

static void o2mLightAll (void) 
{
  int i ;

  OXGET ("o2mLightAll") ;

  for (i = 0 ; i < arrayMax (ox->many) ; ++i)
    arrp (ox->many, i, HOMOL)->flag |= FLAG_HIGHLIGHT ;
    
  ox->manyBox = 0 ;

  o2mDraw (ox) ;

}

static void o2mLight (void) 
{
  int i, j ;
  HOMOL *seg ;
  KeySetDisp dummy ;
  KEYSET keySet = 0 ;

  OXGET ("o2mLight") ;

  if (!keySetActive (&keySet, &dummy))
    { messout("First select a keySet window, thank you.") ;
      return ;
    }
  for (i = 0 ; i < arrayMax (ox->many) ; ++i)
    { seg = arrp (ox->many, i, HOMOL) ;
      if (keySetFind (keySet, seg->hom, &j) ||
          keySetFind (keySet, seg->key1, &j) ||
          keySetFind (keySet, seg->key2, &j)) 
	seg->flag |= FLAG_HIGHLIGHT ;
    }

  o2mDraw (ox) ;

}

static void o2mUnLight (void) 
{
  int i, j ;
  HOMOL *seg ;
  KeySetDisp dummy ;
  KEYSET keySet = 0 ;

  OXGET ("o2mUnLight") ;

  if (!keySetActive (&keySet, &dummy))
    { messout ("First select a keySet window, thank you.") ;
      return ;
    }
  for (i = 0 ; i < arrayMax (ox->many) ; ++i)
    { seg = arrp (ox->many, i, HOMOL) ;
      if (keySetFind (keySet, seg->hom, &j) ||
          keySetFind (keySet, seg->key1, &j) ||
          keySetFind (keySet, seg->key2, &j)) 
	seg->flag &= ~FLAG_HIGHLIGHT ;
    }

  o2mDraw (ox) ;

}

static void o2mLightHom (void) 
{
  int i ;
  HOMOL *seg ;

  OXGET ("o2mLightHom") ;

  if (!(ox->manyBox))
    {messout ("You have not selected a homology") ;
     return ;}

  for (i = 0 ; i < arrayMax (ox->many) ; i++)
    {seg = arrayp (ox->many, i, HOMOL) ;
     if (seg->pbox == ox->manyBox) seg->flag |= FLAG_HIGHLIGHT ;
    }

  o2mDraw (ox) ;

}

static void o2mUnLightHom (void) 
{
  int i ;
  HOMOL *seg ;

  OXGET ("o2mUnLightHom") ;

  if (!(ox->manyBox))
    {messout ("You have not selected a homology") ;
     return ;}

  for (i = 0 ; i < arrayMax (ox->many) ; i++)
    {seg = arrayp (ox->many, i, HOMOL) ;
     if (seg->pbox == ox->manyBox) seg->flag &= ~FLAG_HIGHLIGHT ;
    }

  o2mDraw (ox) ;

}



static void o2mHide (void)
{
  int i, j ;
  HOMOL *seg ;
  KeySetDisp dummy ;
  KEYSET keySet = 0 ;
 
  OXGET ("o2mHide") ;

  if (!keySetActive (&keySet, &dummy))
    {messout ("First select a keySet window, thank you.") ;
     return ;
    }

  seg = arrp (ox->many, 0, HOMOL) ;
  i = arrayMax (ox->many) ;
  while(i--)
    {seg->flag &= ~FLAG_HOMHIDE ; 
     if (!keySetFind (keySet, seg->hom, &j) &&
         !keySetFind (keySet, seg->key1, &j) &&
         !keySetFind (keySet, seg->key2, &j)) 
       seg->flag |= FLAG_HOMHIDE ;
     seg++ ;
    }

  o2mDraw (ox) ;

}

static void o2mHideLight (void) 
{
  int i ;
  HOMOL *seg ;

  OXGET ("o2mHideLight") ;

  for (i = 0 ; i < arrayMax (ox->many) ; ++i)
    { seg = arrp (ox->many, i, HOMOL) ;
      if (seg->flag & FLAG_HIGHLIGHT)
	seg->flag |= FLAG_HOMHIDE ;
    }

  o2mDraw (ox) ;

}

static void o2mUnHide (void) 
{
  int i ;
  HOMOL *seg ;

  OXGET ("o2mUnHide") ;

  for (i = 0 ; i < arrayMax (ox->many) ; ++i)
    { seg = arrp (ox->many, i, HOMOL) ;
      seg->flag &= ~FLAG_HOMHIDE ;
    }

  o2mDraw (ox) ;


}

static void o2mExport (void) 
{
  int i, j, k = 0 ;
  HOMOL *seg ;
  static KEYSET kset = 0 ;
  BOOL found = FALSE ;

  OXGET ("o2mExport") ;

  kset = keySetReCreate (kset) ;

  for (i = 0 ; i < arrayMax (ox->many) ; ++i)
    { found = FALSE ;
      seg = arrp (ox->many, i, HOMOL) ;
      if (seg->flag & FLAG_HIGHLIGHT)
        {for (j = 0 ; j < keySetMax (kset) ; j++)
          {if (chkSpecies (seg->hom, keySet (kset, j))) found = TRUE ;}
	 if (found == FALSE) keySet (kset, k++) = seg->hom ;
        }
    }
  keySetSort (kset) ;
  keySetCompress (kset) ;
  keySetNewDisplay (kset, "Ox") ;
}

/************** end of file ****************/
 
 
 
 
 
 
 
