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 + } +}