Merge branch 'develop' of https://source.jalview.org/git/jalview.git into develop
[jalview.git] / src / jalview / util / DnaUtils.java
1 package jalview.util;
2
3 import java.util.ArrayList;
4 import java.util.Collections;
5 import java.util.List;
6
7 public class DnaUtils
8 {
9
10   /**
11    * Parses an ENA/GenBank format location specifier and returns a list of
12    * [start, end] ranges. Returns null if not able to parse.
13    * 
14    * @param location
15    * @return
16    * @see http://www.insdc.org/files/feature_table.html#3.4
17    */
18   public static List<int[]> parseLocation(String location)
19   {
20     if (location.startsWith("join("))
21     {
22       return parseJoin(location);
23     }
24     else if (location.startsWith("complement("))
25     {
26       return parseComplement(location);
27     }
28     String errorMessage = "Unable to process location specifier: "
29             + location;
30     if (location.startsWith("order("))
31     {
32       System.err.println(errorMessage);
33       return null;
34     }
35
36     /*
37      * try to parse m..n (or simply m)
38      */
39     String[] range = location.split("\\.\\.");
40     if (range.length == 1 || range.length == 2)
41     {
42       try
43       {
44         int start = Integer.valueOf(range[0]);
45         int end = range.length == 1 ? start : Integer.valueOf(range[1]);
46         return Collections.singletonList(new int[] { start, end });
47       } catch (NumberFormatException e)
48       {
49         /*
50          * could be a location like <1..888 or 1..>888
51          */
52         System.err.println(errorMessage);
53         return null;
54       }
55     }
56     else
57     {
58       /*
59        * could be a location like 102.110 or 123^124
60        */
61       System.err.println(errorMessage);
62       return null;
63     }
64   }
65
66   /**
67    * Parses a complement(locationSpec) into a list of start-end ranges
68    * 
69    * @param location
70    * @return
71    */
72   static List<int[]> parseComplement(String location)
73   {
74     /*
75      * take what is inside complement()
76      */
77     if (!location.endsWith(")"))
78     {
79       return null;
80     }
81     String toComplement = location.substring("complement(".length(),
82             location.length() - 1);
83     List<int[]> ranges = parseLocation(toComplement);
84     if (ranges == null)
85     {
86       /*
87        * something bad in there
88        */
89       return null;
90     }
91
92     /*
93      * reverse the order and direction of ranges
94      */
95     Collections.reverse(ranges);
96     for (int[] range : ranges)
97     {
98       int temp = range[0];
99       range[0] = range[1];
100       range[1] = temp;
101     }
102     return ranges;
103   }
104
105   /**
106    * Parses a join(loc1,loc2,...,locn) into a list of start-end ranges
107    * 
108    * @param location
109    * @return
110    */
111   static List<int[]> parseJoin(String location)
112   {
113     List<int[]> ranges = new ArrayList<int[]>();
114
115     /*
116      * take what is inside join()
117      */
118     if (!location.endsWith(")"))
119     {
120       return null;
121     }
122     String joinedLocs = location.substring("join(".length(),
123             location.length() - 1);
124     String[] locations = joinedLocs.split(",");
125     for (String loc : locations)
126     {
127       List<int[]> range = parseLocation(loc);
128       if (range == null)
129       {
130         /*
131          * something bad in there
132          */
133         return null;
134       }
135       else
136       {
137         ranges.addAll(range);
138       }
139     }
140     return ranges;
141   }
142
143 }