<repo_name>watsabitz/DSRH<file_sep>/common/services/auth.js
angular
    .module('Dsrh')
    .factory('Auth', Auth);

Auth.$inject = ['$firebaseAuth', '$q', 'Database'];
function Auth($firebaseAuth, $q, Database){
    const authObj = {};

    //initialize the $firebaseAuth service
    let auth = $firebaseAuth();

    //append functions to the Auth service
    authObj.auth = auth;
    authObj.createUser = createUser;
    authObj.addUser = addUser;
    authObj.updateUser = updateUser;
    authObj.deleteUser = deleteUser;
    authObj.sendVerificationEmail = sendVerificationEmail;
    authObj.signIn = signIn;
    authObj.signOut = signOut;
    authObj.resetPassword = resetPassword;
    authObj.retrieveUserInfo = retrieveUserInfo;
 


    /** 
     * Create user
     */
    function createUser(user){
        // create a chain of promises
        // we let the caller to catch and treat the error in the controller
        return auth.$createUserWithEmailAndPassword(user.email, user.password)
            .then((firebaseUser) => {
                log('User created');
                // console.log('User: ', firebaseUser);

                return this.addUser(user, firebaseUser.uid).then(() => {
                    log('User profile updated');

                    return this.sendVerificationEmail().then(() => {
                        log('Verification email sent');
                        
                        //we don't want to log in the user if he does not have a verified email
                        return this.signOut().then(() => {

                            return $q.when(); // return a success promise
                        });
                    });
                });
            });
    }



    /** 
     * Update user
     */
    function updateUser(user){
        
        // retrieve the old username
        var oldUsername = auth.$getAuth().displayName;

        // delete only the username from the username list and then update the account profile and the database
        return Database.deleteUser(user, oldUsername)
            .then( ()=> {
                return this.addUser(user);
            });
    }



    /** 
     * Add user information in the database
     */
    function addUser(userInfo, id){

        // get the user profile data information
        const user = auth.$getAuth();

        // this information is different than the one which we manually store in the database
        // and is strictly asociated with the user account
        const userProfile = {
            displayName: userInfo.displayName || ''
            // photoURL: userInfo.photoURL || ''
        };
        
        // update user profile data
        return user.updateProfile(userProfile)

        //then create an object with the user information in the database;
        .then( () => {
            return Database.addUser(userInfo, id || user.uid);
        });
    }



    /** 
     * Delete the currently signed-in in user
     */
    function deleteUser(){
        auth.$deleteUser()
            .then(() => {
                console.log('user deleted');
            })
            .catch((error) => {
                console.log(error);
            });
    }



    /** 
     * Send a verfication email when the account is created
     */
    function sendVerificationEmail(){
        //get the user information
        const user = auth.$getAuth();

        return user.sendEmailVerification();
    }



    /** 
     * Sign in with the email and the password
     */
    function signIn(email, password){
        return auth.$signInWithEmailAndPassword(email, password);
    }



    /** 
     * Sign out the current logged user
     */
    function signOut(){
        return auth.$signOut();
    }
    


    /** 
     * Reset email to reset the password
     */
    function resetPassword(resetEmail){
        return auth.$sendPasswordResetEmail(resetEmail);
    }



    /** 
     * Retrieve user information which was stored at authentification/update profile phase;
     */
    function retrieveUserInfo(){
        return Database.retrieveUserInfo(auth.$getAuth().uid);
    }



    return authObj;
}<file_sep>/common/services/snackBar.js
angular
  .module("Dsrh")
  .factory("SnackBar", snackBar);

  function snackBar($timeout){
    var SB = {};
    SB.showMainInfoSnackbar = showMainInfoSnackbar;

    function showMainInfoSnackbar(errorSnack = false, message = false, successSnack = false, changeTop = false){
      const x = document.getElementById("mainInfoSnackbar");

      if (message) {
        x.textContent = message;
      }
      
      //orizontal align the snakcbar
      var viewPortWidth = Math.max(document.documentElement.clientWidth, window.innerWidth || 0);
      x.style.right = `${viewPortWidth/2 - x.getBoundingClientRect().width/2}px`;

      //vertical align the sidebar
      // x.style.top = `${window.scrollY + 30}px`;
      if(changeTop) {
        x.style.setProperty("--top", `${window.scrollY + 30}px`)
      } else {
        x.style.setProperty("--top", `30px`);
      }

      //if it's an error snakbar make it red
      if(errorSnack) {
        x.style.backgroundColor = '#e24d52';
      } else if (successSnack){
        x.style.backgroundColor = '#119094';
      } else {
        x.style.backgroundColor = '#333';
      }


      //show the snakbar
      x.className = "show";

      // remove the "show" class to hide the snackBar
      $timeout(function(){
          x.className = x.className.replace("show", ""); 
      }, 3000);
    }

    return SB;

  }<file_sep>/common/directives/search/search.js
angular
    .module("Dsrh")
    .directive("searchDirective", searchDirective);


    function searchDirective(Search, SnackBar){


        function getTemplateUrl(elem, attrs){
            return 'common/directives/search/' + attrs.templateName + 'SearchTemplate.html';
        }


        function searchController($filter, $scope, $state, $timeout){
            const preloader = document.querySelector('#preloader');
            preloader.style.display = "block";
            
        /** 
         * Hotels
         */

            // test to see if the init was made 
            // if not, make the initialization  
            // if(!Search.initDone){
                Search.init()
                .then(() => {
                    log('Search data successfully retrieved from database');
                    Search.initDone = true;
                    getSearchData();
                    preloader.style.display = "none";
                })
                .catch((error) => {
                    log('Search Data was not retrieved from database', error);
                    Search.initDone = false;
                    preloader.style.display = "none";
                });
            // } else {
                // else directly get the data  
                // getSearchData();
            // }


            // get search data and put in on the scope
            function getSearchData(){
                log('Search data successfully loaded');
                const data = ['cities', 'hotels', 'restaurants'];
                if($scope.addToSearch) {
                    $scope.addToSearch.split(',').forEach( item  => {
                        switch (item) {
                            case data[0] :
                                $scope[item] = Search.getCitiesList(); 
                                console.log('Cities:', $scope[item].length);
                                break; 
                            case data[1] :
                                $scope[item] = Search.getHotelsList();
                                console.log('Hotels:', $scope[item].length); 
                                break; 
                            case data[2] :
                                $scope[item] = Search.getRestaurantsList(); 
                                console.log('Restaurants:', $scope[item].length);
                                break; 
                        }
                    });
                }
            }

            $scope.showSearchResult = false;
            $scope.showSearchResultRest = false;
            //get the search input position and put the search result div bellow it
            //also, set the width of the div to the same length as the search
            const searchInput = document.querySelector("input#searchedTextInput");
            let searchInputPosition = searchInput.getBoundingClientRect();
            const searchResult = document.querySelector("div#searchResult");
            if(searchResult) searchResult.style.top = `${searchInputPosition.bottom + 12}px`;
            if(searchResult) searchResult.style.width = `${searchInputPosition.width}px`;
            

            //do the regex tests
            function populateResultList(input, listToIterate, returnedListName){
                const regExp1 = new RegExp(`^${input}`, 'gi');
                const regExp2 = new RegExp(`(?!^)${input}`, 'gi');

                let searchResult1 = [], searchResult2 = [];

                $scope[listToIterate].forEach( (item) => {
                    if( regExp1.test(item) ) {
                        searchResult1.push(item); 
                    } else if( regExp2.test(item) ) {
                        searchResult2.push(item);
                    }
                });
                $scope[returnedListName] = [...searchResult1, ...searchResult2];
            }


            function resetReturnedLists(){
                $scope.returnedCities = null;
                $scope.returnedHotels = null;
                $scope.returnedRestaurants = null;
            }

            //this value needs to be different than null in order to make the search
            //possible values: C,H,R type: city, hotel, restaurants
            $scope.selectionType = Search.selectionType ? Search.selectionType : null;

            //make the search
            $scope.doInputSearch = function (type){

                $scope.selectionType = null;

                //update the search result div width
                searchInputPosition = searchInput.getBoundingClientRect();
                searchResult.style.width = `${searchInputPosition.width}px`; 

                //reset the list
                resetReturnedLists();

                //we make the search only if the user typed more than 1 character
                if(type == 'H' && $scope.searchObj.searchedTerm.length > 1){

                    populateResultList($scope.searchObj.searchedTerm, 'cities', 'returnedCities');
                    if ($scope.hotels) populateResultList($scope.searchObj.searchedTerm, 'hotels', 'returnedHotels');

                    $scope.showSearchResult = true;
                } else if (type == 'R' && $scope.searchObjRest.searchedTerm.length > 1){
                    populateResultList($scope.searchObjRest.searchedTerm, 'cities', 'returnedCities');
                    if ($scope.restaurants) populateResultList($scope.searchObjRest.searchedTerm, 'restaurants', 'returnedRestaurants');

                    $scope.showSearchResultRest = true;
                }else {
                    $scope.showSearchResult = false;
                    $scope.showSearchResultRest = false;
                }
            };

            $scope.selectOption = function(option, selectionType){
                //C,H,R type: city, hotel, restaurants
                $scope.selectionType = selectionType;
                if(option == 'H'){
                    $scope.searchObj.searchedTerm = option;
                } else if (option == 'R') {
                    $scope.searchObjRest.searchedTerm = option;
                } else {
                    $scope.searchObjRest.searchedTerm = option;
                    $scope.searchObj.searchedTerm = option;
                }
                resetReturnedLists();
            };
         


        
            /** 
             * Search Bar
             */

            //init date picker values;
            var initalStartDate = $filter('date')(new Date(), 'dd MMM yyyy'); //creat initial start date as today; ex: 21 Oct 2017
            var initalEndDate = $filter('date')(new Date().setDate(new Date().getDate() + 1), 'dd MMM yyyy'); //creat initial end date as today + 1 day
                


            // init search bar values
            if(Search.searchObj == null){
                $scope.searchObj = {
                    searchedTerm : '',
                    startDate : initalStartDate,
                    endDate : initalEndDate,
                    rooms: [1]
                };
            } else{
                $scope.searchObj = Search.searchObj;
            }


            
            /** 
             * DatePicker
             */



            //get the pickers
            var startDatePicker = $('#startDate').datepicker({
                uiLibrary: 'bootstrap4',
                iconsLibrary: 'fontawesome',
                value: Search.searchObj ? Search.searchObj.startDate : initalStartDate, // set the input value
                format: 'dd mmm yyyy',
                weekStartDay: 1,
                minDate: initalStartDate, // set the calendar value
                change: updateFirstCalendarValue,
                hide: function () {
                    startDatePickerVisible = false;
                }
            });
            var endDatePicker = $('#endDate').datepicker({
                uiLibrary: 'bootstrap4',
                iconsLibrary: 'fontawesome',
                value: Search.searchObj ? Search.searchObj.endDate : initalEndDate,
                format: 'dd mmm yyyy',
                weekStartDay: 1,
                minDate: initalEndDate,
                change: updateSecondCalendarValue,
                hide: function () {
                    endDatePickerVisible = false;
                }

            });


            //show the datePickers when clicking on the inputs
            const startDateInput = document.querySelector('#startDate');
            //if we have the element on the page (== we are in the hotels page and not in the restaurants page)
            let startDatePickerVisible = false;
            if(startDateInput) {
                startDateInput.addEventListener('click', () => {
                    if (startDatePickerVisible) {
                        startDatePicker.hide();
                        startDatePickerVisible = false;
                    } else {
                        startDatePicker.show();
                        startDatePickerVisible = true;
                    }
                });
            }


            const endDateInput = document.querySelector('#endDate');
            let endDatePickerVisible = false;
            if(endDateInput) {
                endDateInput.addEventListener('click', () => {
                    if (endDatePickerVisible) {
                        endDatePicker.hide();
                        endDatePickerVisible = false;
                    } else {
                        endDatePicker.show();
                        endDatePickerVisible = true;
                    }
                });
            }



            //update the first calendar values
            function updateFirstCalendarValue(){
                $scope.searchObj.startDate = this.value;
                
                // change the the second date (increment it by one) if it's lower or equal than the one we selected in the first;
                if (new Date(this.value) >= new Date(endDatePicker.value())  ){
                    var newValue = $filter('date')(new Date(this.value).setDate(new Date(this.value).getDate() + 1), 'dd MMM yyyy'); 
                    endDatePicker.value(newValue) ;
                }

                $scope.$apply(); // we integrate jquery library with angularJS framework
            }
            
            
            //update the second calendar values
            function updateSecondCalendarValue(){
                $scope.searchObj.endDate = this.value;

                // change the the first date (decrement it by one) if it's higher or equal than the one we selected in the second;
                if (new Date(this.value) <=  new Date(startDatePicker.value())){
                    var newValue = $filter('date')(new Date(this.value).setDate(new Date(this.value).getDate() - 1), 'dd MMM yyyy'); 
                    startDatePicker.value(newValue) ;
                    
                }

                $scope.$apply();
            }



            /** 
             * DropDown
             */

            //set the maximum number or rooms

            $scope.min = {
                rooms: 0,
                personsPerRoom: 1
            }; 

            $scope.max = {
                rooms: 10,
                personsPerRoom: 4
            }; 
            
            $scope.guestText = 'persoane';
            $scope.updateGuestNumber = function(){
                $scope.guestNumber = $scope.searchObj.rooms.reduce( (a, item) => {return a + item; }, 0);
                $scope.guestText =  $scope.guestNumber != 1 ? 'persoane' : 'persoana';
                updateTextAndValues();
            };
            $scope.updateGuestNumber(); 

            // update the text and values from the dropdown 
            function updateTextAndValues(){
                $scope.roomsText = $scope.searchObj.rooms.length != 1 ? 'camere' : 'camera';
    
                $scope.roomsAndGuests = `${$scope.searchObj.rooms.length} ${$scope.roomsText}   - ${$scope.guestNumber} ${$scope.guestText}`; 
    
                $scope.activeRemove = {
                    rooms: $scope.searchObj.rooms.length == $scope.min.rooms  ? false : true,
                };
    
                $scope.activeAdd = {
                    rooms: $scope.searchObj.rooms.length == $scope.max.rooms  ? false : true,
                };
            }
            updateTextAndValues();

            $scope.decreasePersonsPerRoom = function(index){
                if ($scope.searchObj.rooms[index] != $scope.min.personsPerRoom) {
                    $scope.searchObj.rooms[index] -= 1;
                    $scope.updateGuestNumber();
                }
            }

            $scope.increasePersonsPerRoom = function(index){
                if ($scope.searchObj.rooms[index] != $scope.max.personsPerRoom) {
                    $scope.searchObj.rooms[index] += 1;
                    $scope.updateGuestNumber();
                }
            }


            // add/remove item in the dropdown when the user press on the '-' or '+' sign
            $scope.changeItemQuantity = function(action, itemName){
                if(itemName == 'rooms') {
                    if(action == 'increase' && $scope.searchObj.rooms.length < $scope.max.rooms){
                        $scope.searchObj.rooms.push(1); 
                        $scope.updateGuestNumber();
                    } else if (action == 'decrease' && $scope.searchObj.rooms.length > $scope.min.rooms){
                        $scope.searchObj.rooms.splice($scope.searchObj.rooms.length-1, 1); 
                        $scope.updateGuestNumber();
                    }
                    // setInsertAgeBox();
                }
                updateTextAndValues();
            }; 


            //called when the user tries to make a search
            $scope.submitSearchForm = function(){
                Search.searchObj = $scope.searchObj;
                Search.selectionType = $scope.selectionType;
                //replace undefined values with 0;
                var rooms = $scope.searchObj.rooms.map(item  => item ? item : 0);

                var mainInfoMessage = null;
                //if the user did not selected any option 
                //we prevent him from continue and we show him a warning
                if(!$scope.selectionType){
                    switch($scope.templateName){
                        case ('hotels'):
                            mainInfoMessage = 'Va rugam sa introduceti un nume de oras sau hotel valid';
                            break;
                        default:
                            mainInfoMessage = 'Va rugam sa introduceti un nume de oras valid';
                    }
                    SnackBar.showMainInfoSnackbar(true, mainInfoMessage);
                }else if(rooms.includes(0)){
                    mainInfoMessage = "Va rugam introduceti numarul de persoane in toate camerele";
                    SnackBar.showMainInfoSnackbar(true, mainInfoMessage);
                }else if($scope.selectionType == "C"){
                    Search.getSearchData($scope.selectionType, $scope.searchObj.searchedTerm, rooms, $scope.searchObj.startDate, $scope.searchObj.endDate)
                    .then((response) =>{
                        Search.returnedData = response;
                        $state.go("hotelsCitySearchResult");
                    })
                    .catch((error) => {
                        console.error(error);
                        console.error('Could not retrieve CitiesHotelsRoomsData');
                    });
                }else if($scope.selectionType == "H"){

                    Search.getSearchData($scope.selectionType, $scope.searchObj.searchedTerm, rooms, $scope.searchObj.startDate, $scope.searchObj.endDate)
                    .then((hotel) =>{
                        //go to the hotels details page
                        //transform the name of the hotel to "dash" style and then send it as parameter
                        $state.go('hotelDetails', {
                            hotelURL: $scope.searchObj.searchedTerm.trim().toLowerCase().replace(/\s/g, '-'),
                            hotelName: Object.keys(hotel)[0],
                            hotelDetails: Object.values(hotel)[0]
                        });
                    })
                    .catch((error) => {
                        console.error(error);
                        console.error('Could not retrieve CitiesHotelsRoomsData');
                    });


                }
            };

            /** 
             * Restaurants
             */ 
            
            $scope.submitSearchFormRest = function(){
                Search.searchObjRest = $scope.searchObjRest;
                
                Search.selectionType = $scope.selectionType;

                var mainInfoMessage = null;
                //if the user did not selected any option 
                //we prevent him from continue and we show him a warning
                if(!$scope.searchObjRest.searchedTerm && ($scope.selectionType != 'R' || $scope.selectionType != 'C')){
                    switch($scope.templateName){
                        case ('restaurants'):
                            mainInfoMessage = 'Va rugam sa introduceti un nume de oras sau restaurant valid';
                            break;
                        default:
                            mainInfoMessage = 'Va rugam sa introduceti un nume de oras valid';
                    }
                    SnackBar.showMainInfoSnackbar(true, mainInfoMessage);
                }else if($scope.selectionType == "R"){
                    Search.getSearchDataRest($scope.selectionType, $scope.searchObjRest)
                    .then((response) =>{
                        let restaurant = response[0];
                        // go to the Restaurants details page
                        // transform the name of the restaurant to "dash" style and then send it as parameter
                        $state.go('restaurantDetails', {
                            restaurantURL: $scope.searchObjRest.searchedTerm.trim().toLowerCase().replace(/\s/g, '-'),
                            restaurantName: restaurant.$id,
                            restaurantDetails: restaurant,
                            searchedObject: $scope.searchObjRest
                        });
                    })
                    .catch((error) => {
                        console.error(error);
                        console.error('Could not retrieve CitiesRestaurantsRoomsData');
                    });

                }else if($scope.selectionType == "C"){
                    Search.getSearchDataRest($scope.selectionType + 'R', $scope.searchObjRest)
                    .then((response) =>{
                        Search.returnedData = response;
                        Search.searchedObject = $scope.searchObjRest;
                        $state.go('restaurantsCitySearchResult');
                    })
                    .catch((error) => {
                        console.error(error);
                        console.error('Could not retrieve CitiesRestaurantsRoomsData');
                    });

                }
            }
  
			
            var initialRestDate = $filter('date')(new Date(), 'dd MMM yyyy'); 
            
			if(Search.searchObjRest == null){
                $scope.searchObjRest = {
                    searchedTerm : '',
                    restDate : initialRestDate,
                    restTime : '',
                    person: 1
                };
            } else{
                $scope.searchObjRest = Search.searchObjRest;
            }
            
            //get the pickers
            var restDatePicker = $('#restDate').datepicker({
                uiLibrary: 'bootstrap4',
                iconsLibrary: 'fontawesome',
                value: initialRestDate, // set the input value
                format: 'dd mmm yyyy',
                weekStartDay: 1,
                minDate: initialRestDate, // set the calendar value
                change: updateRestCalendarValue,
                hide: function () {
                    restDatePickerVisible = false;
                }
            });
			
			$('#restTime').timepicker({
				'scrollDefault': 'now' , 
				'disableTextInput': true,
				'timeFormat': 'H:i'
            });
            $timeout(function (){
                let x =  $('#restTime').timepicker('setTime', new Date());
                $scope.searchObjRest.restTime = x.val();
                $scope.$apply();
            },100)


            
            // $('#restTime').on('showTimepicker', function() {
            //     console.log()
            // }

            $('#restTime').on('changeTime', function() {
                $scope.searchObjRest.restTime = $(this).val();
                $scope.$apply();
            });
			

            
			$scope.personText = $scope.searchObjRest.person != 1 ? 'persoane' : 'persoana';
        
            
            $scope.changeItemQuantityRest = function(action) {
                if(action == 'decrease' && $scope.searchObjRest.person != 1){
                    $scope.searchObjRest.person --;
                } else if (action == 'increase' && $scope.searchObjRest.person != 10){
                    $scope.searchObjRest.person ++;
                }
                $scope.personText = $scope.searchObjRest.person != 1 ? 'persoane' : 'persoana';
            }    

            function updateRestCalendarValue(){
                $scope.searchObjRest.restDate = this.value;
                $scope.$apply();
            }
			
        }

        return {
            restrict: 'E',
            templateUrl: getTemplateUrl,
            controller: searchController,
            replace: true,
            scope: {
                templateName: '@',
                addToSearch: '@'
            }
        };

    }<file_sep>/pages/restaurantsPages/restaurantsCitySearchResult/restaurantsCitySearchResult.js
angular
  .module('Restaurants')
  .controller("restaurantsCitySearchResultCtrl", restaurantsCitySearchResultCtrl);

  function restaurantsCitySearchResultCtrl($scope, Search){


    $scope.restaurants = Search.returnedData;
    $scope.searchedObject = Search.searchedObject;

    $scope.sortingOptions = [
      {
        label: "Crescator dupa nota",
        criteria: '+userRating'
      },
      {
        label: "Descrescator dupa nota",
        criteria: '-userRating'
      }
    ];

    $scope.orderCriteria = '+userRating'
  

    $scope.showError = $scope.restaurants.length  == 0;

    if($scope.showError){
      $scope.errorMessage = "Ne pare rau dar nu am gasit mese disponibile in perioada selectata !";
    }
  }<file_sep>/common/directives/searchResultTile/searchResultTile.js
angular
  .module("Dsrh")
  .directive("searchResultTile", searchResultTile);

  function searchResultTile(ERRORS, CURRENCIES){


    function getTemplateUrl(elem, attrs){
      return 'common/directives/searchResultTile/' + attrs.templateName + 'SearchResultTile.html';
    }



    function searchResultTileController($scope, $state){

      //if we don't have an image show the default one
      if(!$scope.itemValue.photos || !$scope.itemValue.photos.main){
        $scope.itemValue.photos = {
          main : ERRORS.IMAGE_NOT_FOUND
        };
      }

      $scope.setProperCurrency = function(totalPrice){

        //get the currency code
        const [price, currencyCode] = totalPrice.split(" ");
        //and use it to get the currency name
        const currencyName = currencyCode ? CURRENCIES[currencyCode] : CURRENCIES.DEFAULT;
  
        return `${price} ${currencyName}`;
      }

      //create an array based on stars numbers to iterate over it with ng-repeat
      $scope.getStarsNumber = function(){
        return new Array($scope.itemValue.stars);
      };

      $scope.goToHotel = function(){
        //go to the hotels details page
        //transform the name of the hotel to "dash" style and then send it as parameter
        $state.go('hotelDetails', {
          hotelURL: $scope.itemName.trim().toLowerCase().replace(/\s/g,'-'),
          hotelName: $scope.itemName,
          hotelDetails: $scope.itemValue,
        });
      };


      $scope.goToRestaurant = function(){
        //go to the restaurants details page
        //transform the name of the restaurant to "dash" style and then send it as parameter
        $state.go('restaurantDetails', {
          restaurantURL: $scope.itemName.trim().toLowerCase().replace(/\s/g,'-'),
          restaurantName: $scope.itemName,
          restaurantDetails: $scope.itemValue,
          searchedObject: $scope.searchedObject,
        });
      };

    }


    return {
      restrict: "E",
      templateUrl: getTemplateUrl,
      controller: searchResultTileController,
      // replace: true,
      scope: {
        templateName: "@",
        itemName: "<",
        itemValue: "<",
        searchedObject:"<?"
      }
    };

  }<file_sep>/common/filters/generalFilters.js
angular
  .module("Dsrh")
  .filter("generateDropDown", function($filter){

    function price(a, b){
      return a.price.split(' ')[0] - b.price.split(' ')[0];
    }

    return function(dropDownOptions, toBeRemoved, currentItemIndex){

      //we need to make a deep copy of the array in order to not alter the source
      const cToBeRemoved = angular.copy(toBeRemoved);

      //we substract the current element from the 'toBeRemoved' list
      cToBeRemoved.splice(currentItemIndex, 1); 

      //create a string with all of the options we want to remove
      let toBeRemovedString = cToBeRemoved.reduce( (string, item) =>  string += JSON.stringify(item), '');

      //keep only the options which are not included in the 'toBeRemovedString';
      return dropDownOptions
              .filter(option => !toBeRemovedString.includes(option.name))
              .sort(price);
    }
  })
  .filter("enhancedOrderBy", function(){


    return function(results, criteria){
      let asc = criteria.slice(0, 1) == '+' ? true : false;
      let orderByCriteria = criteria.slice(1, criteria.length);
      if(orderByCriteria !== "totalPrice"){

        return results.sort( (a, b) =>  {
          if(asc){
            return a[orderByCriteria] - b[orderByCriteria];
          } else {
            return b[orderByCriteria] - a[orderByCriteria];
          }
        })

      } else {

        return results.sort( (a, b) =>  {
          if(asc){
            return Number(a[orderByCriteria].split(' ')[0]) - Number(b[orderByCriteria].split(' ')[0]);
          } else {
            return Number(b[orderByCriteria].split(' ')[0])  - Number(a[orderByCriteria].split(' ')[0]);
          }
        })

      }
    }
  });
<file_sep>/pages/restaurantsPages/restaurantDetails/restaurantDetails.js
angular
  .module('Restaurants')
  .controller('restaurantDetailsCtrl', restaurantDetailsCtrl);

  function restaurantDetailsCtrl(RestaurantDetails, $scope, $stateParams, $sce, Utilis, SnackBar, $timeout, Auth){


    $scope.restaurantData = $stateParams;

    $scope.firebaseUser = null;
    //every time the authentification state of the user changes we update the scope
    Auth.auth.$onAuthStateChanged((firebaseUser) => {
      $scope.firebaseUser = firebaseUser && firebaseUser.emailVerified ? firebaseUser : null;
      if(!firebaseUser) return;
      RestaurantDetails.retrieveUserInfo(firebaseUser.uid).$loaded().then((data)=>{
        $scope.userData = {};
        $scope.userData.fullName = data.lastName + ' ' + data.firstName;
        $scope.userData.email = data.email;
        $scope.userData.phone = data.phone;
      });
    });
    
    $scope.hasComments = Object.keys($scope.restaurantData.restaurantDetails.comments).length > 0 ? true : false; 
    

    if(!$scope.restaurantData.restaurantDetails.validTables){
      $scope.errorMessage = "Ne pare rau dar nu am gasit mese disponibile in perioada selectata !";
    }

    $scope.sanitizeDescription = function(){
      return $sce.trustAsHtml($scope.restaurantData.restaurantDetails.description);
    };


    $scope.getPersonsText = function (capacity){
      return capacity > 1 ?  'persoane' : 'persoana';
    };

    //tranform the dates from the calendar to be the same as the ones received from the database
    //from '25 May 20018" to "2018-05-25"
    function transformDates(dateFromCalendar) {
      let date = new Date(dateFromCalendar);
      //we make sure to add a '0' to each date 
      //for example "2018-5-4" becomes "2018-05-04"
      //otherwise ther will be a 2-3 hour  diference between this date and the one which we receve from the databse when we transfomr them in miliseconds
      return `${date.getFullYear()}-${date.getMonth()+1 < 10 ? '0' : ''}${date.getMonth()+1}-${date.getDate() < 10 ? '0' : ''}${date.getDate()}`;
    }
    $scope.restaurantData.searchedObject.restDate = transformDates($scope.restaurantData.searchedObject.restDate);

    if ($scope.restaurantData.restaurantDetails.validTables)$scope.selectedTable = $scope.restaurantData.restaurantDetails.validTables[0];

    //do the restaurant reservation
    $scope.reservationMade = false;
    $scope.makeRestaurantReservation = function() {

     RestaurantDetails.makeRestaurantReservation($scope.restaurantData.restaurantName, $scope.selectedTable.tableName, $scope.restaurantData.searchedObject, $scope.userData)
        .then( () => {

          SnackBar.showMainInfoSnackbar(false, 'Rezervarea a fost facuta cu success', true, true);

          $timeout(() => {
            $scope.reservationMade = true;
          }, 2000);
  
          $timeout(() => {
            $scope.showSuccess = true;
          }, 4000);
        
        })
        .catch( err => {
          SnackBar.showMainInfoSnackbar(true, 'A aparut o problema la efectuarea rezervarii');
          console.log(err);
        })

    }


    $scope.restaurantData.restaurantDetails.comments = RestaurantDetails.objectToSortedArray($scope.restaurantData.restaurantDetails.comments);
    
    //calculate average rating of the comments
    function calculateAverage(comments){
      if(!comments) return;

      return comments.reduce( (acc, item) => acc+=item.rating, 0)/comments.length;
    }
    $scope.ratingAverage = calculateAverage($scope.restaurantData.restaurantDetails.comments);
    
    //round to specific precision (see MDN)
    function precisionRound(number, precision) {
      var factor = Math.pow(10, precision);
      return Math.round(number * factor) / factor;
    }
    
    $scope.ratings = [0,1,2,3,4,5,6,7,8,9,10];
    $scope.comment = {
      rating: $scope.ratings[0]
    };

    $scope.changeLabel = function(label){
      return label.replace('table', 'Masa ');
    }



    $scope.postCommentAndRatingRest = function(){

      $scope.comment.userName = $scope.firebaseUser.displayName;
      //create a "2018-05-29" date format and remove the time
      $scope.comment.date = new Date().toISOString().split("T")[0];
      //calculate the new rating
      const avr = ($scope.ratingAverage + $scope.comment.rating ) / 2;
      const newRating = precisionRound(avr, 1)
      console.log(newRating)
      //make a full copy of the comment because we will reset it
      const commentCopy = angular.copy($scope.comment);
      
      RestaurantDetails.postCommentAndRatingRest($scope.restaurantData.restaurantName, commentCopy, newRating)
        .then(() => {
          $scope.restaurantData.restaurantDetails.comments.unshift(commentCopy);
        })
        .catch((err) => {
          SnackBar.showMainInfoSnackbar(true, 'A aparut o problema la postarea comentariului');
          console.log(err);
        });

      //refersh the comment
      $scope.comment = {
        rating: $scope.ratings[0]
      };
    };

  }<file_sep>/pages/restaurantsPages/mainPage/mainRestaurants.js
angular
    .module("Restaurants", [])
    .controller('mainRestaurantsCtrl', mainRestaurantsCtrl)

    mainRestaurantsCtrl.$inject = ['$state'];
    function mainRestaurantsCtrl($state){

    };<file_sep>/common/constants/constants.js

let errors = {
  IMAGE_NOT_FOUND: "https://firebasestorage.googleapis.com/v0/b/dsrh-dp.appspot.com/o/image_not_found.png?alt=media&token=<PASSWORD>"
};

let currencies = {
  DEFAULT: 'lei',
  RON: 'lei',
  E: 'euro'
};

let hotel_facilities = {
  wifi : ["WiFi gratuit inclus", "057-wifi.svg"],
  trans_aero: ["transfer de la și/sau la aeroport", "035-taxi.svg"],
  anim_comp: ["acceptă animale de companie", "073-information.svg"],
  cam_nef: ["camere pentru nefumători", "066-no-smoking.svg"],
  non_stop: ["recepţie deschisă nonstop", "024-open.svg"],
  terasa: ["terasă", "018-coffee-cup.svg"],
  bar: ["bar", "011-syrup.svg"],
  piscina: ["piscină", "068-swimming-pool.svg"],
  piscina_in: ["piscină interioară", "068-swimming-pool.svg"],
  parcare: ["parcare", "047-parking.svg"],
  spa_and_wellness: ["spa și centru de wellness", "042-towel.svg"],
  fitness: ["centru de fitness", "045-dumbbell.svg"],
  tv: ["TV", "069-television.svg"]
}

angular
  .module("Dsrh")
  .constant('ERRORS', errors)
  .constant('CURRENCIES', currencies)
  .constant('FACILITIES', hotel_facilities);<file_sep>/pages/hotelsPages/hotelsCitySearchResult/hotelsCitySearchResult.js
angular
  .module('Hotels')
  .controller("hotelsCitySearchResultCtrl", hotelsCitySearchResultCtrl);

  function hotelsCitySearchResultCtrl($scope, Search){


    $scope.hotels = [];
    for(let key in Search.returnedData){
      $scope.hotels.push(Search.returnedData[key]);
    }

    $scope.sortingOptions = [
      {
        label: "Crescator dupa nr. de stele",
        criteria: '+stars'
      },
      {
        label: "Descrescator dupa nr. de stele",
        criteria: '-stars'
      },
      {
        label: "Crescator dupa nota",
        criteria: '+userRating'
      },
      {
        label: "Descrescator dupa nota",
        criteria: '-userRating'
      },
      {
        label: "Crescator dupa pret",
        criteria: '+totalPrice'
      },
      {
        label: "Descrescator dupa pret",
        criteria: '-totalPrice'
      }
    ];

    $scope.orderCriteria = '+stars'
  

    $scope.showError = $scope.hotels.length  == 0;

    if($scope.showError){
      $scope.errorMessage = "Ne pare rau dar nu am gasit camere disponibile in perioada selectata !";
    }
  }<file_sep>/common/services/utilis.js
angular
  .module('Dsrh')
  .factory('Utilis', Utilis);


function Utilis(CURRENCIES){

  function transformCurrency(totalPrice){
    //get the currency code
    const [price, currencyCode] = totalPrice.split(" ");
    //and use it to get the currency name
    const currencyName = currencyCode ? CURRENCIES[currencyCode] : CURRENCIES.DEFAULT;

    return `${price} ${currencyName}`;
  }

  let rObj = {};
  rObj.transformCurrency = transformCurrency;

  return rObj;
}<file_sep>/common/directives/search/searchFactory.js
angular
  .module('Dsrh')
  .factory("Search", Search);


  function Search(Database){
    
    const src = {};

    src.init = init;
    src.initDone = false;
    src.cities = [];
    src.getCitiesList = getCitiesList;
    src.setCitiesList = setCitiesList;
    src.hotels = [];
    src.getHotelsList = getHotelsList;
    src.setHotelsList = setHotelsList;
    src.restaurants = [];
    src.getRestaurantsList = getRestaurantsList;
    src.setRestaurantsList = setRestaurantsList;
    src.getSearchData = getSearchData; 
    src.getSearchDataRest = getSearchDataRest;
    src.returnedData = null;
    src.searchObj = null;
    src.selectionType = null;


    function init(){
      return Promise.all([
        getDbLists('getCitiesList','cities'),
        getDbLists('getHotelsList','hotels'),
        getDbLists('getRestaurantsList','restaurants')
      ]);
    }

    /** 
     * Retrieve cities list
     */
    function getDbLists(listFunction, objectName) {
      return new Promise(function(resolve, reject){
        Database
          [listFunction]() // retrieve the list
          .$loaded() //wait until the response arrives
          .then(result => {
            if(objectName == 'cities'){
              src[objectName] = result.map(item => item.$value );  
            } else {
              src[objectName] = result.map(item => item.$id);  
            }
            resolve();
          })
          .catch(error => {
            console.log(error);
            reject();
          });
      });
    }

    function getCitiesList() {
      return this.cities;
    }

    function setCitiesList() {
      return this.cities;
    }

    function getHotelsList() {
      return this.hotels;
    }

    function setHotelsList() {
      return this.hotels;
    }

    function getRestaurantsList() {
      return this.restaurants;
    }

    function setRestaurantsList() {
      return this.restaurants;
    }




    //when we make the search we need to decide if we look after a city or a specific hotel/restaurant
    function getDesiredFunctionName(item) {

      let functionName = null;

      const data = ['C', 'H', 'CR','R'];
          switch (item) {
              case data[0] :
                  functionName =  'getCityHotelsData';
                  break; 
              case data[1] :
                  functionName =  'getHotelData';
                  break; 
              case data[2] :
                functionName =  'getCityRestaurantsData';
              break; 
              case data[3] :
                functionName =  'getRestaurantData';
              break; 
          }
       
      return functionName;
    }



    //tranform the dates from the calendar to be the same as the ones received from the database
    //from '25 May 20018" to "2018-05-25"
    function transformDates(dateFromCalendar) {
      let date = new Date(dateFromCalendar);
      //we make sure to add a '0' to each date 
      //for example "2018-5-4" becomes "2018-05-04"
      //otherwise ther will be a 2-3 hour  diference between this date and the one which we receve from the databse when we transfomr them in miliseconds
      return `${date.getFullYear()}-${date.getMonth()+1 < 10 ? '0' : ''}${date.getMonth()+1}-${date.getDate() < 10 ? '0' : ''}${date.getDate()}`;
    }


    // get the number of days
    function getRequestedDays(startDate, endDate){
      //86400000 represents a day in miliseconds
      return (new Date(endDate) - new Date(startDate))/86400000;
    } 
    

    //check to see if the hotel has any rooms available in the seclected time period
    function checkRoomAvailability(occupied, startDate, endDate){
      let hasAvailablePeriod = true;

      let dStart = new Date(startDate);
      let dEnd = new Date(endDate);

      if(Object.values(occupied).length != 0) {
        for(var period of Object.values(occupied)){

          let pdStart = new Date(period.startDate);
          let pdEnd = new Date(period.endDate);
  
          if(pdEnd <= new Date()){
            continue;
          }
  
          if(dStart < pdStart){
            hasAvailablePeriod = (dEnd <= pdStart) ? true : false;
  
          }else if(dStart >=  pdEnd){
            hasAvailablePeriod = (dEnd > pdEnd) ? true : false;
  
          }else{
            hasAvailablePeriod = false;
          }
  
        }
      }

      return hasAvailablePeriod;
    }


    //sort the rooms by the price
    //put the cheapest first
    function sortRooms(a, b){
      return Number(a.price.split(" ")[0]) - Number(b.price.split(" ")[0]);
    }


    //check to see if the hotel has the requested rooms
    function checkRoomsMatchCriteria(req, roomsAvailable){
      //copy the requests
      var cReq = angular.copy(req);
      var searchResult = [];
      roomsAvailable.forEach((room) => {
        var index = cReq.indexOf(parseInt(room.capacity));
        if(index > -1){
            //push the result
            searchResult.push(room);
            //delete the requested room
            cReq.splice(index,1);
        } 
      });
      // console.log({req, cReq});
      return searchResult.length == req.length ? searchResult : null;
    }


    function calculateTotalPrice(rooms, requestedDays){


      // take each room price and multiply it with the requested days
      // then add them to create the final sum
      const totalPrice = rooms.reduce( (sum, room)  => sum += Number(room.price.split(" ")[0]) * Number(requestedDays), 0);

      //get the currency code for one of the rooms 
      const currencyCode = rooms[0].price.split(" ")[1];

      return `${totalPrice} ${currencyCode}`;


    }


    function generateHotelList(validHotels, hotel,  startDate, endDate, requestedDays, validRooms, sortedAvailableRooms){
      validHotels[hotel.$id] = hotel;
      validHotels[hotel.$id].startDate = startDate;
      validHotels[hotel.$id].endDate = endDate;
      validHotels[hotel.$id].requestedDays = requestedDays;
      if(validRooms) {
        validHotels[hotel.$id].totalPrice = calculateTotalPrice(validRooms, requestedDays); 
        validHotels[hotel.$id].validRooms = validRooms;
        validHotels[hotel.$id].sortedAvailableRooms = sortedAvailableRooms;
      }
    }


    function getSearchData(searchType, searchedTerm, requestedRooms, startDateFromCalendar, endDateFromCalendar) {
      let fN = getDesiredFunctionName(searchType);

      return Database[fN](searchedTerm)
        .then((response) =>{

          var validHotels = {};

          //we need to create a deep copy in order to lose of the automatic coupling with the database
          const hotels = response.length > 1 ? [...angular.copy(response)] : [angular.copy(response)];
          
          let startDate = transformDates(startDateFromCalendar);
          let endDate = transformDates(endDateFromCalendar);
          let requestedDays = getRequestedDays(startDate, endDate);


          //we check each hotel
          hotels.forEach((hotel) => {
            
            let availableRooms = [];
            //and then each room
            for(let room in hotel.rooms){
              //roomData is the actual room information
              let roomData = hotel.rooms[room];
              //we test to see if the room is free 
              let isRoomAvailable = checkRoomAvailability(roomData.occupied, startDate, endDate);
              //and if it's free we add it on the list;
              if(isRoomAvailable){
                availableRooms.push({name: room, capacity: roomData.capacity, price: roomData.price});
              } 
            }

            //if the hotels has rooms available for the requested time
            //we sort them and then we check them to see if they match our rooms and person serach
            if(availableRooms.length > 0){
              let sortedAvailableRooms =  availableRooms.sort(sortRooms);
              let validRooms = checkRoomsMatchCriteria(requestedRooms, sortedAvailableRooms);
              
              if(validRooms) generateHotelList(validHotels, hotel, startDate, endDate, requestedDays, validRooms, sortedAvailableRooms);
            }
          });

          //in case of a direct hotel search
          //we still return the hotel even if does not have any valid rooms
          if(searchType === 'H' &&  Object.keys(validHotels).length === 0){
            generateHotelList(validHotels, response, startDate, endDate, requestedDays, null, null);
          }

          return validHotels; 

        });
    };

    function checkRestaurantValidity(restaurant, searchedObject){
      let validTables = [];
      for(let table in restaurant.tables){
        if(Number(restaurant.tables[table].capacity) == Number(searchedObject.person)) {
          let validTable = true;
          for (let occId of Object.keys(restaurant.tables[table].occupied)){
            let occObj = restaurant.tables[table].occupied[occId]

            let date = transformDates(searchedObject.restDate);
            if(occObj.restDate == date) {
              let [y,m,d] = date.split('-');

              let [hU,mU] = searchedObject.restTime.split(':');
              let dateU = new Date(y,m,d, hU, mU).getTime();

              let [hD,mD] = occObj.restTimeStart.split(':'); 
              let dateD = new Date(y,m,d, hD, mD).getTime();

              //10800000 = 3 hours miliseconds
              let RESERVATION_TIME = 10800000;

              if( (dateU > dateD - RESERVATION_TIME) && (dateU < dateD + RESERVATION_TIME)){
                validTable = false;
              } else {
                validTable = true;
              }
            }
          }
          //at the end if the table is valid we push it ot the lsit of validTables
          if(validTable){
            let tableObj = angular.copy(restaurant.tables[table]);
            tableObj.tableName = table;
            validTables.push(tableObj);
          }
        }
      }
      return validTables; 
    }

    function getSearchDataRest(searchType, searchedObject){
      const {searchedTerm, restDate, restTime, person} = searchedObject;
      let fN = getDesiredFunctionName(searchType);
      let validRestaurants = [];
      return Database[fN](searchedTerm)
        .then((response) => {

          const restaurants = response.length > 1 ? [...angular.copy(response)] : [angular.copy(response)];

          restaurants.forEach((restaurant) => {
            let validTables = checkRestaurantValidity(restaurant, searchedObject);
            if(validTables.length > 0) {
              restaurant.validTables = validTables;
              validRestaurants.push(restaurant);
            }
          });
          
          //if it's a direct restaurant search and its not valid we still return the restaurant
          //for informational purpose
          if(searchType == 'R' && validRestaurants.length == 0){
            validRestaurants.push(restaurants[0]);
          }
          
          console.log(validRestaurants);
          return validRestaurants;
          
        })
    };


    return src;
  }

<file_sep>/pages/hotelsPages/hotelDetails/hotelDetails.js
angular
  .module('Hotels')
  .controller('hotelDetailsCtrl', hotelDetailsCtrl);

  function hotelDetailsCtrl(HotelDetails, $scope, $stateParams, $sce, FACILITIES, Utilis, SnackBar, $timeout, Auth){

    $scope.facilities = FACILITIES;


    $scope.hotelData = $stateParams;



    $scope.firebaseUser = null;
    //every time the authentification stae of the user changes we update the scope
    Auth.auth.$onAuthStateChanged((firebaseUser) => {
      $scope.firebaseUser = firebaseUser && firebaseUser.emailVerified ? firebaseUser : null;
      if(!firebaseUser) return;
      HotelDetails.retrieveUserInfo(firebaseUser.uid).$loaded().then((data)=>{
        $scope.userData = {};
        $scope.userData.fullName = data.lastName + ' ' + data.firstName;
        $scope.userData.email = data.email;
        $scope.userData.phone = data.phone;
      });
    });
    
    $scope.hasComments = Object.keys($scope.hotelData.hotelDetails.comments).length > 0 ? true : false; 
    

    if(!$scope.hotelData.hotelDetails.validRoom){
      $scope.errorMessage = "Ne pare rau dar nu am gasit camere disponibile in perioada selectata !";
    }

    $scope.sanitizeDescription = function(){
      return $sce.trustAsHtml($scope.hotelData.hotelDetails.description);
    };

    //split the rooms by their capcaity
    function splitRoomsByCapacity (rooms){
      if (!rooms) return;
      if (!$scope.split) $scope.split = {};

      rooms.forEach(function(room){
        const splitName = 'validRoom'+room.capacity;
        if (!$scope.split[splitName]) $scope.split[splitName] = [];
        $scope.split[splitName].push(room);
      });

    }
    splitRoomsByCapacity($scope.hotelData.hotelDetails.validRooms);


    $scope.generateDropDownLabel = function(name, price){
      return `${name} - ${Utilis.transformCurrency(price)}`;
    };


    $scope.getPersonsText = function (capacity){
      return capacity > 1 ?  'persoane' : 'persoana';
    };

    $scope.getRoomsText = function (length){
      return length > 1 ?  'Camerele selectate' : 'Camera selectata';
    };

    $scope.getTotalsRooms = function(rooms){
      if(!rooms) return '';
      const text = rooms.length > 1 ? 'camere' : 'camera';
      return `${rooms.length} ${text}`;
    };

    $scope.getTotalsPersons = function(rooms){
      if(!rooms) return '';

      const numberOfPersons = rooms.reduce( (sum, room) =>  sum += Number(room.capacity), 0);
      const text = numberOfPersons > 1 ? 'persoane' : 'persoana';
      return `${numberOfPersons} ${text}`;
    };

    $scope.getTotalsPrice = function(rooms){
      if(!rooms) return '';
      let arr = [];
      for(let item in rooms){
        arr = arr.concat(rooms[item]);
      }
      const totalPrice = arr.reduce( (sum, room) =>  sum += Number(room.price.split(' ')[0]), 0) + ' ' + arr[0].price.split(' ')[1];
      return `${Utilis.transformCurrency(totalPrice)}`;
    };

    //make a list with all the selected rooms
    //we will use it to update the database

    function roomsToUpdate(selectedObj){
      const rooms = [];

      for(let item of Object.keys(selectedObj)){
        selectedObj[item].forEach( room => rooms.push(room.name) );
      }

      return rooms;
    }

    //do the hotel reservation
    $scope.reservationMade = false;
    $scope.makeHotelReservation = function() {

      HotelDetails.makeHotelReservation($scope.hotelData.hotelName, roomsToUpdate($scope.split), $scope.hotelData.hotelDetails.startDate, $scope.hotelData.hotelDetails.endDate, $scope.userData)
        .then( () => {

          SnackBar.showMainInfoSnackbar(false, 'Rezervarea a fost facuta cu success', true, true);

          $timeout(() => {
            $scope.reservationMade = true;
          }, 2000);
  
          $timeout(() => {
            $scope.showSuccess = true;
          }, 4000);
        
        })
        .catch( err => {
          SnackBar.showMainInfoSnackbar(true, 'A aparut o problema la efectuarea rezervarii');
          console.log(err);
        })

    }


    $scope.hotelData.hotelDetails.comments = HotelDetails.objectToSortedArray($scope.hotelData.hotelDetails.comments);
    
    //calculate average rating of the comments
    function calculateAverage(comments){
      if(!comments) return;

      return comments.reduce( (acc, item) => acc+=item.rating, 0)/comments.length;
    }
    $scope.ratingAverage = calculateAverage($scope.hotelData.hotelDetails.comments);
    
    //round to specific precision (see MDN)
    function precisionRound(number, precision) {
      var factor = Math.pow(10, precision);
      return Math.round(number * factor) / factor;
    }
    
    $scope.ratings = [0,1,2,3,4,5,6,7,8,9,10];
    $scope.comment = {
      rating: $scope.ratings[0]
    };
    $scope.postCommentAndRating = function(){

      $scope.comment.userName = $scope.firebaseUser.displayName;
      //crate a "2018-05-29" date format and remove the time
      $scope.comment.date = new Date().toISOString().split("T")[0];
      //calculate the new rating
      const avr = ($scope.ratingAverage + $scope.comment.rating ) / 2;
      const newRating = precisionRound(avr, 1)
      console.log(newRating)
      //make a full copy of the comment because we will reset it
      const commentCopy = angular.copy($scope.comment);
      
      HotelDetails.postCommentAndRating($scope.hotelData.hotelName, commentCopy, newRating)
        .then(() => {
          $scope.hotelData.hotelDetails.comments.unshift(commentCopy);
        })
        .catch((err) => {
          SnackBar.showMainInfoSnackbar(true, 'A aparut o problema la postarea comentariului');
          console.log(err);
        });

      //refersh the comment
      $scope.comment = {
        rating: $scope.ratings[0]
      };
    };


  }<file_sep>/pages/userRegistration/userRegistration.js
angular.module("Dsrh")
    .controller('userRegistrationCtrl', userRegistrationCtrl);


    userRegistrationCtrl.$inject = ['$scope', 'Auth', '$state', 'Database', 'UserDetails'];
    function userRegistrationCtrl($scope, Auth, $state, Database, UserDetails){

        $scope.dayList = generateDates(1,31);
        $scope.monthList = generateDates(1,12);
        $scope.yearList = generateDates(1950, new Date().getFullYear()-18);

        $scope.forms = {
            userRegistrationForm : null
        };

        $scope.formDetails = {
            firstName: '',
            lastName: '',
            password: '',
            password2: '',
            email : '',
            displayName: '',
            address: '',
            dob:[$scope.dayList[0], $scope.monthList[0], $scope.yearList[$scope.yearList.length-1]],
            phone:'',
            gender: 'male'
        };

        if(UserDetails) {
            $scope.userDetails = UserDetails;
            $scope.formDetails = {
                firstName: UserDetails.firstName,
                lastName: UserDetails.lastName,
                password: <PASSWORD>,
                password2: <PASSWORD>,
                email : UserDetails.email,
                displayName: UserDetails.displayName,
                address: UserDetails.address,
                dob:[UserDetails.dob[0], UserDetails.dob[1], UserDetails.dob[2]],
                phone: UserDetails.phone,
                gender: UserDetails.gender
            };
        } else {
            $scope.userDetails = null;
            $scope.formDetails = {
                firstName: '',
                lastName: '',
                password: '',
                password2: '',
                email : '',
                displayName: '',
                address: '',
                dob:[$scope.dayList[0], $scope.monthList[0], $scope.yearList[$scope.yearList.length-1]],
                phone:'',
                gender: 'male'
            };
        }

        //for testing purpose
        // $scope.formDetails = {
        //     "firstName": "aaaaaaa",
        //     "lastName": "bbaaaaaaa",
        //     "password": "<PASSWORD>",
        //     "password2": "<PASSWORD>",
        //     "email": "<EMAIL>",
        //     "displayName": "soky799x",
        //     "address": "aaaaaaaaaaaa",
        //     "dob": [
        //       "01",
        //       "01",
        //       "2000"
        //     ],
        //     phone:0763547363,
        //     gender: 'male'
        //   };

        $scope.errorsMsg = ["Acest camp este obligatoriu", ' Minim 3 caractere', ' Maxim 16 caractere', ' Minim 6 caractere', ' Cele doua parole nu se potrivesc', ' Adresa de mail nu este valida', ' Numele de utilizator este deja folosit', ' Maxim 50 caractere',];
        
        //generate numbers for the dob picker
        function generateDates(start, end){
            let list = [];
            
            for(start; start<=end; start++){
                let numToPush = start < 10 ? '0'+ start.toString() : start.toString();
                list.push(numToPush);
            }
            
            return list;
        }
        

        // take the form element
        const form = document.querySelector('#userRegistrationForm');

        // and listen for the submit event (when the submit button is clicked)
        form.addEventListener('submit', function (event) {
            if ($scope.forms.userRegistrationForm.$invalid) {
                event.preventDefault();
                event.stopPropagation();
            }else if(UserDetails){
                $scope.updateUser($scope.formDetails);
            }else{
                $scope.createUser($scope.formDetails);
            }

        });



        $scope.isFormLoading = false;

        $scope.authResponseMessage = {
            success: '',
            title: '',
            message: ''
        };


        /** 
         * Create a user with email and password
         */
        $scope.createUser = function(userInfo){
            $scope.isFormLoading = true;
            $scope.receivedError = '';
            log("Start 'Create User'");
            Auth.createUser(userInfo)
                .then(() => {
                    log("End 'Create User'");
                    $scope.isFormLoading = false;
                    $scope.authResponseMessage = {
                        success: true,
                        title: 'Felicitari!',
                        message:'Felicitari, contul tau a fost creat. Un email de verificare a fost trimis la adresa dumneavoastra. Contul se va activa numai dupa confirmarea acestuia (urmand pasii din email).'
                    };
                    $('#authResponseMessageModal').modal('toggle');
                })
                .catch((err) => {
                    $scope.isFormLoading = false;
                    $scope.authResponseMessage = {
                        success: false,
                        title: 'Eroare!',
                        message:'A aparut o problema la crearea contului.'
                    };
                    $scope.receivedError = $scope.authErrors[err.code] || '';
                    $('#authResponseMessageModal').modal('toggle');
                    console.log(err);
                });
        };

        $scope.updateUser = function(userInfo){
            $scope.isFormLoading = true;
            $scope.receivedError = '';
            log("Start 'Update User'");
            Auth.updateUser(userInfo)
                .then(() => {
                    log("End 'Update User'");
                    $scope.isFormLoading = false;
                    $scope.authResponseMessage = {
                        success: true,
                        title: 'Felicitari!',
                        message: 'Contul tau a fost modificat cu success.'
                    };
                    $('#authResponseMessageModal').modal('toggle');
                })
                .catch((err) => {
                    $scope.isFormLoading = false;
                    $scope.authResponseMessage = {
                        success: false,
                        title: 'Eroare!',
                        message:'A aparut o problema la modificarea contului tau.'
                    };
                    $scope.receivedError = $scope.authErrors[err.code] || '';
                    $('#authResponseMessageModal').modal('toggle');
                    console.log(err);
                });
        };


        //listen for the close event on the modal
        $('#authResponseMessageModal').on('hidden.bs.modal', function () {

            //destroy the modal
            $('#authResponseMessageModal').modal('dispose');

            //if it's a success go back to the main page;
            if($scope.authResponseMessage.success == true) {
                $state.go('hotels');
            }
        });

        $scope.authErrors = {
            "auth/email-already-in-use": 'Adresa de email este deja folosita',
            "auth/invalid-email" : "Adresa de mail este invalida",
            "auth/weak-password" : "<PASSWORD>",
        };

        $scope.checkingUsername = false;
        $scope.userExists = false;
        $scope.checkValidUser = function(userName) {
            if (UserDetails && UserDetails.displayName && UserDetails.displayName == userName){
                // we don't want to show an error if the user is making a change in his details and does not change the username
                // it's obvious that his username already exists in the database
                $scope.userExists = false;
            } else {
                $scope.checkingUsername = true;
                $scope.userExists = false;
                Database.checkUserName(userName)
                .then((result) => {
                    //check the user in the list;
                    $scope.checkingUsername = false;
                    $scope.userExists = result.$value;
                })
                .catch(() => {
                    $scope.checkingUsername = false;
                    $scope.userExists = true;
                    return true;
                });
            }
        };

    }
<file_sep>/common/services/database.js
angular
    .module('Dsrh')
    .factory('Database', Database);


    Database.$inject = ['$firebaseObject', '$firebaseArray'];
    function Database($firebaseObject, $firebaseArray){

        //create a reference to the database
        const db = firebase.database();

        const dataBase = {};

        dataBase.dObj = $firebaseObject;
        dataBase.dArray = $firebaseArray;
        dataBase.addUser = addUser;
        dataBase.deleteUser = deleteUser;
        dataBase.retrieveUserList = retrieveUserList; 
        dataBase.checkUserName = checkUserName;
        dataBase.retrieveUserInfo = retrieveUserInfo;
        dataBase.getCitiesList = getCitiesList;
        dataBase.getHotelsList = getHotelsList;
        dataBase.getRestaurantsList = getRestaurantsList;
        dataBase.getCityHotelsData = getCityHotelsData;
        dataBase.getCityRestaurantsData = getCityRestaurantsData;
        dataBase.getHotelData = getHotelData;
        dataBase.getRestaurantData = getRestaurantData;
        dataBase.makeHotelReservation = makeHotelReservation;
        dataBase.makeRestaurantReservation = makeRestaurantReservation;
        dataBase.postCommentAndRating = postCommentAndRating;
        dataBase.postCommentAndRatingRest = postCommentAndRatingRest;


        

        /** 
         * Add user in information in the database 
         * + add the username in the userName List 
         */
        function addUser(userInfo, id){

            const strippedUserInfo = angular.copy(userInfo);

            //we delete unecessary data from the object before storing it to the database;
            delete strippedUserInfo.password2;

            // add the user data and then put the username in the list of userNames
            // we cannot make a double change because the validation rules are based on the first sent object
            return db.ref('/users/' + id).set(strippedUserInfo)
                .then(() => {
                    return db.ref('/userNames/' + userInfo.displayName).set(true);
                });
        }



        /** 
         * Removes the user information from the database 
         * optionally: delete only the username from the list of userNames
         */
        function deleteUser(userInfo, oldUsername) {

            if(oldUsername) {
                // delete only the username from the list of userNames
                return this.dObj(db.ref('/userNames/' + oldUsername)).$remove();
            } else {
                // delete all the data asocaited with the user

                //TBD
            }
        }



        /** 
         * Retrieve the whole list of userNames
         */
        function retrieveUserList(){
            return this.dArray(db.ref().child('userNames')).$loaded();
        }



        /** 
         * Check if the userName is in the userName List
         */
        function checkUserName(userName){
            return this.dObj(db.ref(`userNames/${userName}`)).$loaded();
        }



        /** 
         * retrieve user information
         */
        function retrieveUserInfo(id){
            return this.dObj(db.ref(`users/${id}`));
        }
        
        
        
        /** 
         * retrieve cities list
         */
        function getCitiesList(){
            //cretae a query which will orter the cities by their name;
            const query = db.ref(`cities`).orderByValue();
            //retrieve the array;
            return this.dArray(query);
        }



        /** 
         * retrieve hotels list
         */
        function getHotelsList(){
            //create a query which will order the hotels by their name;
            const query = db.ref(`hotelsCitiesMap`).orderByValue();
            //retrieve the array;
            return this.dArray(query);
        }
        

        /** 
         * retrieve restaurant list
         */
        function getRestaurantsList(){
            //create a query which will order the restaurants by their name;
            const query = db.ref(`restaurantsCitiesMap`).orderByValue();
            //retrieve the array;
            return this.dArray(query);
        }



        /** 
         * retrieve data for hotels after a city search
         */
        function getCityHotelsData(city){
            return this.dArray(db.ref(`/citiesHotelsData/${city}`)).$loaded();
        }

        /** 
         * retrieve data for restaurants after a city search
         */
        function getCityRestaurantsData(city){
            return this.dArray(db.ref(`/citiesRestaurantsData/${city}`)).$loaded();
        }



        /** 
         * retrieve data of a hotel after a direct hotel search 
         */
        function getHotelData(hotel){
            return this.dObj(db.ref(`hotelsCitiesMap/${hotel}`)).$loaded().then( (response) => {
                return this.dObj(db.ref(`citiesHotelsData/${response.$value}/${hotel}`)).$loaded();
            });
        }

        

        /** 
         * retrieve data of a restaurant after a direct restaurant search 
         */
        function getRestaurantData(restaurant){
            return this.dObj(db.ref(`restaurantsCitiesMap/${restaurant}`)).$loaded().then( (response) => {
                return this.dObj(db.ref(`citiesRestaurantsData/${response.$value}/${restaurant}`)).$loaded();
            });
        }



        /**
         * make hotel reservation
         * simultaniously update the rooms occupied dates
         */
        function makeHotelReservation(hotel, rooms, startDate, endDate, userData){
            return this.dObj(db.ref(`hotelsCitiesMap/${hotel}`)).$loaded().then( (response) => {
                const updateObj = {};

                rooms.forEach( (room) => {
                    let newKey = db.ref(`citiesHotelsData/${response.$value}/${hotel}/rooms/${room}/occupied`).push().key;
                    updateObj[`${room}/occupied/${newKey}`] = {startDate : startDate, endDate: endDate, guestData: userData}
                });

                return db.ref(`citiesHotelsData/${response.$value}/${hotel}/rooms`).update(updateObj);
            });
        }

        /**
         * make restaurant reservation
         */
        function makeRestaurantReservation(restaurant, table, {restDate, restTime}, userData){
            return this.dObj(db.ref(`restaurantsCitiesMap/${restaurant}`)).$loaded().then( (response) => {
                const updateObj = {};

                let newKey = db.ref(`citiesRestaurantsData/${response.$value}/${restaurant}/tables/${table}/occupied`).push().key;
                updateObj[`${table}/occupied/${newKey}`] = {restDate : restDate, restTimeStart: restTime, guestData: userData}


                return db.ref(`citiesRestaurantsData/${response.$value}/${restaurant}/tables`).update(updateObj);
            });
        } 


        /**
         * post the comment
         * and update the hotel rating;
         */
        function postCommentAndRating(hotel, comment, newRating){
            const updateObj = {};
            updateObj[`userRating`] = newRating;

            return this.dObj(db.ref(`hotelsCitiesMap/${hotel}`)).$loaded().then( (response) => {

                const newKey = db.ref(`citiesHotelsData/${response.$value}/${hotel}/comments`).push().key;
                updateObj[`comments/${newKey}`] = comment;

                return db.ref(`citiesHotelsData/${response.$value}/${hotel}`).update(updateObj)
            })
        }


        /**
         * post the comment
         * and update the restaurant rating;
         */
        function postCommentAndRatingRest(restaurant, comment, newRating){
            const updateObj = {};
            updateObj[`userRating`] = newRating;

            return this.dObj(db.ref(`restaurantsCitiesMap/${restaurant}`)).$loaded().then( (response) => {

                const newKey = db.ref(`citiesRestaurantData/${response.$value}/${restaurant}/comments`).push().key;
                updateObj[`comments/${newKey}`] = comment;

                return db.ref(`citiesRestaurantsData/${response.$value}/${restaurant}`).update(updateObj)
            })
        }



        // // helper to add data
        // hotelsAndCities.map( (item) => dataBase.dArray(db.ref(`hotelsCitiesMap`)).$add(item) );
        // hotelsAndCities.map( (item) => db.ref(`hotelsCitiesMap/${item.name}`).set(item.city) );

        return dataBase;
    }