1   package eu.fbk.dkm.pikes.resources.mpqa;
2   
3   import com.google.common.base.Joiner;
4   import com.google.common.collect.Lists;
5   import com.google.common.collect.Maps;
6   import com.google.common.collect.Ordering;
7   import org.slf4j.Logger;
8   import org.slf4j.LoggerFactory;
9   
10  import javax.annotation.Nullable;
11  import java.util.Arrays;
12  import java.util.List;
13  import java.util.Map;
14  import java.util.Objects;
15  import java.util.regex.Matcher;
16  import java.util.regex.Pattern;
17  
18  /**
19   * Created by alessio on 24/03/15.
20   */
21  public final class Record {
22  
23      private final String line;
24  
25      private final Span span;
26  
27      private final String name;
28  
29      private final String value;
30  
31      private final Map<String, String> valueMap;
32  
33      private static Pattern attribPatt = Pattern.compile("^\\s*[a-zA-Z0-9_-]+=");
34      private static Pattern endPatt = Pattern.compile("^\\s*$");
35      private static final Logger LOGGER = LoggerFactory.getLogger(Record.class);
36  
37      public Record(final String line) {
38  
39          final String[] tokens = line.trim().split("\t");
40  
41          this.line = line;
42          this.span = new Span(tokens[1]);
43          this.name = tokens[3].trim();
44          this.value = tokens.length < 5 ? "" : Joiner.on(" ").join(
45                  Arrays.asList(tokens).subList(4, tokens.length));
46          this.valueMap = Maps.newHashMap();
47  
48          final List<String> entries = Lists.newArrayList();
49          int start = -1;
50          boolean insideQuote = false;
51          for (int i = 0; i < this.value.length(); ++i) {
52              final char c = this.value.charAt(i);
53              if (insideQuote) {
54                  if (c == '\"') {
55                      final String fromNow = this.value.substring(i + 1);
56                      final Matcher attribMatcher = attribPatt.matcher(fromNow);
57                      final Matcher endMatcher = endPatt.matcher(fromNow);
58                      if (attribMatcher.find() || endMatcher.find()) {
59                          insideQuote = false;
60                      }
61                  }
62              } else {
63                  if (c == '\"') {
64                      insideQuote = true;
65                  } else if (start >= 0 && Character.isWhitespace(c)) {
66                      entries.add(this.value.substring(start, i));
67                      start = -1;
68                  } else if (start < 0) {
69                      start = i;
70                  }
71              }
72          }
73          if (start >= 0) {
74              entries.add(this.value.substring(start));
75          }
76  
77          for (final String entry : entries) {
78              final int index = entry.indexOf("=");
79              if (index >= 0) {
80                  final String key = entry.substring(0, index).trim();
81                  String value = entry.substring(index + 1).trim();
82                  if (value.startsWith("\"") && value.endsWith("\"")) {
83                      value = value.substring(1, value.length() - 1);
84                  }
85                  this.valueMap.put(key, value);
86              }
87          }
88      }
89  
90      public Span getSpan() {
91          return this.span;
92      }
93  
94      public String getName() {
95          return this.name;
96      }
97  
98      public String getValue() {
99          return this.value;
100     }
101 
102     public Map<String, String> getValueMap() {
103         return this.valueMap;
104     }
105 
106     @Nullable
107     public String getValue(final String key) {
108         return this.valueMap.get(key);
109     }
110 
111     //
112     // public Map<String, String> getValueMap() {
113     // return this.valueMap;
114     // }
115 
116     @Override
117     public boolean equals(final Object object) {
118         if (object == this) {
119             return true;
120         }
121         if (!(object instanceof Record)) {
122             return false;
123         }
124         final Record other = (Record) object;
125         return this.span.equals(other.span) && this.name.equals(other.name);
126     }
127 
128     @Override
129     public int hashCode() {
130         return Objects.hash(this.span, this.name);
131     }
132 
133     @Override
134     public String toString() {
135         return this.line;
136     }
137 
138     public static Ordering<Record> comparator(final String attribute) {
139         return new Ordering<Record>() {
140 
141             @Override
142             public int compare(final Record left, final Record right) {
143                 final String leftValue = left.getValue(attribute);
144                 final String rightValue = right.getValue(attribute);
145                 int result = Ordering.natural().nullsLast().compare(leftValue, rightValue);
146                 if (result == 0) {
147                     result = left.getSpan().compareTo(right.getSpan());
148                     if (result == 0) {
149                         result = left.getName().compareTo(right.getName());
150                     }
151                 }
152                 return result;
153             }
154 
155         };
156     }
157 
158 }