source : selectFacet.js

(function (angular) {
    'use strict';
    /**
     * @memberof spApp
     * @ngdoc directive
     * @name selectFacet
     * @description
     *   Facet selection controls
     */
    angular.module('select-facet-directive', ['map-service', 'predefined-areas-service'])
        .directive('selectFacet', ['$http', 'MapService', 'PredefinedAreasService', '$timeout', 'FacetAutoCompleteService', 'BiocacheService',
            'LayoutService', function ($http, MapService, PredefinedAreasService, $timeout, FacetAutoCompleteService, BiocacheService, LayoutService) {
                return {
                    templateUrl: '/spApp/selectFacetCtrl.htm',
                    scope: {
                        _selectedFacet: '=selectedFacet',
                        _uniqueId: '=uniqueId'
                    },
                    link: function (scope, element, attrs) {
                        scope.facet = {};
                        scope.facets = [];
                        scope.facetList = [];
                        scope.exportUrl = null;
                        scope.sortFacetsByName = false;
                        scope.fqsOfSpeciesOptions=[];
                        FacetAutoCompleteService.search(BiocacheService.newQuery(["-*:*"])).then(function (data) {
                            scope.facets = data
                        });
                        //Watch special options update
                        //fq=geospatial_kosher:true&fq=-occurrence_status:absent
                        scope.$on("speciesOptionsChange",function (event, value) {
                            scope.fqsOfSpeciesOptions = [];
                            /*
                            spatially-valid = geospatial_kosher:true
                            spatially-suspect = geospatial_kosher:false
                            spatially-unknown = -geospatial_kosher:*
                            If we want include VALID and MISSING(UNKNOWN) spatial data
                            fq=(geospatial_kosher:true OR -geospatial_kosher:*) BS(solr) does not support '-' in complicated query
                            */
                            if (value.spatiallyUnknown) { //include UNKNOWN (MISSING) spatial data records
                                if (value.spatiallyValid && value.spatiallySuspect) {
                                    //Do nothing, returns all records
                                    //scope.fqsOfSpeciesOptions.push('*:*')
                                } else if (value.spatiallyValid) {
                                    //spatially-unknown && spatiallyValid
                                    //-> rule out of spatiallySuspect
                                    scope.fqsOfSpeciesOptions.push('-geospatial_kosher:false');
                                }else if (value.spatiallySuspect) {
                                    //spatially-unknown && spatiallySuspect
                                    //-> rule out of spatiallyValid
                                    scope.fqsOfSpeciesOptions.push('-geospatial_kosher:true');
                                }
                            } else {
                                //spatially-valid and spatially-suspect
                                if (value.spatiallyValid && value.spatiallySuspect) {
                                    scope.fqsOfSpeciesOptions.push('geospatial_kosher:*');
                                } else if (value.spatiallyValid) {
                                    scope.fqsOfSpeciesOptions.push('geospatial_kosher:true');
                                } else if (value.spatiallySuspect) {
                                    scope.fqsOfSpeciesOptions.push('geospatial_kosher:false');
                                }
                            }
                            //if includeAbsences NOT selected
                            if (!value.includeAbsences) {
                                scope.fqsOfSpeciesOptions.push("-occurrence_status:absent")
                            }
                            //if a facet has been selected, then refresch results
                            if(scope.hasFacetSelected()){
                                scope.update();
                            }
                        });
                        scope.hasFacetSelected=function(){
                            if($.isEmptyObject(scope.facet)){
                                return false;
                            }
                            if(scope.facet == '' || scope.facet == 'search'){
                                return false;
                            }
                            //Angular added $$hashkey to track object
                            var keys = Object.keys(scope.facet);
                            if (keys.length == 1 && keys[0] == "$$hashKey"){
                                return false;
                            }
                            return true;
                        }
                        scope.pageSize = 10;
                        scope.offset = 0;
                        scope.updatingPage = false;
                        scope.downloadSize = 0;
                        scope.facetFilter = '';
                        scope.indexFields = []
                        scope.activeFacets = []
                        scope.activeFacet = {}
                        LayoutService.addToSave(scope);
                        scope.ok = function (data) {
                            if (scope.step === 2) {
                                scope.applySelection();
                                scope.updateSel();
                            } else {
                                scope.step = scope.step + 1
                            }
                        };
                        scope.nextPage = function () {
                            scope.applySelection();
                            if (scope.offset + scope.pageSize < scope.activeFacet.max) {
                                scope.offset += scope.pageSize;
                                scope.updatePage()
                            }
                        };
                        scope.previousPage = function () {
                            scope.applySelection();
                            if (scope.offset > 0) {
                                scope.offset -= scope.pageSize;
                                scope.updatePage()
                            }
                        };
                        BiocacheService.getIndexFields().then(function (indexFields) {
                            scope.indexFields = indexFields
                        })
                        scope.updateActiveFacets = function (data) {
                            for (var j = 0; j < data.length; j++) {
                                var idx = -1
                                $.each(scope.activeFacets, function (i, v) {
                                    if (v.facet == data[j].name) {
                                        idx = i
                                    }
                                })
                                if (data[j].selected) {
                                    if (idx < 0) {
                                        var item = {
                                            name: data[j].description || data[j].downloadName || data[j].name,
                                            facet: data[j].name
                                        }
                                        scope.activeFacets.push(item)
                                        scope.activeFacet = item
                                        scope.facet = item.facet
                                    }
                                } else {
                                    if (idx >= 0) {
                                        scope.activeFacets.splice(idx, 0)
                                    }
                                }
                            }
                        }
                        scope.searchFacets = function () {
                            LayoutService.openModal('facet', {
                                data: scope.indexFields,
                                onChange: scope.updateActiveFacets
                            }, true)
                        }
                        scope.changeFacet = function () {
                            scope.updateSel()
                            if (scope.facet === 'search') {
                                scope.searchFacets()
                                scope.facet = ''
                                return;
                            }
                            var alreadyActive = false
                            $.each(scope.activeFacets, function (i, v) {
                                if (scope.facet === v.facet) {
                                    alreadyActive = true
                                    scope.activeFacet = v
                                }
                            })
                            if (!alreadyActive) {
                                $.each(scope.facets, function (i, v) {
                                    if (scope.facet === v.facet) {
                                        scope.activeFacets.push(v)
                                        scope.activeFacet = v
                                    }
                                })
                            }
                            if (!scope.activeFacet.selection) {
                                scope.activeFacet.selection = []
                            }
                            scope.offset = 0;
                            scope.updateFacet()
                        };
                        scope.clearFilter = function () {
                            scope.activeFacet.facetFilter='';
                            scope.facetFilter = '';
                            scope.offset = 0;
                            if (scope.activeFacet.selection) {
                                scope.activeFacet.selection = []
                            }
                            scope.updatePage()
                        };
                        scope.applyFilter = function () {
                            scope.facetFilter = scope.activeFacet.facetFilter;
                            scope.offset = 0;
                            scope.updatePage()
                        };
                        scope.facetsOrderByName = function(){
                            scope.facetOrderby = 'label';
                        }
                        scope.facetsOrderByCount = function(){
                            scope.facetOrderBy = 'count';
                        }
                        scope.updateFacet = function () {
                            scope.update(true);
                        };
                        scope.updatePage = function () {
                            scope.update(false);
                        };
                        scope.update = function (updateAll) {
                            scope.updatingPage = true;
                            var config = {
                                eventHandlers: {
                                    progress: function (c) {
                                        scope.downloadSize = c.loaded
                                    }
                                }
                            };
                            scope.applySelection();
                            var q = ["*:*"];
                            if ($SH.qc !== undefined && $SH.qc != null && $SH.qc.length > 0) q = [$SH.qc];
                            var pageSize = 10;
                            var offset = scope.offset;
                            $.each(scope.activeFacets, function (i, v) {
                                if (v.facet !== scope.facet) {
                                    // add this fq
                                    var fq = v.sel
                                    if (fq) {
                                        q.push(fq)
                                    }
                                } else {
                                    scope.activeFacet = v
                                }
                            })
                            $.each(scope.fqsOfSpeciesOptions, function(i){
                                q.push(scope.fqsOfSpeciesOptions[i])
                            })
                            var sortBy = 'count';
                            if(scope.sortFacetsByName){
                                //Sort by name alphabetically
                                sortBy = 'index'
                            }
                            if (scope.facet !== 'search' && scope.facet !== '') {
                                //Biocache returns error message as plain text
                                var config = {headers: {"Accept": "text/plain, */*",
                                           }};
                                BiocacheService.facetGeneral(scope.facet, {
                                    q: q,
                                    bs: $SH.biocacheServiceUrl
                                }, pageSize, offset, scope.facetFilter, sortBy, config).then(function (data) {
                                    if (data.length > 0) {
                                        scope.activeFacet.facetList = data[0].fieldResult;
                                        scope.activeFacet.exportUrl = BiocacheService.facetDownload(scope.facet);
                                        scope.activeFacet.max = data[0].count + scope.offset;
                                        scope.activeFacet.maxPages = Math.ceil(scope.activeFacet.max / scope.pageSize)
                                    } else {
                                        scope.activeFacet.max = 0;
                                        scope.activeFacet.facetList = [];
                                        scope.activeFacet.maxPages = 0
                                    }
                                    scope.updateSel();
                                    scope.updateCheckmarks();
                                    scope.updatingPage = false;
                                }, function (error) {
                                    scope.updatingPage = false;
                                     if (error.data){
                                         bootbox.alert("Error: " + error.data.errorType +"<br/>Check logs for more information!")
                                     } else {
                                         bootbox.alert("An error occurred. Please try again and if the same error occurs, send an email to support@ala.org.au and include the URL to this page, the error message and what steps you performed that triggered this error.")
                                     }
                                })
                            }
                        };
                        scope.clearSelection = function () {
                            for (var i = 0; i < scope.activeFacet.facetList.length; i++) {
                                scope.activeFacet.facetList[i].selected = false
                            }
                            scope.activeFacet.selection = [];
                            scope.updateSel()
                        };
                        scope.applySelection = function () {
                            if (scope.activeFacet.facetList) {
                                for (var i = 0; i < scope.activeFacet.facetList.length; i++) {
                                    if (scope.activeFacet.facetList[i].selected) {
                                        var found = false;
                                        for (var k in scope.activeFacet.selection) {
                                            if (scope.activeFacet.selection[k].fq === scope.activeFacet.facetList[i].fq) {
                                                found = true
                                            }
                                        }
                                        if (!found) scope.activeFacet.selection.push(scope.activeFacet.facetList[i])
                                    } else {
                                        for (k in scope.activeFacet.selection) {
                                            if (scope.activeFacet.selection[k].fq === scope.activeFacet.facetList[i].fq) {
                                                scope.activeFacet.selection.splice(Number(k), 1)
                                            }
                                        }
                                    }
                                }
                                scope.updateSel()
                            }
                        };
                        scope.updateCheckmarks = function () {
                            for (var i = 0; i < scope.activeFacet.facetList.length; i++) {
                                var found = false;
                                for (var k in scope.activeFacet.selection) {
                                    if (scope.activeFacet.selection[k].fq === scope.activeFacet.facetList[i].fq) {
                                        found = true
                                    }
                                }
                                if (found) scope.activeFacet.facetList[i].selected = true
                            }
                        };
                        scope.updateSel = function () {
                            if (scope.activeFacet.selection) {
                                var sel = '';
                                var invert = false;
                                var count = 0;
                                for (var i = 0; i < scope.activeFacet.selection.length; i++) {
                                    var fq = scope.activeFacet.selection[i].fq;
                                    if (fq.match(/^-/g) != null && (fq.match(/:\*$/g) != null || fq.match(/\[\* TO \*\]$/g) != null)) {
                                        invert = true
                                    }
                                    count++
                                }
                                if (count === 1) invert = false;
                                for (i = 0; i < scope.activeFacet.selection.length; i++) {
                                    fq = scope.activeFacet.selection[i].fq;
                                    if (invert) {
                                        if (sel.length > 0) sel += " AND ";
                                        if (fq.match(/^-/g) != null && (fq.match(/:\*$/g) != null || fq.match(/\[\* TO \*\]$/g) != null)) {
                                            sel += fq.substring(1)
                                        } else {
                                            sel += '-' + fq
                                        }
                                    } else {
                                        if (sel.length > 0) sel += " OR ";
                                        sel += fq
                                    }
                                }
                                if (invert) {
                                    sel = '-(' + sel + ')'
                                }
                                if (sel.length === 0) {
                                    scope.activeFacet.sel = ''
                                } else {
                                    scope.activeFacet.sel = sel
                                }
                                scope._selectedFacet.splice(0, scope._selectedFacet.length)
                                $.each(scope.activeFacets, function (i, v) {
                                    if (v.sel) {
                                        scope._selectedFacet.push(v.sel)
                                    }
                                })
                            }
                        }
                        // default selection
                        if (scope.activeFacets.length > 0) {
                            scope.facet = scope.activeFacets[scope.activeFacets.length - 1].facet
                            scope.changeFacet()
                        }
                    }
                }
            }])
}(angular));