/* File: genecurate.c * Author: Richard Durbin (rd@sanger.ac.uk) * Copyright (C) Richard Durbin, Genome Research Limited, 2002 *------------------------------------------------------------------- * This file is part of the ACEDB genome database package * * 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 * or see the on-line version at http://www.gnu.org/copyleft/gpl.txt * ------------------------------------------------------------------ * Description: temporary standalone implementation of genecurate.h * Exported functions: * HISTORY: * Last edited: Apr 19 18:43 2002 (edgrif) * Created: Tue Jan 22 23:30:14 2002 (rd) * CVS info: $Id: genecurate.c,v 1.2 2002/04/19 17:52:37 edgrif Exp $ *------------------------------------------------------------------- */ /* models required by this file NB some changes from RD ?Gene Version UNIQUE Int Name Public_name UNIQUE ?Gene_name XREF Public_name // not directly editable CGC_name UNIQUE ?Gene_name XREF CGC_name Sequence_name UNIQUE ?Gene_name XREF Sequence_name Other_name ?Gene_name XREF Other_name #Evidence History Version_change Int UNIQUE DateType UNIQUE ?Person #Gene_history_action Merged_into UNIQUE ?Gene XREF Acquires_merge Acquires_merge ?Gene XREF Merged_into Split_from UNIQUE ?Gene XREF Split_into Split_into ?Gene XREF Split_from_parent Live // remove live to make gene "dead" Species ?Species #Gene_history_action Event Created Killed Resurrected Merged_into UNIQUE ?Gene Acquires_merge UNIQUE ?Gene Split_from UNIQUE ?Gene Split_into UNIQUE ?Gene Name_change Name CGC_name UNIQUE Text Sequence_name UNIQUE Text Other_name UNIQUE Text #Evidence Paper ?Paper Person ?Person // RD 020122 made ?Gene_name tag2 to track how name used ?Gene_name Gene Public_name ?Gene CGC_name ?Gene Sequence_name ?Gene Other_name ?Gene ****************************/ #include "acedb.h" #include "lex.h" #include "bs.h" #include "whooks/systags.h" #include "genecurate.h" #include "pick.h" #include "main.h" /* for checkWriteAccess() */ #include "bindex.h" #include "keyset.h" struct GeneConnectionStruct { KEY user ; KEY species ; } ; static int classGene = 0 ; static int classGeneName = 0 ; static int classPerson = 0 ; static char* idFormat = "WB:gn%06d" ; static KEY typeTag[3] ; static void geneCurateInitialise (void) ; static KEY newGene (void) ; static BOOL setPublicName (KEY gene) ; static void updateHistory (KEY gene, KEY user, char* event, KEY target, GeneNameType type, char* name) ; /*************************************************************/ /****** initialise a connection ******************************/ /*************************************************************/ GeneConnection geneConnection (char *host, char* user, KEY species, STORE_HANDLE handle) { GeneConnection gx ; geneCurateInitialise () ; if (!user || !*user) { messerror ("geneConnection() requires a user string") ; return 0 ; } gx = (GeneConnection) halloc(sizeof(struct GeneConnectionStruct), handle) ; lexaddkey (user, &gx->user, classPerson) ; gx->species = species ; return gx ; } /*************************************************************/ /****** primary actions to create, merge, split, kill etc. ***/ /*************************************************************/ KEY geneCreate (GeneConnection gx, GeneNameType type, char* name) { KEY gene, nameKey ; OBJ obj ; if (!gx || !checkWriteAccess ()) return 0 ; if (type > OTHER_NAME) { messerror ("Bad type %d in geneCreate()", type) ; return 0 ; } gene = newGene() ; obj = bsUpdate (gene) ; lexaddkey (name, &nameKey, classGeneName) ; bsAddKey (obj, typeTag[type], nameKey) ; if (gx->species) bsAddKey (obj, str2tag("Species"), gx->species) ; bsAddTag (obj, str2tag("Live")) ; bsSave (obj) ; updateHistory (gene, gx->user, "Created", 0, type, name) ; setPublicName (gene) ; return gene ; } /**************************************************************/ BOOL geneKill (GeneConnection gx, KEY gene) { OBJ obj ; if (!gx || !checkWriteAccess () || class(gene) != classGene || !(obj = bsUpdate(gene))) return FALSE ; if (bsFindTag (obj, str2tag("Live"))) { bsRemove (obj) ; bsSave (obj) ; updateHistory (gene, gx->user, "Killed", 0, 0, 0) ; return TRUE ; } else { bsDestroy (obj) ; return FALSE ; } } /**************************************************************/ BOOL geneResurrect (GeneConnection gx, KEY gene) { OBJ obj ; if (!gx || !checkWriteAccess () || class(gene) != classGene || !(obj = bsUpdate(gene))) return FALSE ; if (bsAddTag (obj, str2tag("Live"))) { bsSave (obj) ; updateHistory (gene, gx->user, "Resurrected", 0, 0, 0) ; return TRUE ; } else { bsDestroy (obj) ; return FALSE ; } } /**************************************************************/ BOOL geneMerge (GeneConnection gx, KEY gene, KEY target) { OBJ obj ; if (!gx || !checkWriteAccess () || class(target) != classGene || !bIndexTag (target, str2tag("Live")) || class(gene) != classGene || !(obj = bsUpdate(gene))) return FALSE ; if (bsFindTag (obj, str2tag("Live"))) { bsRemove (obj) ; bsSave (obj) ; updateHistory (gene, gx->user, "Merged_into", target, 0, 0) ; updateHistory (target, gx->user, "Acquires_merge", gene, 0, 0) ; return TRUE ; } else { bsDestroy (obj) ; return FALSE ; } } /**************************************************************/ KEY geneSplit (GeneConnection gx, KEY gene, GeneNameType type, char *name) { KEY child, nameKey ; OBJ obj ; if (!gx || !checkWriteAccess () || class(gene) != classGene || !bIndexTag (gene, str2tag("Live"))) return FALSE ; if (type > OTHER_NAME) { messerror ("Bad type %d in geneCreate()", type) ; return 0 ; } child = newGene() ; obj = bsUpdate (child) ; lexaddkey (name, &nameKey, classGeneName) ; bsAddKey (obj, typeTag[type], nameKey) ; if (gx->species) bsAddKey (obj, str2tag("Species"), gx->species) ; bsAddTag (obj, str2tag("Live")) ; bsSave (obj) ; updateHistory (child, gx->user, "Split_from", gene, type, name) ; updateHistory (gene, gx->user, "Split_into", child, 0, 0) ; setPublicName (child) ; return child ; } /*************************************************************/ /****** name functions ***************************************/ /*************************************************************/ static KEYSET geneList = 0 ; static GeneNameType lastType ; static char* lastName ; static void makeGeneList (GeneNameType type, char *name) ; int geneNameCount (GeneConnection gx, GeneNameType type, char *name) { if (!gx) return 0 ; if (!lastName || lastType != type || strcmp(lastName, name)) makeGeneList (type, name) ; return keySetMax(geneList) ; } /****************************************/ KEY geneNameGet (GeneConnection gx, GeneNameType type, char *name, int n) { if (!gx) return 0 ; if (!lastName || lastType != type || strcmp(lastName, name)) makeGeneList (type, name) ; if (n >= 0 && n < keySetMax(geneList)) return keySet(geneList, n) ; else return 0 ; } /****************************************/ static void makeGeneList (GeneNameType type, char *name) { KEY geneName ; OBJ obj ; int i ; static Array units = 0 ; geneList = keySetReCreate (geneList) ; if (!lexword2key (name, &geneName, classGeneName) || !(obj = bsCreate (geneName))) return ; units = arrayReCreate (units, 16, BSunit) ; bsGetArray (obj, str2tag("Gene"), units, 2) ; /* tag 2 */ for (i = 1 ; i < arrayMax(units) ; i += 2) keySet(geneList, keySetMax(geneList)) = arr(units, i, BSunit).k ; bsDestroy (obj) ; lastType = type ; if (lastName) messfree (lastName) ; lastName = strnew (name, 0) ; /* local copy */ } /*************************************************************/ /****** a little utility to follow a chain of merges *********/ /*************************************************************/ BOOL geneDescendant (GeneConnection gx, KEY *gene) { OBJ obj = 0 ; while ((obj = bsCreate (*gene))) { if (bsFindTag (obj, str2tag ("Live"))) { bsDestroy (obj) ; return TRUE ; } if (!bsGetKey (obj, str2tag ("Merged_into"), gene)) { bsDestroy (obj) ; return FALSE ; } bsDestroy (obj) ; } return FALSE ; } /*************************************************************/ /****** local functions **************************************/ /*************************************************************/ static void geneCurateInitialise (void) { int isDone = FALSE ; if (isDone) return ; if (!(classGene = pickWord2Class ("Gene"))) messcrash ("No Gene class") ; if (!(classGeneName = pickWord2Class ("Gene_name"))) messcrash ("No Gene_name class") ; if (!(classPerson = pickWord2Class ("Person"))) messcrash ("No Person class") ; typeTag[0] = str2tag("CGC_name") ; typeTag[1] = str2tag("Sequence_name") ; typeTag[2] = str2tag("Other_name") ; isDone = TRUE ; } /*************************************************************/ static KEY newGene (void) { KEY gene ; int n = 0 ; while (!lexaddkey (messprintf (idFormat, ++n), &gene, classGene)) ; return gene ; } /*************************************************************/ static BOOL setPublicName (KEY gene) /* return if name changes */ { OBJ obj = bsUpdate (gene) ; KEY name ; BOOL result = FALSE ; if (!obj) return FALSE ; if (bsGetKey (obj, str2tag("CGC_name"), &name)) result = bsAddKey (obj, str2tag("Public_name"), name) ; else if (bsGetKey (obj, str2tag("Sequence_name"), &name)) result = bsAddKey (obj, str2tag("Public_name"), name) ; else if (bsGetKey (obj, str2tag("Other_name"), &name)) result = bsAddKey (obj, str2tag("Public_name"), name) ; bsSave (obj) ; return result ; } /*************************************************************/ static void updateHistory (KEY gene, KEY user, char* event, KEY target, GeneNameType type, char* newName) { OBJ obj = bsUpdate (gene) ; int version = 0 ; mytime_t time = timeParse ("now") ; if (!obj) return ; bsGetData (obj, str2tag("Version"), _Int, &version) ; ++version ; if (!bsAddData (obj, str2tag("Version"), _Int, &version)) messerror ("updateHistory could not update Version") ; if (bsAddData (obj, str2tag("Version_change"), _Int, &version) && bsAddData (obj, _bsRight, _DateType, &time) && bsAddKey (obj, _bsRight, user) && bsPushObj (obj)) { if (!bsAddTag (obj, str2tag(event))) messerror ("Unknown event %s in updateHistory()", event) ; if (target && !bsAddKey (obj, _bsRight, target)) messerror ("Couldn't add target in updateHistory()", event) ; if (!bsAddData (obj, typeTag[type], _Text, newName)) messerror ("Couldn't add nameType %s in updateHistory()", name(typeTag[type])) ; } else messerror ("updateHistory could not add Version_change") ; if (!strcmp (event, "Merged_into")) bsAddKey (obj, str2tag(event), target) ; else if (!strcmp (event, "Split_from")) bsAddKey (obj, str2tag(event), target) ; /* don't need reciprocals since done by XREF */ bsSave (obj) ; } /********************* end of file ******************/