/*>>>>> dups isn't right; need to make an auxillary file of dups values
somehow; maybe read prosite.dat? <<<<*/
/* Interpro Copyright 2000 Fred Hutchinson Cancer Research Center
   Read an Interpro xml file and make .lis files for protomat

   interpro interpro.xml <IPR|all> [-x]
	Extracts sequence information for one or all entries
	Outputs one .lis file for each entry listing all TP/FN
		sequences - can't determine repeats info?

   Interpro entry is assumed to have this format:
	<interpro id="IPR002937"> => AC
	<name>...</name> => DE
	<type>Domain|Family|Repeat</type>
		Take all types, differences are clear
	<memberlist>
	<dbxref db="PROSITE"|"PFAM"|"PRINTS"|"PROFILE" dbkey="ac" name="ID">
		Skip PROFILE, use name from first dbxref as ID 
	<protein sptr_ac="P43164" status="T"|"N"|"F"|"?" start="164" end="188"/>
		Take status="T" or "N"
		Could be multiple entries for same sequence:
			PROSITE => repeated domain; use to estimate dups
			PRINTS => multiple domains
	</dbxref>
	</memberlist>
	<abstract>
		....
	</abstract>
	</interpro>

  Output .lis file has this format:
	>AC ;ID;DE;MOTIFJ=[4,npos=T+N,dups,17];$
	pros/
	sptr_ac		PS=T|N DB=ac,ac,ac...
	...

--------------------------------------------------------------------
 2/ 9/00  J. Henikoff
 2/21/00  Added -x option to just make xref file
 3/27/00  Always make xref if all
 3/30/00  Modifications for Interpro 1.0 format
 4/15/00  Try to fix dups (was always 1 for PROSITE!)
 4/16/00  Write interpro.motifj = motifj parameters
 4/17/00  Change AC from IPR to IPB per Rolf's request
====================================================================*/

#define EXTERN
#define MAXNAME 80	/* Maximum file name length */
#define MINWIDTH 10	/* Minimum block width */
#define MAXWIDTH 55	/* Maximum block width */
#define MAXSEQ 1500	/* Maximum number of sequences */
#define MAXKEY 10	/* Max dbkeys per IPR entry */
#define MAXGROUP 2000	/* Max #lines in repeats.dat */

#include <blocksprogs.h>

int get_iprs();
struct db_id *insert_id();
void free_ids();
int read_repeats();
int get_repeats();

/*  Additional info for a struct db_id sequence */
struct db_extra {
	char dbkey[IDLEN];
	int count;			/* #times seq is in dbkey */
};

struct working {
	char ac[MAXAC+1];
	int num;
} Repeats[MAXGROUP];
int NRepeat, MaxRepeat, All, Xonly;

/*=======================================================================*/
int main(argc, argv)
     int argc;
     char *argv[];
{
   FILE *fip, *fxref;
   char iprfile[MAXNAME], xreffile[MAXNAME], iprname[MAXAC];
   int nipr;

   ErrorLevelReport = 4;	/* BLIMPS error level */

   if (argc < 4)
   {
      printf("INTERPRO: Copyright 2000 Fred Hutchinson Cancer Research");
      printf(" Center\nUSAGE: interpro interpro.xml <IPR|all>\n");
   }
   /* ------------1st arg = interpro.xml  -------------------------------*/
   if (argc > 1)
      strcpy(iprfile, argv[1]);
   else
   {
      printf("\nEnter name of interpro xml file: ");
      gets(iprfile);
   }
   if ( (fip=fopen(iprfile, "r")) == NULL)
   {
      printf("\nCannot open file %s\n", iprfile);
      exit(-1);
   }

   /* ------------2nd arg = entry number -----------------------------------*/
   if (argc > 2)
      strcpy(iprname, argv[2]);
   else
   {
      printf("\nEnter name of interpro entry or all : ");
      gets(iprname);
   }
   if (!strlen(iprname)) strcpy(iprname, "all");
   All = NO;
   if (strcmp(iprname, "all") == 0) All = YES;

   /* ------------3rd arg optionally == -x for xref file only---------------*/
   fxref = NULL; Xonly = NO;
   if (argc > 3 && (strncmp(argv[3], "-x", 2) == 0) )
   {
      Xonly = YES;
   }
   if (Xonly || All)
   {
      strcpy(xreffile, iprfile);
      strcat(xreffile, ".xref");
      fxref = fopen(xreffile, "w");
   }

   /*----------------------------------------------------------------------*/
   NRepeat = read_repeats();		/* repeats.dat in current dir */
   nipr = get_iprs(fip, fxref, iprname);
   fclose(fip);
   printf("%d entries processed from %s\n", nipr, iprname);
   exit(0);
}  /* end of main */

/*========================================================================
========================================================================*/
int get_iprs(fip, fxref, iprname)
FILE *fip, *fxref;
char iprname[MAXNAME];
{
   FILE *flis, *fmot;
   char line[MAXLINE], ac[MAXNAME], id[MAXNAME], de[MAXLINE], *ptr, *ptr1;
   char ctemp[MAXLINE], ctemp1[MAXNAME], fname[MAXNAME], status[MAXNAME];
   char db[MAXKEY+1][MAXNAME], dbkey[MAXKEY+1][MAXNAME];
   struct db_id *ids, *did;
   int i, ndb, maxdb, nipr, nac, nseq, occurs, dups, reps, done, member_flag;
   int maxrep, firstps, nseqps;

   fmot = fopen("interpro.motifj", "w");
   ids = makedbid();
   nipr = nac = nseq = nseqps = firstps = occurs = 0;
   done = NO;
   ac[0] = id[0] = de[0] = '\0';

   /*=====================================================================*/
   while (!done && !feof(fip) && fgets(line, MAXLINE, fip) != NULL)
   {
      if (strstr(line, "<interpro ") != NULL)
      {    
         /*  <interpro id="IPR002937">\n  */
         nipr++;
         nseq = nseqps = occurs = firstps = ndb = 0;
         member_flag = NO;
         ptr = strtok(line, "\"");
         if (ptr != NULL)
         {
            ptr = strtok(NULL, "\"");
            if (ptr != NULL)
            { 
               strcpy(ac, ptr);
		/* change IPR to IPB */
	       if (strlen(ac) > 3 && ac[2] == 'R') ac[2] = 'B';
               nac++; ndb = 0;
               member_flag = NO;
               if (fxref != NULL)
               {
                  fprintf(fxref, "%s", ac);
               }
               if (strlen(ac) > MAXAC-1) ac[MAXAC-1] = '\0';
               if ( All || (strcmp(iprname, ac) == 0) )
               {
	          sprintf(fname, "%s.lis", ac);
                  flis = fopen(fname, "w");
               }
            }
            else printf("ERROR no ac found");
         }

         while (!done && !feof(fip) && fgets(line, MAXLINE, fip) != NULL &&
                 strstr(line, "</interpro>") == NULL )
         {
            if (strstr(line, "<name>") != NULL)
            {
               strcpy(de, ac);
               ptr = strtok(line, "> \t\r\n");
               if (ptr != NULL)
               {
                  ptr = strtok(NULL, "<\t\r\n");
                  if (ptr != NULL) { strcpy(de, ptr); }
                  else  /* look for name on next line  (e.g. IPR002128) */
                  {
printf("%s:  <name> not found\n", ac);
                  }
               }
            }

            /*-------------Database---------------------------------*/
            
            if ( (strstr(line, "<memberlist>") != NULL) )
                   member_flag = YES;
            if ( (strstr(line, "</memberlist>") != NULL) )
                   member_flag = NO;

      /* <dbxref db="PROSITE"|"PFAM"|"PRINTS"|"PROFILE|PREFILE" 
		dbkey="ac" name="ID"> */
            if ( member_flag && (strstr(line, "<dbxref") != NULL) )
            {
              /*  Some <dbkey entries have no sequences and end with /> */
              /*  Don't use PROFILE or PREFILE, not reliable  */
              if( (strstr(line, "/") == NULL) &&
                  (strstr(line, "PROSITE") != NULL ||
                   strstr(line, "PRINTS")  != NULL ||
                   strstr(line, "PFAM")    != NULL) )
              {
	       /*  Flag first PROSITE entry, will use it to count dups */
               if (strstr(line, "PROSITE") != NULL)
	       {
			if (!firstps) firstps = 1;
			else firstps = 0;
               }
	       else { firstps = 0; }
               strcpy(ctemp, line);
               ptr = strstr(line, "db=");
               if (ptr != NULL)
               {
                  ptr1 = strtok(ptr,"\"");
                  ptr1 = strtok(NULL,"\"");
                  strcpy(db[ndb], ptr1);
               }
               strcpy(line, ctemp);
               ptr = strstr(line, "dbkey=");
               if (ptr != NULL)
               {
                  ptr1 = strtok(ptr,"\"");
                  ptr1 = strtok(NULL,"\"");
                  strcpy(dbkey[ndb], ptr1);
               }
               ptr = strstr(ctemp, "name=");
               if (ptr != NULL)
               {
                  ptr1 = strtok(ptr,"\"");
                  ptr1 = strtok(NULL,"\"");
                  strcpy(id, ptr1);
               }

               /*--------Sequences for Database--------------------------*/
               /*---A sequence may exist multiple times for same dbxref--*/
/*>>>> sometimes there is no </dbxref>; need to stop if hit
   <dbref> or </memberlist>    <<<<*/
               while ( !feof(fip) && fgets(line, MAXLINE, fip) != NULL &&
                       strstr(line, "</dbxref>") == NULL )
               {
                  if (strstr(line, "<protein") != NULL)
                  {
                     strcpy(ctemp, line);
                     ptr = strstr(line, "status=");
                     if (ptr != NULL)
                     {
                        ptr1 = strtok(ptr,"\"");
                        ptr1 = strtok(NULL,"\"");
                        strcpy(status, ptr1);
                     }
                     if (status[0] == 'T' || status[0] == 'N')
                     {
                        ptr = strstr(ctemp, "sptr_ac=");
                        if (ptr != NULL)
                        {
                           ptr1 = strtok(ptr,"\"");
                           ptr1 = strtok(NULL,"\"");
                           /*- Won't insert if there from previous dbxref -*/
                           did = insert_id(ptr1, ids);
                           if (did != NULL)
                           {
			      if (firstps) occurs++;
                              if (!did->found)  /* new seq for ac */
                              {
                                 nseq++;
				 if (firstps) nseqps++;
                                 strcpy(did->ps, status);
                                 sprintf(did->info, "%s", dbkey[ndb]);
                                 did->found = YES;
				 did->rank = 1;		/* # of dbkeys */
				 did->score = 0;	/* reps */
                              }
                              else   /* existing seq for ac */
                              {
                                 strcpy(ctemp1, did->info);
                                 if (strstr(ctemp1, dbkey[ndb]) == NULL)
                                 {
                                    sprintf(ctemp1, " %s", dbkey[ndb]);
                                    strcat(did->info, ctemp1);
				    did->rank += 1;	/* # of dbkeys */
                                 }
                              }
/*>>> need to increment did->score = PROSITE repeats here; not so
	easy because there may be multiple PROSITE entries 
        assuming if there is a PROSITE, it's first   
>>>*/
                              if ( (strcmp(db[0], "PROSITE") == 0) &&
				   (strcmp(dbkey[0], dbkey[ndb]) == 0) )
                              {
           			   did->score += 1;   /* maxrep */
                              }
                                 
                           }  /* end of did */
                        }
                     }
                  }
               }  /* end of sequences for dbxref */ 

               if (ndb < MAXKEY) ndb++;
               else printf("Too many dbxref entries for %s\n", ac);
             }
             else
             {
               printf("Skipping %s %s", ac, line);
               while ( !feof(fip) && fgets(line, MAXLINE, fip) != NULL &&
                       strstr(line, "</dbxref>") == NULL &&
                       strstr(line, "</memberlist>") == NULL )
                                ;
             }
            }  /*  end of dbxref   */

         }  /* end of interpro */

         /*-------------Repeats from PROSITE-----------*/
         maxrep = 1; maxdb = 0;
         did = ids->next;
         while (did != NULL)
         {
            if ( did->score > maxrep )  maxrep = did->score;
	    if (did->rank > maxdb) maxdb = did->rank;
            did = did->next;
         }
         /*------------Repeats from repeats.dat---------------------*/
         if (NRepeat > 0)
         {
            for (i=0; i<ndb; i++)
            {
               reps = get_repeats(dbkey[i]);
               if (reps >= 0 && (reps+1) < maxrep) maxrep = reps+1;
            }
         }

         /*--------------Output the results---------------------------*/
         dups = occurs - nseq;
	 if (dups < 0) dups = 0;
         if (flis != NULL)
         {
            fprintf(flis, ">%s ;%s;%s;MOTIFJ=[4,%d,%d,17];$\n", 
                 ac, id, de, nseq, dups);
            fprintf(flis, "pros/\n");
            did = ids->next;
            while (did != NULL)
            {
/*  Only print sequences that are true for all dbxrefs 
               if (did->rank == ndb)
*/
               fprintf(flis, "%s\tPS=%s %s\n", did->entry, did->ps, did->info);
               did = did->next;
            }
            fclose(flis);
         }
         free_ids(ids);
         if (fmot != NULL)
         {  fprintf(fmot, "%s %d %d %d\n", ac, nseq, dups, maxrep);  }
         if (fxref != NULL)
         {
            for (i=0; i < ndb; i++) fprintf(fxref, " %s", dbkey[i]);
            fprintf(fxref, " %d %d\n", maxrep, dups);
         }

      }   /*  end of <interpro> */

   }   /*  end of fip  */

   fclose(fmot);
   return(nipr);

}  /* end of get_iprs */
/*==========================================================================
 Insert a new sequence in the list of sequences if it's not already there
 The list is sorted by entry (sequence name)
===========================================================================*/
struct db_id *insert_id(seqname, ids)
char seqname[MAXNAME];
struct db_id *ids;
{
   struct db_id *did, *new, *last;
   int insert;

   insert = YES;
   last = ids;
   did = ids->next;
   while (insert && did != NULL && strlen(did->entry) &&
          strcmp(did->entry, seqname) <= 0)
   {
      if (strcmp(seqname, did->entry) == 0)
      {
          insert = NO;
          return(did);
      }
      last = did;
      did = did->next;
   }
   if (insert)
   {
      new = makedbid();
      strcpy(new->entry, seqname);
      new->found = NO;		/* flag => new id */
      /*  insert new in front of did  */
      new->next = did;
      last->next = new;
      if (did != NULL)
      {
         new->prior = did->prior;
         did->prior = new;
      }
      return(new);
   }
   else
   {     return(NULL);    }

}  /* end of insert_id */
/*====================================================================================*/
void free_ids(ids)
struct db_id *ids;
{
   struct db_id *did, *old;

   did = ids->next;
   while (did != NULL)
   {
      old = did;
      did = did->next;
      free(old);
   }
   ids->next = ids->prior = NULL;
} /* end of free_ids  */

/*======================================================================
	Read the repeats.dat file
======================================================================*/
int read_repeats()
{
   int nrep;
   FILE *frep;
   char line[MAXLINE] ;

   nrep = 0;
   MaxRepeat = 0;

   /*   Look in current directory first */
   frep=fopen("repeats.dat", "r");
/*
   if (frep == NULL)
   {
      sprintf(fname, "%srepeats.dat", DatDir);
      frep=fopen(fname, "r");
   }
*/

   if (frep != NULL)
   {
      while (nrep < MAXGROUP && 
             !feof(frep) && fgets(line, MAXLINE, frep) != NULL)
      {
         if (line[0] != '>' && line[0] != '#')
         {
            sscanf(line, "%s %d", Repeats[nrep].ac, &Repeats[nrep].num);
            if (Repeats[nrep].num < 0) Repeats[nrep].num = 0;
            if (Repeats[nrep].num > MaxRepeat) MaxRepeat = Repeats[nrep].num;
            nrep++;
         }
      }
   }
   return(nrep);
}  /* end of read_repeats */
/*=========================================================================
	Look up number of repeats for ac     
	Assuming that absence => no repeats
==========================================================================*/
int get_repeats(fam)
char *fam;
{
   int j;

   j = 0;
   /*   Assumes repeats.dat is sorted by ac     */
   while (j < NRepeat && strcmp(Repeats[j].ac, fam) <= 0) j++;
   if (j > 0 && strcmp(Repeats[j-1].ac, fam) == 0)
	return(Repeats[j-1].num);
   else return(0);
} /* end of get_repeats  */
