package com.jdbernard.timeanalyzer

import org.joda.time.Duration

/**
 * A category represents a collection of like events.
 */
public abstract class Category implements Comparable<Category> {

    public List<Entry> entries
    public List<Category> categories
    public String description

    public Category() {
        entries = []
        categories = []
        description = "Unnamed Category"
    }

    public abstract boolean matchesEvent(Event e)

    public Entry addEvent(Event e) {
        Entry entry

        // 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
                def category = new DescriptionBasedCategory(e.description)

                // add the new event to the category
                entry = category.addEvent(e)

                // remove the existing entry from this category and
                // add it to the subcategory
                this.entries -= existingEntry
                category.entries << existingEntry
                existingEntry.category = category

                // 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(new Duration(0)) { it.duration } +
               entries.sum(new Duration(0)) { it.duration }
    }

    public int compareTo(Category other) {
        return this.getDuration().compareTo(other.getDuration())
    }

    public String toString() { return description }

}