import _ from 'lodash';
import { utilEditDistance } from '../util/index';


export function presetCollection(collection) {
    var maxSearchResults = 50,
        maxSuggestionResults = 10;

    var presets = {

        collection: collection,


        item: function(id) {
            return _.find(this.collection, function(d) {
                return d.id === id;
            });
        },


        matchGeometry: function(geometry) {
            return presetCollection(this.collection.filter(function(d) {
                return d.matchGeometry(geometry);
            }));
        },


        search: function(value, geometry) {
            if (!value) return this;

            function leading(a) {
                var index = a.indexOf(value);
                return index === 0 || a[index - 1] === ' ';
            }

            function suggestionName(name) {
                var nameArray = name.split(' - ');
                if (nameArray.length > 1) {
                    name = nameArray.slice(0, nameArray.length - 1).join(' - ');
                }
                return name.toLowerCase();
            }


            value = value.toLowerCase();

            var searchable = _.filter(this.collection, function(a) {
                    return a.searchable !== false && a.suggestion !== true;
                }),
                suggestions = _.filter(this.collection, function(a) {
                    return a.suggestion === true;
                });


            // matches value to preset.name
            var leading_name = _.filter(searchable, function(a) {
                    return leading(a.name().toLowerCase());
                }).sort(function(a, b) {
                    var i;
                    i = b.originalScore - a.originalScore;
                    if (i !== 0) return i;

                    i = a.name().toLowerCase().indexOf(value) - b.name().toLowerCase().indexOf(value);
                    if (i !== 0) return i;

                    return a.name().length - b.name().length;
                });

            // matches value to preset.terms values
            var leading_terms = _.filter(searchable, function(a) {
                    return _.some(a.terms() || [], leading);
                });

            // matches value to preset.tags values
            var leading_tag_values = _.filter(searchable, function(a) {
                    return _.some(_.without(_.values(a.tags || {}), '*'), leading);
                });


            // finds close matches to value in preset.name
            var similar_name = searchable.map(function(a) {
                    return {
                        preset: a,
                        dist: utilEditDistance(value, a.name())
                    };
                }).filter(function(a) {
                    return a.dist + Math.min(value.length - a.preset.name().length, 0) < 3;
                }).sort(function(a, b) {
                    return a.dist - b.dist;
                }).map(function(a) {
                    return a.preset;
                });

            // finds close matches to value in preset.terms
            var similar_terms = _.filter(searchable, function(a) {
                    return _.some(a.terms() || [], function(b) {
                        return utilEditDistance(value, b) + Math.min(value.length - b.length, 0) < 3;
                    });
                });

            var leading_suggestions = _.filter(suggestions, function(a) {
                    return leading(suggestionName(a.name()));
                }).sort(function(a, b) {
                    a = suggestionName(a.name());
                    b = suggestionName(b.name());
                    var i = a.indexOf(value) - b.indexOf(value);
                    if (i === 0) return a.length - b.length;
                    else return i;
                });

            var similar_suggestions = suggestions.map(function(a) {
                    return {
                        preset: a,
                        dist: utilEditDistance(value, suggestionName(a.name()))
                    };
                }).filter(function(a) {
                    return a.dist + Math.min(value.length - suggestionName(a.preset.name()).length, 0) < 1;
                }).sort(function(a, b) {
                    return a.dist - b.dist;
                }).map(function(a) {
                    return a.preset;
                });

            var other = presets.item(geometry);

            var results = leading_name.concat(
                    leading_terms,
                    leading_tag_values,
                    leading_suggestions.slice(0, maxSuggestionResults + 5),
                    similar_name,
                    similar_terms,
                    similar_suggestions.slice(0, maxSuggestionResults)
                ).slice(0, maxSearchResults - 1);

            return presetCollection(_.uniq(results.concat(other)));
        }
    };


    return presets;
}
