class Trie
    clusterSize: 3

    constructor: (cluster) ->
        @children = {}
        @data = null
        @cluster = cluster

    newCluster: -> (null for i in [1..@clusterSize])

    insert: (path, data) ->
        node = @
        cluster = @newCluster()
        data or= path
        for item in path
            cluster = (cluster.concat item)[-@clusterSize..]
            if not node.children[item]
                node.children[item] = new Trie(cluster)
            node = node.children[item]

        node.data = data

    search: (q) ->
        results = @searchRecursive q[0], q[1..], [], [], @newCluster()
        results.sort (a, b) ->
            b.similarity - a.similarity
        return results

    searchRecursive: (head, tail, results, clusters, cluster) ->
        for item, node of @children
            if item == head
                newCluster = (cluster[..].concat head)[-@clusterSize..]
                if node.cluster.join() == newCluster.join()
                    newClusters = clusters[..].concat [newCluster]
                else
                    newClusters = clusters
                [newHead, newTail] = [tail[0], tail[1..]]
            else
                [newHead, newTail] = [head, tail]
                [newClusters, newCluster] = [clusters, cluster]

            if not newHead and not newTail and node.data
                results.push
                    data: node.data
                    similarity: clusters.length

            node.searchRecursive newHead, newTail, results, newClusters, newCluster

        return results


root = exports ? this
root.Trie = Trie
