1   package com.stateofflow.eclipse.metrics.location;
2   
3   public final class MetricLocation implements Comparable<MetricLocation> {
4       public interface Closure {
5           public void execute(MetricLocation location);
6       }
7   
8       private final String packageName;
9       private final NamedLineNumber typeInfo;
10      private final NamedLineNumber methodInfo;
11  
12      MetricLocation(final String packageName, final NamedLineNumber typeInfo, final NamedLineNumber methodInfo) {
13          this.packageName = packageName;
14          this.typeInfo = typeInfo;
15          this.methodInfo = methodInfo;
16      }
17  
18      private int compareMethodInfo(final MetricLocation l2) {
19          if (hasMethod()) {
20              return l2.hasMethod() ? getMethodInfo().compareTo(l2.getMethodInfo()) : 1;
21          } else {
22              return l2.hasMethod() ? -1 : 0;
23          }
24      }
25  
26      private int comparePackageNames(final MetricLocation l2) {
27          return getPackageName().compareTo(l2.getPackageName());
28      }
29  
30      public int compareTo(final MetricLocation that) {
31          int comparison = comparePackageNames(that);
32          if (comparison != 0) {
33              return comparison;
34          }
35  
36          comparison = compareTypes(that);
37          if (comparison != 0) {
38              return comparison;
39          }
40  
41          return compareMethodInfo(that);
42      }
43  
44      private int compareTypes(final MetricLocation l2) {
45          return getTypeInfo().compareTo(l2.getTypeInfo());
46      }
47  
48      public MetricLocation createContainingLocation() {
49          if (hasMethod()) {
50              return new MetricLocation(packageName, typeInfo, null);
51          } else if (hasType()) {
52              return new MetricLocation(packageName, null, null);
53          } else {
54              throw new IllegalStateException("No containing location:" + this);
55          }
56      }
57  
58      @Override
59      public boolean equals(final Object thatObj) {
60          if (thatObj == this) {
61              return true;
62          }
63  
64          if (thatObj == null || !thatObj.getClass().equals(getClass())) {
65              return false;
66          }
67  
68          return equalsMetricLocation((MetricLocation) thatObj);
69      }
70  
71      private boolean equalsMetricLocation(final MetricLocation that) {
72          if (!isSameKindOfLocation(that) || !getPackageName().equals(that.getPackageName())) {
73              return false;
74          }
75  
76          return !hasType() || getTypeInfo().equals(that.getTypeInfo()) && (!hasMethod() || getMethodInfo().equals(that.getMethodInfo()));
77      }
78  
79      public NamedLineNumber getMethodInfo() {
80          if (!hasMethod()) {
81              throw new IllegalStateException("No methodInfo available: " + this);
82          }
83          return methodInfo;
84      }
85  
86      public String getPackageName() {
87          return packageName;
88      }
89  
90      public NamedLineNumber getTypeInfo() {
91          if (!hasType()) {
92              throw new IllegalStateException("No typeInfo available: " + this);
93          }
94          return typeInfo;
95      }
96  
97      @Override
98      public int hashCode() {
99          int hash = packageName.hashCode();
100         if (!hasType()) {
101             return hash;
102         }
103 
104         hash ^= typeInfo.hashCode();
105         if (!hasMethod()) {
106             return hash;
107         }
108 
109         return hash ^ methodInfo.hashCode();
110     }
111 
112     public boolean hasMethod() {
113         return methodInfo != null;
114     }
115 
116     public boolean hasType() {
117         return typeInfo != null;
118     }
119 
120     private boolean isSameKindOfLocation(final MetricLocation that) {
121         return hasType() == that.hasType() && hasMethod() == that.hasMethod();
122     }
123 
124     @Override
125     public String toString() {
126         final StringBuffer sb = new StringBuffer();
127         sb.append("packageName=").append(packageName);
128         sb.append(", type=").append(typeInfo);
129         sb.append(", methodName=").append(methodInfo);
130 
131         return sb.toString();
132     }
133 
134     public String getCompilationUnit() {
135         return getPackageName() + "." + truncateAt(truncateAt(getTypeInfo().getName(), '$'), '.');
136     }
137 
138     private String truncateAt(final String type, final char ch) {
139         return type.indexOf(ch) != -1 ? type.substring(0, type.indexOf(ch)) : type;
140     }
141 }
142