JAL-2136 New Phyre2 branch + attempt to resynced with develop
[jalview.git] / src / jalview / io / AnnotationFile.java
index c3e71da..49e99a1 100755 (executable)
@@ -26,17 +26,23 @@ import jalview.datamodel.AlignmentAnnotation;
 import jalview.datamodel.AlignmentI;
 import jalview.datamodel.Annotation;
 import jalview.datamodel.ColumnSelection;
+import jalview.datamodel.DynamicData;
+import jalview.datamodel.DynamicData.DataType;
 import jalview.datamodel.GraphLine;
 import jalview.datamodel.HiddenColumns;
 import jalview.datamodel.HiddenSequences;
+import jalview.datamodel.PDBEntry;
+import jalview.datamodel.PDBEntry.Type;
 import jalview.datamodel.SequenceGroup;
 import jalview.datamodel.SequenceI;
 import jalview.schemes.ColourSchemeI;
 import jalview.schemes.ColourSchemeProperty;
+import jalview.structure.StructureSelectionManager;
 import jalview.util.ColorUtils;
 
 import java.awt.Color;
 import java.io.BufferedReader;
+import java.io.File;
 import java.io.FileReader;
 import java.io.InputStreamReader;
 import java.io.StringReader;
@@ -52,6 +58,28 @@ import java.util.Vector;
 
 public class AnnotationFile
 {
+  StringBuffer text;
+
+  SequenceI refSeq = null;
+
+  String refSeqId = null;
+
+  String[] StructModelHeader = null;
+
+  long nlinesread = 0;
+
+  String lastread = "";
+
+  /**
+   * used for resolving absolute references to resources relative to
+   * annotationFile location
+   */
+  String baseUri = "";
+
+  private static String GRAPHLINE = "GRAPHLINE", COMBINE = "COMBINE",
+          STRUCTMODEL = "STRUCTMODEL",
+          HEADER_STRUCT_MODEL = "HEADER_STRUCT_MODEL";
+
   public AnnotationFile()
   {
     init();
@@ -78,7 +106,6 @@ public class AnnotationFile
     return newline;
   }
 
-  StringBuffer text;
 
   private void init()
   {
@@ -658,9 +685,6 @@ public class AnnotationFile
     }
   }
 
-  SequenceI refSeq = null;
-
-  String refSeqId = null;
 
   public boolean annotateAlignmentView(AlignViewportI viewport,
           String file, DataSourceType protocol)
@@ -695,21 +719,41 @@ public class AnnotationFile
   public boolean readAnnotationFile(AlignmentI al, HiddenColumns hidden,
           String file, DataSourceType sourceType)
   {
+    baseUri = "";
     BufferedReader in = null;
     try
     {
       if (sourceType == DataSourceType.FILE)
       {
         in = new BufferedReader(new FileReader(file));
+        baseUri = new File(file).getParent();
+        if (baseUri == null)
+        {
+          baseUri = "";
+        }
+        else
+        {
+          baseUri += "/";
+        }
       }
       else if (sourceType == DataSourceType.URL)
       {
         URL url = new URL(file);
         in = new BufferedReader(new InputStreamReader(url.openStream()));
+        String bs = url.toExternalForm();
+        baseUri = bs.substring(0, bs.indexOf(url.getHost())
+                + url.getHost().length());
+        baseUri += url.toURI().getPath();
+        if (baseUri.lastIndexOf("/") > -1)
+        {
+          baseUri = baseUri.substring(0, baseUri.lastIndexOf("/")) + "/";
+        }
       }
       else if (sourceType == DataSourceType.PASTE)
       {
         in = new BufferedReader(new StringReader(file));
+        // TODO - support mimencoded PDBs for a paste.. ?
+        baseUri = "";
       }
       else if (sourceType == DataSourceType.CLASSLOADER)
       {
@@ -717,6 +761,8 @@ public class AnnotationFile
         if (is != null)
         {
           in = new BufferedReader(new java.io.InputStreamReader(is));
+          // TODO: this probably doesn't work for classloader - needs a test
+          baseUri = new File("/" + file).getParent() + "/";
         }
       }
       if (in != null)
@@ -738,11 +784,6 @@ public class AnnotationFile
     return false;
   }
 
-  long nlinesread = 0;
-
-  String lastread = "";
-
-  private static String GRAPHLINE = "GRAPHLINE", COMBINE = "COMBINE";
 
   public boolean parseAnnotationFrom(AlignmentI al, HiddenColumns hidden,
           BufferedReader in) throws Exception
@@ -936,12 +977,6 @@ public class AnnotationFile
           modified = true;
           continue;
         }
-        // else if (token.equalsIgnoreCase("VIEW_DEF"))
-        // {
-        // addOrSetView(al,st);
-        // modified = true;
-        // continue;
-        // }
         else if (token.equalsIgnoreCase("VIEW_SETREF"))
         {
           if (refSeq != null)
@@ -988,7 +1023,58 @@ public class AnnotationFile
           modified = true;
           continue;
         }
-
+        else if (token.equalsIgnoreCase(HEADER_STRUCT_MODEL))
+        {
+          int hSize = st.countTokens();
+          StructModelHeader = new String[hSize];
+          for (int x = 0; x < hSize; x++)
+          {
+            StructModelHeader[x] = st.nextToken();
+          }
+          continue;
+        }
+        else if (token.equalsIgnoreCase(STRUCTMODEL))
+        {
+          boolean failedtoadd = true;
+          // expects STRUCTMODEL <Query> <TemplateSeqId> <ModelFile>
+          // <FastaMappingFile>
+          String querySeqId = !st.hasMoreTokens() ? "" : st.nextToken();
+          SequenceI querySeq = al.findName(querySeqId);
+          if (st.hasMoreTokens()) {
+            refSeq = al.findName(refSeqId = st.nextToken());
+            if (refSeq == null)
+            {
+              System.err.println("Couldn't locate " + refSeqId
+                      + " in the alignment for STRUCTMODEL");
+              refSeqId = null;
+            }
+            else
+            {
+              int tSize = st.countTokens() + 2;
+              String[] rowData = new String[tSize];
+              rowData[0] = querySeqId;
+              rowData[1] = refSeqId;
+              for (int x = 2; x < tSize; x++)
+              {
+                rowData[x] = st.nextToken();
+              }
+              if (processStructModel(al, querySeq, refSeq,
+                      StructModelHeader, rowData, baseUri))
+              {
+                failedtoadd = false;
+              }
+            }
+          }
+          if (failedtoadd)
+          {
+            System.err
+                    .println("Need minimum of <Query> <TemplateSeqId> <ModelFile> <FastaMappingFile> as tab separated fields after"
+                            + STRUCTMODEL);
+          } else {
+            modified = true;
+          }
+          continue;
+        }
         // Parse out the annotation row
         graphStyle = AlignmentAnnotation.getGraphValueFromString(token);
         label = st.nextToken();
@@ -1188,6 +1274,100 @@ public class AnnotationFile
     return modified;
   }
 
+
+  /**
+   * Resolve structural model to a reference sequence and register it to
+   * StructureSelectionManager
+   * 
+   * @param al
+   * @param querySequence
+   * @param templateSeq
+   * @param structModelHeader
+   * @param structModelData
+   * @return true if model and sequence was added
+   */
+  static boolean processStructModel(AlignmentI al, SequenceI querySequence,
+          SequenceI templateSeq,
+ String[] structModelHeader,
+          String[] structModelData, String baseUri)
+  {
+    String warningMessage = null;
+    boolean added = false;
+    try {
+      String structureModelFile = resolveAbsolutePath(structModelData[2],
+              baseUri);
+      String fastaMappingFile = resolveAbsolutePath(structModelData[3],
+              baseUri);
+      // System.out.println("Model File >> " + structureModelFile);
+      // System.out.println("Fasta File >> " + fastaMappingFile);
+      String modelName = StructureFile.safeName(structureModelFile);
+      PDBEntry phyre2PDBEntry = new PDBEntry(modelName, " ",
+              Type.PDB,
+              structureModelFile);
+      List<DynamicData> phyreDD = generatePhyreDynamicDataList(
+              structModelHeader, structModelData);
+      phyre2PDBEntry.setProperty("DYNAMIC_DATA_PHYRE2", phyreDD);
+      templateSeq.getDatasetSequence().addPDBId(phyre2PDBEntry);
+      if (querySequence != null)
+      {
+        querySequence.getDatasetSequence().addPDBId(phyre2PDBEntry);
+      }
+      StructureSelectionManager ssm = StructureSelectionManager
+              .getStructureSelectionManager();
+      ssm.registerPhyre2Template(structureModelFile, fastaMappingFile);
+      added = true;
+
+    } catch (Exception x)
+    {
+      warningMessage = x.toString();
+    } finally {
+      if (warningMessage !=null)
+      {
+        System.err.println("Warnings whilst processing STRUCTMODEL: "+warningMessage);
+      }
+    }
+    return added;
+  }
+
+  static List<DynamicData> generatePhyreDynamicDataList(
+          String[] headerArray,
+          String[] dataArray)
+  {
+
+    if (headerArray == null || dataArray == null)
+    {
+      throw new IllegalArgumentException(
+              "Header or data arrays must not be null");
+    }
+
+    if (headerArray.length != dataArray.length)
+    {
+      throw new IllegalArgumentException(
+              "Header and data arrays must be of same lenght");
+    }
+    List<DynamicData> dynamicDataList = new ArrayList<DynamicData>();
+    int x = 0;
+    for (String data : dataArray)
+    {
+      // first four column should be hidden;
+      boolean show = (x > 4);
+      dynamicDataList.add(new DynamicData(headerArray[x], data, DataType.S,
+              "PHYRE2", show));
+      x++;
+    }
+    return dynamicDataList;
+  }
+
+  static String resolveAbsolutePath(String relURI, String _baseUri)
+  {
+    if (relURI.indexOf(":/") > -1 || relURI.startsWith("/")
+            || "".equals(_baseUri) || relURI.startsWith(_baseUri))
+    {
+      return relURI;
+    }
+    return _baseUri + relURI;
+  }
+
   private void parseHideCols(HiddenColumns hidden, String nextToken)
   {
     StringTokenizer inval = new StringTokenizer(nextToken, ",");