<commit_before>'use strict';
/* global angular */

var controllersModule = require('./_index');
var PhotoSwipe = require('photoswipe');
var PhotoSwipeUI_Default = require('../components/photoswipe-ui-default');
/**
 * @ngInject
 */

controllersModule.controller('SearchCtrl', ['$stateParams', '$rootScope', '$scope', '$timeout', '$location', '$filter', '$interval', 'SearchService', 'DebugLinkService', 'MapPopUpTemplateService', function($stateParams, $rootScope, $scope, $timeout, $location, $filter, $interval, SearchService, DebugLinkService, MapPopUpTemplateService) {

    // Define models here
    var vm = this;
    window.vm = vm;
    vm.modal = { text: "Tweet content placeholder"};
    vm.showDetail = false;
    vm.showResult = false;
    vm.term = '';
    $rootScope.root.globalFilter = '';
    var intervals = [];

    // Infinite-scroll trigger 
    var getMore = function() {
        var untilDate = new Date((new Date(vm.pool[vm.pool.length -1 ].created_at)).getTime() - 1);
        var untilDateTerm = $filter("date")(untilDate, "yyyy-MM-dd_HH:mm");
        var loadPoolTerm = $location.search().q + "+until:" + untilDateTerm;
        var params = {
           q: loadPoolTerm,
           timezoneOffset: (new Date().getTimezoneOffset())
        };
        SearchService.getData(params).then(function(data) {
               vm.pool = vm.pool.concat(data.statuses);
        }, function() {});
    };
    $scope.loadMore = function(step) {
        if (vm.pool.length < (2 * step + 1)) {
            getMore();
        }
        vm.statuses = vm.statuses.concat(vm.pool.slice(0,step));
        vm.pool = vm.pool.splice(step);
        console.log(vm.statuses.length);
    };



    // Update status and path on successful search
    vm.update = function(term) {
        updatePath(term);
        SearchService.getData(term).then(function(data) {
               vm.pool = data.statuses;

               vm.statuses = [];
               $scope.loadMore(20);

               vm.showResult = true;
               startNewInterval(data.search_metadata.period);
        }, function() {});

        
    };
    
    // No filter search
    vm.filterLive = function() {
        vm.newStasuses = [];
        vm.peopleSearch = false;
        vm.showMap = false;
        $rootScope.root.globalFilter = 'live';
        var term = vm.term;
        vm.update(term);
    };

    // Accounts search
    // Do a normal query, go one by one, check if existed in accounts to add to vm.accounts
    vm.filterAccounts = function() {
        vm.newStasuses = [];
        $rootScope.root.globalFilter = 'accounts';
        vm.accounts = [];
        var term = vm.term;
        SearchService.getData(term).then(function(data) {
            data.statuses.forEach(function(ele) {
                var notYetInAccounts = true;
                vm.accounts.forEach(function(account) {
                    if (account.screen_name === ele.screen_name) {
                        return notYetInAccounts = false;
                    }
                });
                if (notYetInAccounts) { vm.accounts.push(ele);}
            });
            vm.peopleSearch = true;
            vm.showMap = false;
        }, function() {});

        updatePath(vm.term + '+' + '/accounts');
    };

    // Photos search
    vm.filterPhotos = function() {
        vm.newStasuses = [];
        vm.statuses = [];
        vm.peopleSearch = false;
        vm.showMap = false;
        $rootScope.root.globalFilter = 'photos';
        var term = vm.term + '+' + '/image';
        vm.update(term);
    };

    // Videos search
    vm.filterVideos = function() {
        vm.newStasuses = [];
        vm.peopleSearch = false;
        vm.showMap = false;
        vm.statuses = [];   
        $rootScope.root.globalFilter = 'videos';
        vm.showResult = true;


        // Get native videos
        SearchService.getData(vm.term + '+' + '/video').then(function(data) {
            var statuses = data.statuses;
            var statusesWithVideo = [];
            statuses.forEach(function(status) {
                if (status.videos_count) {
                    if (status.videos[0].substr(-4) === '.mp4') {
                        status.links[0] = status.videos[0];
                    }
                    statusesWithVideo.push(status);
                    
                }
            });

            vm.pool = statusesWithVideo;
            vm.statuses = [];
            $scope.loadMore(15);

            startNewInterval(data.search_metadata.period);
        }, function() {});    

        updatePath(vm.term + '+' + '/video');
    };


    // News search
    vm.filterNews = function() {
        vm.newStasuses = [];
        vm.peopleSearch = false;
        vm.showMap = false;
        $rootScope.root.globalFilter = 'news';
        vm.statuses = [];
        var term = vm.term;

        SearchService.getData(term).then(function(data) {
            data.statuses.forEach(function(status) {
                if (hasExternalLink(status)) {
                    DebugLinkService.debugLink(status.links[0]).then(function(data) {
                        if (data.type === 'link' && data.thumbnail_url) {
                            vm.statuses.push(status);
                        }
                    }, function() {return;});
                }
            });
            startNewInterval(data.search_metadata.period);
        }, function() {});

        updatePath(vm.term + '+' + '/news');
    };

    // Map search, show results on a map
    vm.filterMap = function() {
        vm.newStasuses = [];
        $rootScope.root.globalFilter = "map";
        vm.statuses = [];
        vm.accounts = [];
        vm.showMap = true;

        updatePath(vm.term + '+' + '/map');
        var params = {
            q: vm.term,
            count: 300
        };
        SearchService.initData(params).then(function(data) {
            initMap(data.statuses);    
        }, function() {});

        angular.forEach(intervals, function(interval) {
            $interval.cancel(interval);
        });
    };

    // Create photoswipe
    // Lib's docs: http://photoswipe.com/documentation/getting-started.html
    vm.openSwipe = function(status_id) {
        var items = [];
        var images  = angular.element('#' + status_id + ' .images-wrapper img');
        var options = { index: 0, history: false};
        var swipeEle = document.querySelectorAll('.pswp')[0];
        var swipeObject = 'gallery' + status_id;

        angular.forEach(images, function(image) {
            this.push(scrapeImgTag(image));
        }, items);
       
        $timeout(function() {
            window[swipeObject] = new PhotoSwipe(swipeEle, PhotoSwipeUI_Default, items, options);
            window[swipeObject].init();    
        }, 0);
    };


    // Concat new status with vm.statuses when e.g. ng-click
    vm.showNewStatuses = function() {
        vm.statuses = vm.newStasuses.concat(vm.statuses);
        vm.newStasuses = [];
    };


    // HELPERS FN
    ///////////////////
    var bgUpdateTemp = function() {
        var lastestDateObj = new Date(vm.statuses[0].created_at);
        var term = ($rootScope.root.globalFilter === 'live') ? vm.term : vm.term + '+' + filterToQuery($rootScope.root.globalFilter);
        SearchService.getData(term).then(function(data) {
            var keepComparing = true; var i = 0;
            while (keepComparing) {
               if (new Date(data.statuses[i].created_at) <= lastestDateObj) {  
                 vm.newStasuses = data.statuses.slice(0, i);
                 console.log(vm.newStasuses);
                 vm.noOfNewStatuses = vm.newStasuses.length;
                 keepComparing = false;
               }
               i++;
            }
        }, function() {});
    };

    var startNewInterval = function(period) {
        angular.forEach(intervals, function(interval) {
            $interval.cancel(interval);
        });
        console.log(period);
        intervals.push($interval(bgUpdateTemp, parseInt(period)));
    };


    // Scrape for imgTag to serve photoswipe requirement
    function scrapeImgTag(imgTag) {
        var ngEle = angular.element(imgTag);
        return {
            src: ngEle.attr('src'),
            w: parseInt(ngEle.css('width').replace('px', '')),
            h: parseInt(ngEle.css('height').replace('px', ''))
        };
    }

    // Change stateParams on search
    function updatePath(query) {
      $location.search({
        q: query
      });
      $rootScope.root.globalSearchTerm = vm.term;
    }

    // Evaluate current search query to extract term & filter
    function evalSearchQuery() {
        var queryParts = $location.search().q.split('+');
        var queryToFilter = {
            '/image': 'photos',
            '/video': 'videos',
            '/accounts': 'accounts', 
            '/news' : 'news',
            '/map' : 'map'
        };
        vm.term = queryParts[0];
        $rootScope.root.globalFilter = (queryParts[1]) ? queryToFilter[queryParts[1]] : 'live';

    }

    // Turn filter parameter to the right query parameter
    function filterToQuery(filterName) {
        var filtersToQueries = {
            'photos' : '/image',
            'videos' :'/video',
            'accounts' : '/accounts', 
            'news' : '/news',
            'map' : '/map'
        };
        return filtersToQueries[filterName
        ];
    }

    // Check if a status has external link, twitter pic src is not considered as external
    function hasExternalLink(status) {
        if (!status.links[0]) {
            return false;
        } else if (status.links[0].indexOf('pbs.twimg.com') > -1) {
            return false;
        } else {
            return true;    
        }
    }

    // Insert into status based on time created
    function insertToStatusesByTimeOrder(ele, arr) {
        var eleTime = new Date(ele.created_at);
        for (var i = 0; i < arr.length; i++) {
            if (eleTime > (new Date(arr[i].created_at))) {
                arr.splice(i, 0, arr);
                i = arr.length;
            };
        }
    }


    // Init map point from data
    function initMapPoints(data) {
        var tweets = {
            "type": "FeatureCollection",
            "features": [
            ]
        };
        data.forEach(function(ele) {
            if (ele.location_mark) {
                var text = MapPopUpTemplateService.genStaticTwitterStatus(ele);
                var pointObject = {
                    "geometry": {
                        "type": "Point",
                        "coordinates": [
                            ele.location_mark[0],
                            ele.location_mark[1]
                        ]
                    },
                    "type": "Feature",
                    "properties": {
                        "popupContent": "<div class='foobar'>" + text + "</div>"
                    },
                    "id": ele.id_str
                };
                tweets.features.push(pointObject);
            }
        });

        return tweets;
    }

    // Add points to map
    function addPointsToMap(map, tweets) {
        function onEachFeature(feature, layer) {
            if (feature.properties && feature.properties.popupContent) {
                var popupContent = feature.properties.popupContent;
            }
            layer.bindPopup(popupContent);
        }
        L.geoJson([tweets], {
            style: function (feature) {
                return feature.properties && feature.properties.style;
            },
            onEachFeature: onEachFeature,
            pointToLayer: function (feature, latlng) {
                return L.circleMarker(latlng, {
                    radius: 8,
                    fillColor: "#ff7800",
                    color: "#000",
                    weight: 1,
                    opacity: 1,
                    fillOpacity: 0.8
                });
            }
        }).addTo(map);    
     
        map.on("zoomend", function(event) {
            var bound = map.getBounds();
            var longWest = parseFloat(bound._southWest.lng);
            var latSouth = parseFloat(bound._southWest.lat);
            var longEast = parseFloat(bound._northEast.lng);
            var latNorth = parseFloat(bound._northEast.lat);
            var locationTerm = "/location=" + longWest + "," + latSouth + "," + longEast + "," + latNorth; 
            console.log(vm.term + "+" + locationTerm);
            SearchService.getData(vm.term + "+" + locationTerm).then(function(data) {
                console.log(data);<commit_msg>Add fn to process bound, add listen on draggin/panning on map<commit_after>'use strict';
/* global angular */

var controllersModule = require('./_index');
var PhotoSwipe = require('photoswipe');
var PhotoSwipeUI_Default = require('../components/photoswipe-ui-default');
/**
 * @ngInject
 */

controllersModule.controller('SearchCtrl', ['$stateParams', '$rootScope', '$scope', '$timeout', '$location', '$filter', '$interval', 'SearchService', 'DebugLinkService', 'MapPopUpTemplateService', function($stateParams, $rootScope, $scope, $timeout, $location, $filter, $interval, SearchService, DebugLinkService, MapPopUpTemplateService) {

    // Define models here
    var vm = this;
    window.vm = vm;
    vm.modal = { text: "Tweet content placeholder"};
    vm.showDetail = false;
    vm.showResult = false;
    vm.term = '';
    $rootScope.root.globalFilter = '';
    var intervals = [];

    // Infinite-scroll trigger 
    var getMore = function() {
        var untilDate = new Date((new Date(vm.pool[vm.pool.length -1 ].created_at)).getTime() - 1);
        var untilDateTerm = $filter("date")(untilDate, "yyyy-MM-dd_HH:mm");
        var loadPoolTerm = $location.search().q + "+until:" + untilDateTerm;
        var params = {
           q: loadPoolTerm,
           timezoneOffset: (new Date().getTimezoneOffset())
        };
        SearchService.getData(params).then(function(data) {
               vm.pool = vm.pool.concat(data.statuses);
        }, function() {});
    };
    $scope.loadMore = function(step) {
        if (vm.pool.length < (2 * step + 1)) {
            getMore();
        }
        vm.statuses = vm.statuses.concat(vm.pool.slice(0,step));
        vm.pool = vm.pool.splice(step);
        console.log(vm.statuses.length);
    };



    // Update status and path on successful search
    vm.update = function(term) {
        updatePath(term);
        SearchService.getData(term).then(function(data) {
               vm.pool = data.statuses;

               vm.statuses = [];
               $scope.loadMore(20);

               vm.showResult = true;
               startNewInterval(data.search_metadata.period);
        }, function() {});

        
    };
    
    // No filter search
    vm.filterLive = function() {
        vm.newStasuses = [];
        vm.peopleSearch = false;
        vm.showMap = false;
        $rootScope.root.globalFilter = 'live';
        var term = vm.term;
        vm.update(term);
    };

    // Accounts search
    // Do a normal query, go one by one, check if existed in accounts to add to vm.accounts
    vm.filterAccounts = function() {
        vm.newStasuses = [];
        $rootScope.root.globalFilter = 'accounts';
        vm.accounts = [];
        var term = vm.term;
        SearchService.getData(term).then(function(data) {
            data.statuses.forEach(function(ele) {
                var notYetInAccounts = true;
                vm.accounts.forEach(function(account) {
                    if (account.screen_name === ele.screen_name) {
                        return notYetInAccounts = false;
                    }
                });
                if (notYetInAccounts) { vm.accounts.push(ele);}
            });
            vm.peopleSearch = true;
            vm.showMap = false;
        }, function() {});

        updatePath(vm.term + '+' + '/accounts');
    };

    // Photos search
    vm.filterPhotos = function() {
        vm.newStasuses = [];
        vm.statuses = [];
        vm.peopleSearch = false;
        vm.showMap = false;
        $rootScope.root.globalFilter = 'photos';
        var term = vm.term + '+' + '/image';
        vm.update(term);
    };

    // Videos search
    vm.filterVideos = function() {
        vm.newStasuses = [];
        vm.peopleSearch = false;
        vm.showMap = false;
        vm.statuses = [];   
        $rootScope.root.globalFilter = 'videos';
        vm.showResult = true;


        // Get native videos
        SearchService.getData(vm.term + '+' + '/video').then(function(data) {
            var statuses = data.statuses;
            var statusesWithVideo = [];
            statuses.forEach(function(status) {
                if (status.videos_count) {
                    if (status.videos[0].substr(-4) === '.mp4') {
                        status.links[0] = status.videos[0];
                    }
                    statusesWithVideo.push(status);
                    
                }
            });

            vm.pool = statusesWithVideo;
            vm.statuses = [];
            $scope.loadMore(15);

            startNewInterval(data.search_metadata.period);
        }, function() {});    

        updatePath(vm.term + '+' + '/video');
    };


    // News search
    vm.filterNews = function() {
        vm.newStasuses = [];
        vm.peopleSearch = false;
        vm.showMap = false;
        $rootScope.root.globalFilter = 'news';
        vm.statuses = [];
        var term = vm.term;

        SearchService.getData(term).then(function(data) {
            data.statuses.forEach(function(status) {
                if (hasExternalLink(status)) {
                    DebugLinkService.debugLink(status.links[0]).then(function(data) {
                        if (data.type === 'link' && data.thumbnail_url) {
                            vm.statuses.push(status);
                        }
                    }, function() {return;});
                }
            });
            startNewInterval(data.search_metadata.period);
        }, function() {});

        updatePath(vm.term + '+' + '/news');
    };

    // Map search, show results on a map
    vm.filterMap = function() {
        vm.newStasuses = [];
        $rootScope.root.globalFilter = "map";
        vm.statuses = [];
        vm.accounts = [];
        vm.showMap = true;

        updatePath(vm.term + '+' + '/map');
        var params = {
            q: vm.term,
            count: 300
        };
        SearchService.initData(params).then(function(data) {
            initMap(data.statuses);    
        }, function() {});

        angular.forEach(intervals, function(interval) {
            $interval.cancel(interval);
        });
    };

    // Create photoswipe
    // Lib's docs: http://photoswipe.com/documentation/getting-started.html
    vm.openSwipe = function(status_id) {
        var items = [];
        var images  = angular.element('#' + status_id + ' .images-wrapper img');
        var options = { index: 0, history: false};
        var swipeEle = document.querySelectorAll('.pswp')[0];
        var swipeObject = 'gallery' + status_id;

        angular.forEach(images, function(image) {
            this.push(scrapeImgTag(image));
        }, items);
       
        $timeout(function() {
            window[swipeObject] = new PhotoSwipe(swipeEle, PhotoSwipeUI_Default, items, options);
            window[swipeObject].init();    
        }, 0);
    };


    // Concat new status with vm.statuses when e.g. ng-click
    vm.showNewStatuses = function() {
        vm.statuses = vm.newStasuses.concat(vm.statuses);
        vm.newStasuses = [];
    };


    // HELPERS FN
    ///////////////////
    var bgUpdateTemp = function() {
        var lastestDateObj = new Date(vm.statuses[0].created_at);
        var term = ($rootScope.root.globalFilter === 'live') ? vm.term : vm.term + '+' + filterToQuery($rootScope.root.globalFilter);
        SearchService.getData(term).then(function(data) {
            var keepComparing = true; var i = 0;
            while (keepComparing) {
               if (new Date(data.statuses[i].created_at) <= lastestDateObj) {  
                 vm.newStasuses = data.statuses.slice(0, i);
                 console.log(vm.newStasuses);
                 vm.noOfNewStatuses = vm.newStasuses.length;
                 keepComparing = false;
               }
               i++;
            }
        }, function() {});
    };

    var startNewInterval = function(period) {
        angular.forEach(intervals, function(interval) {
            $interval.cancel(interval);
        });
        console.log(period);
        intervals.push($interval(bgUpdateTemp, parseInt(period)));
    };


    // Scrape for imgTag to serve photoswipe requirement
    function scrapeImgTag(imgTag) {
        var ngEle = angular.element(imgTag);
        return {
            src: ngEle.attr('src'),
            w: parseInt(ngEle.css('width').replace('px', '')),
            h: parseInt(ngEle.css('height').replace('px', ''))
        };
    }

    // Change stateParams on search
    function updatePath(query) {
      $location.search({
        q: query
      });
      $rootScope.root.globalSearchTerm = vm.term;
    }

    // Evaluate current search query to extract term & filter
    function evalSearchQuery() {
        var queryParts = $location.search().q.split('+');
        var queryToFilter = {
            '/image': 'photos',
            '/video': 'videos',
            '/accounts': 'accounts', 
            '/news' : 'news',
            '/map' : 'map'
        };
        vm.term = queryParts[0];
        $rootScope.root.globalFilter = (queryParts[1]) ? queryToFilter[queryParts[1]] : 'live';

    }

    // Turn filter parameter to the right query parameter
    function filterToQuery(filterName) {
        var filtersToQueries = {
            'photos' : '/image',
            'videos' :'/video',
            'accounts' : '/accounts', 
            'news' : '/news',
            'map' : '/map'
        };
        return filtersToQueries[filterName
        ];
    }

    // Check if a status has external link, twitter pic src is not considered as external
    function hasExternalLink(status) {
        if (!status.links[0]) {
            return false;
        } else if (status.links[0].indexOf('pbs.twimg.com') > -1) {
            return false;
        } else {
            return true;    
        }
    }

    // Insert into status based on time created
    function insertToStatusesByTimeOrder(ele, arr) {
        var eleTime = new Date(ele.created_at);
        for (var i = 0; i < arr.length; i++) {
            if (eleTime > (new Date(arr[i].created_at))) {
                arr.splice(i, 0, arr);
                i = arr.length;
            };
        }
    }


    // Init map point from data
    function initMapPoints(data) {
        var tweets = {
            "type": "FeatureCollection",
            "features": [
            ]
        };
        data.forEach(function(ele) {
            if (ele.location_mark && ele.user) {
                var text = MapPopUpTemplateService.genStaticTwitterStatus(ele);
                var pointObject = {
                    "geometry": {
                        "type": "Point",
                        "coordinates": [
                            ele.location_mark[0],
                            ele.location_mark[1]
                        ]
                    },
                    "type": "Feature",
                    "properties": {
                        "popupContent": "<div class='foobar'>" + text + "</div>"
                    },
                    "id": ele.id_str
                };
                tweets.features.push(pointObject);
            }
        });

        return tweets;
    }


    // Get location in search term, from lat, long bound
    function getLocationTermFromBound(bound) {
        var longWest = parseFloat(bound._southWest.lng);
        var latSouth = parseFloat(bound._southWest.lat);
        var longEast = parseFloat(bound._northEast.lng);
        var latNorth = parseFloat(bound._northEast.lat);
        var locationTerm = "/location=" + longWest + "," + latSouth + "," + longEast + "," + latNorth;
        return locationTerm;
    }

    // Add points to map
    function addPointsToMap(map, tweets) {
        function onEachFeature(feature, layer) {
            if (feature.properties && feature.properties.popupContent) {
                var popupContent = feature.properties.popupContent;
            }
            layer.bindPopup(popupContent);
        }
        L.geoJson([tweets], {
            style: function (feature) {
                return feature.properties && feature.properties.style;
            },
            onEachFeature: onEachFeature,
            pointToLayer: function (feature, latlng) {
                return L.circleMarker(latlng, {
                    radius: 8,
                    fillColor: "#ff7800",
                    color: "#000",
                    weight: 1,
                    opacity: 1,
                    fillOpacity: 0.8
                });
            }
        }).addTo(map);    
     
        map.on("zoomend", function(event) {
            var bound = map.getBounds();
            var locationTerm = getLocationTermFromBound(bound);
            console.log(vm.term + "+" + locationTerm);
            SearchService.getData(vm.term + "+" + locationTerm).then(function(data) {
                console.log(data);
                addPointsToMap(window.map, initMapPoints(data.statuses));    
            }, function(data) {});
        });
        map.on("dragend", function(event) {
            var bound = map.getBounds();
            var locationTerm = getLocationTermFromBound(bound);
            console.log(vm.term + "+" + locationTerm);
            SearchService.getData(vm.term + "+" + locationTerm).then(function(data) {
                console.log(data);
{'fraction_non_alphanumeric': 0.13533312769895126, 'fraction_numerical': 0.0035471930906847624, 'mean_word_length': 1.6802728118218455, 'pattern_counts': {'":': 18, '<': 13, '<?xml version=': 0, '>': 11, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6617714', 'n_tokens_mistral': 7447, 'n_tokens_neox': 7130, 'n_words': 1374}