diff --git a/build.xml b/build.xml
new file mode 100644
index 0000000..eb290f0
--- /dev/null
+++ b/build.xml
@@ -0,0 +1,44 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/main/com/jdbernard/timeanalyzer/Category.groovy b/src/main/com/jdbernard/timeanalyzer/Category.groovy
index d6e49ac..04cc445 100644
--- a/src/main/com/jdbernard/timeanalyzer/Category.groovy
+++ b/src/main/com/jdbernard/timeanalyzer/Category.groovy
@@ -1,15 +1,79 @@
package com.jdbernard.timeanalyzer
-public abstract class Category implements Comparable {
+import org.joda.time.Duration
+
+/**
+ * A category represents a collection of like events.
+ */
+public abstract class Category implements Comparable {
List entries
+ List categories
+ String description
+
+ public Category() {
+ entries = []
+ categories = []
+ description = "Unnamed Category"
+ }
public abstract boolean matchesEvent(Event e)
- public abstract Entry addEvent(Event e)
- public Category() { entries = [] }
+ public Entry addEvent(Event e) {
+ Entry entry
- public int compareTo(C other) {
+ // see if we have a subcategory that will hold this event
+ entry = addToSubCategory(e)
+ if (!entry) {
+ // if not, do we have another entry that could be grouped with
+ // this one to create a new category, based on the description?
+ def existingEntry = entries.find
+ { it.description == e.description }
+
+ // yes
+ if (existingEntry) {
+ // create the new category
+ category = new DescriptionBasedCategory(e.description)
+
+ // remove the existing entry from this category and
+ // add it to the subcategory
+ this.entries -= existingEntry
+ category.entries << existingEntry
+
+ // add the new event to the category
+ entry = category.addEvent(e)
+
+ // add the category to our list of subcategories
+ categories << category
+ }
+
+ // no, let's create a generic entry and add it
+ else {
+ entry = new Entry(this, e)
+ entries << entry
+ }
+ }
+
+ return entry
}
+
+ public Entry addToSubcategory(Event e) {
+
+ // find all matching subcategories
+ def matchingCategories = categories.findAll { it.matchesEvent(e) }
+
+ if (matchingCategories)
+ return matchingCategories[0].addEvent(e)
+ return null
+ }
+
+ public Duration getDuration() {
+ return categories.sum { it.duration } + entries.sum { it.duration }
+ }
+
+ public int compareTo(Category other) {
+ return this.getDuration().compareTo(other.getDuration())
+ }
+
}
diff --git a/src/main/com/jdbernard/timeanalyzer/DescriptionBasedCategory.groovy b/src/main/com/jdbernard/timeanalyzer/DescriptionBasedCategory.groovy
new file mode 100644
index 0000000..64675f1
--- /dev/null
+++ b/src/main/com/jdbernard/timeanalyzer/DescriptionBasedCategory.groovy
@@ -0,0 +1,16 @@
+package com.jdbernard.timeanalyzer
+
+import org.joda.time.Duration
+
+public class DescriptionBasedCategory extends Category {
+
+ public DescriptionBasedCategory(String description) {
+ super()
+ this.description = description
+ }
+
+ public boolean matchesEvent(Event e) {
+ return e.description == description
+ }
+
+}
diff --git a/src/main/com/jdbernard/timeanalyzer/Entry.java b/src/main/com/jdbernard/timeanalyzer/Entry.java
index ce20f00..f56ae13 100644
--- a/src/main/com/jdbernard/timeanalyzer/Entry.java
+++ b/src/main/com/jdbernard/timeanalyzer/Entry.java
@@ -1,6 +1,32 @@
-package com.jdbernard.timanalyzer;
+package com.jdbernard.timeanalyzer;
-public class Entry extends Event {
+import org.joda.time.DateTime;
+import org.joda.time.Duration;
+public class Entry {
+
+ public String description;
+ public String notes;
+ public DateTime start;
+ public Duration duration;
public Category category;
+
+ public Entry(Category c, String description, DateTime start,
+ Duration duration) {
+ this(c, description, "", start, duration);
+ }
+
+ public Entry(Category c, Event e) {
+ this(c, e.description, e.notes, e.start, e.duration);
+ }
+
+ public Entry(Category c, String description, String notes, DateTime start,
+ Duration duration) {
+ this.description = description;
+ this.notes = notes;
+ this.start = start;
+ this.duration = duration;
+ this.category = category;
+ }
+
}
diff --git a/src/main/com/jdbernard/timeanalyzer/EventTransformation.java b/src/main/com/jdbernard/timeanalyzer/EventTransformation.java
deleted file mode 100644
index 3320dce..0000000
--- a/src/main/com/jdbernard/timeanalyzer/EventTransformation.java
+++ /dev/null
@@ -1,25 +0,0 @@
-package com.jdbernard.timeanalyzer;
-
-public abstract class EventTransformation {
-
- private Category category;
-
- public EventTransformation(Category cat) {
- this.category = cat;
- }
-
- /**
- * Determine if this transformation is applicable for a given event.
- * @param e An event to match.
- * @return *true* if this transformation is applicable to the given event,
- * *false* otherwise.
- */
- public abstract boolean matches(Event e);
-
- /**
- * Transform an entry.
- * @param e The Event to transform.
- * @return A new Entry.
- */
- public abstract Entry transform(Event e);
-}
diff --git a/src/main/com/jdbernard/timeanalyzer/EventTransformer.groovy b/src/main/com/jdbernard/timeanalyzer/EventTransformer.groovy
deleted file mode 100644
index bb1d174..0000000
--- a/src/main/com/jdbernard/timeanalyzer/EventTransformer.groovy
+++ /dev/null
@@ -1,21 +0,0 @@
-package com.jdbernard.timeanalyzer
-
-public class EventTransformer {
-
- List transformations
-
- public EventTransformer(List transformations) {
- this.transformations = transformations
- }
-
- /**
- * Transform an event. The first matching transformation is used.
- * @param e The event to transform.
- * @return The resulting Entry.
- */
- public Entry transform(Event e) {
- for (t : transformations)
- if (t.matches(e))
- return t.transform(t)
- }
-}
diff --git a/src/main/com/jdbernard/timeanalyzer/GeneralCategory.groovy b/src/main/com/jdbernard/timeanalyzer/GeneralCategory.groovy
new file mode 100644
index 0000000..4686a61
--- /dev/null
+++ b/src/main/com/jdbernard/timeanalyzer/GeneralCategory.groovy
@@ -0,0 +1,12 @@
+package com.jdbernard.timeanalyzer
+
+public class GeneralCategory {
+
+ public GeneralCategory() {
+ super()
+ description = "General"
+ }
+
+ public boolean matchesEvent(Event e) { true }
+
+}
diff --git a/src/main/com/quantumdigital/ithelp/timeanalyzer/ITHelpCategory.groovy b/src/main/com/quantumdigital/ithelp/timeanalyzer/ITHelpCategory.groovy
index a04b414..4aee2ea 100644
--- a/src/main/com/quantumdigital/ithelp/timeanalyzer/ITHelpCategory.groovy
+++ b/src/main/com/quantumdigital/ithelp/timeanalyzer/ITHelpCategory.groovy
@@ -1,15 +1,58 @@
package com.quantumdigital.ithelp.timeanalyzer
import com.jdbernard.timeanalyzer.Category
+import com.jdbernard.timeanalyzer.Entry
+import com.jdbernard.timeanalyzer.Event
public class ITHelpCategory extends Category {
+ private def ithelpPattern = ~/^ITHelp:(.*)$/
+ private def ticketPattern = ~/^ITHelp:.*#(\d+).*/
+
public boolean matchesEvent(Event e) {
- return (e.description ==~ /^ITHelp:.*/)
+ return (e.description ==~ ithelpPattern)
}
- public ITHelpEntry addEvent(Event e) {
- assert eventMatches(e)
+ public Entry addEvent(Event e) {
+
+ Entry entry
+ // try to add to an existing category
+ entry = addToSubcategory(e)
+
+ // no existing category matches
+ if (!entry) {
+
+ // see if it is a new ticket entry
+ def ticketMatch = e.description =~ ticketPattern
+
+ // if is a new ticket
+ if(ticketMatch) {
+ // parse the ticket number
+ int ticketId = ticketMatch[0][1] as int
+
+ // create the category
+ TicketCategory category = new TicketCategory(ticketId)
+
+ // add the category to our list
+ categories << category
+
+ // add the event to the category
+ entry = category.addEvent(e)
+ }
+
+ // not a new ticket, use the general logic for adding
+ else {
+
+ // add a general entry to this category
+ entry = super.addEvent(e)
+
+ // adjust the description (remove the ITHelp tag)
+ def m = entry.description =~ ithelpPattern
+ entry.description = m[0][1]
+ }
+ }
+
+ return entry
}
}
diff --git a/src/main/com/quantumdigital/ithelp/timeanalyzer/ITHelpEntry.groovy b/src/main/com/quantumdigital/ithelp/timeanalyzer/ITHelpEntry.groovy
deleted file mode 100644
index df49d20..0000000
--- a/src/main/com/quantumdigital/ithelp/timeanalyzer/ITHelpEntry.groovy
+++ /dev/null
@@ -1,5 +0,0 @@
-package com.quantumdigital.ithelp.timeanalyzer
-
-import com.jdbernard.timeanalyzer.Event
-
-public class ITHelpEntry extends Entry
diff --git a/src/main/com/quantumdigital/ithelp/timeanalyzer/ITHelpEventTransformation.groovy b/src/main/com/quantumdigital/ithelp/timeanalyzer/ITHelpEventTransformation.groovy
deleted file mode 100644
index 884ac98..0000000
--- a/src/main/com/quantumdigital/ithelp/timeanalyzer/ITHelpEventTransformation.groovy
+++ /dev/null
@@ -1,12 +0,0 @@
-package com.quantumdigital.ithelp.timeanalyzer
-
-import com.jdbernard.timeanalyzer.EventTransformation
-
-public class ITHelpEventTransformation extends EventTransformation {
-
- public boolean matches(Event e) {
- return e.description ==~ /^ITHelp: .*/
- }
-
- public Entry
-}
diff --git a/src/main/com/quantumdigital/ithelp/timeanalyzer/TicketCategory.groovy b/src/main/com/quantumdigital/ithelp/timeanalyzer/TicketCategory.groovy
index c172a72..5916fa2 100644
--- a/src/main/com/quantumdigital/ithelp/timeanalyzer/TicketCategory.groovy
+++ b/src/main/com/quantumdigital/ithelp/timeanalyzer/TicketCategory.groovy
@@ -1,15 +1,20 @@
package com.quantumdigital.ithelp.timeanalyzer
import com.jdbernard.timeanalyzer.Category
+import com.jdbernard.timeanalyzer.Event
public class TicketCategory extends Category {
- public boolean matchesEvent(Event e) {
- return (e.description ==~ /ITHelp:.*#\d+.*/)
+ public final int ticketId
+
+ public TicketCategory(int ticketId) {
+ super()
+ this.ticketId = ticketId
+ this.description = "Ticket #${ticketId}"
}
- public TicketEntry addEvent(Event e) {
- assert eventMatches(e)
+ public boolean matchesEvent(Event e) {
+ return (e.description ==~ /ITHelp:.*#${ticketId}.*/)
+ }
- TicketEntry entry = new TicketEntry(e)
- entries << entry
+}
diff --git a/src/main/com/quantumdigital/ithelp/timeanalyzer/TicketEntry.groovy b/src/main/com/quantumdigital/ithelp/timeanalyzer/TicketEntry.groovy
new file mode 100644
index 0000000..f3cee93
--- /dev/null
+++ b/src/main/com/quantumdigital/ithelp/timeanalyzer/TicketEntry.groovy
@@ -0,0 +1,17 @@
+package com.quantumdigital.ithelp.timeanalyzer
+
+import com.jdbernard.timeanalyzer.Entry
+import com.jdbernard.timeanalyzer.Event
+
+public class TicketEntry extends Entry {
+
+ public int id
+
+ public TicketEntry(ITHelpCategory category, Event e) {
+ super(category, e)
+
+ def m = e.description =~ /^ITHelp:(.*#(\d+).*)$/
+ this.description = m[0][1]
+ this.id = m[0][2] as int
+ }
+}