(function () {
  'use strict';
  // Source: src/html/scripts/tour-sales/module.js
  angular.module('tour-sales', [
    'ui.router',
    'tours',
    'ui.bootstrap',
    'daterangepicker'
  ]);
  angular.module('sightseeing-sales', [
    'ui.router',
    'tours',
    'ui.bootstrap',
    'daterangepicker'
  ]);
  angular.module('vo-sales', [
    'ui.router',
    'tours',
    'ui.bootstrap',
    'htmlToPdfSave',
    'updateMeta',
    'daterangepicker'
  ]);
  angular.module('cruise-sales', [
    'ui.router',
    'tours',
    'ui.bootstrap',
    'daterangepicker'
  ]);
  angular.module('clubmed-sales', [
    'ui.router',
    'tours',
    'ui.bootstrap',
    'daterangepicker'
  ]);
  angular.module('omra-sales', [
    'ui.router',
    'tours',
    'ui.bootstrap',
    'daterangepicker'
  ]);
  angular.module('tours', [
    'ui.bootstrap',
    'daterangepicker'
  ]);
  // Source: src/html/scripts/tour-sales/states.js
  angular.module('tours').config([
    '$sceProvider',
    '$stateProvider',
    '$urlRouterProvider',
    'settings',
    function ($sceProvider, $stateProvider, $urlRouterProvider, settings) {
      // Completely disable SCE.  For demonstration purposes only!
      // Do not use in new projects.
      $sceProvider.enabled(false);
      //https://atlasvoyages.com/ngapps/vo-sales#/?country=MA:Maroc&type=VO&lang=fr&from=2018-08-13&to=2018-10-12
      $stateProvider.state('tourSearch', {
        url: '/?departure&theme&lang&vcity&depname&type&country&from&to',
        templateUrl: settings.templates.search,
        controller: 'tours_SearchCtrl'
      }).state('tour', {
        url: '/tour/:tour?from&to&lang',
        templateUrl: settings.templates.product,
        controller: 'tours_TourCtrl'
      }).state('bookings', {
        url: '/tours/orders/:tour',
        templateUrl: 'hermes-tour-orders',
        controller: 'tours_ords'
      }).state('tours2', {
        url: '/tours2/?departure&theme&lang&vcity&depname&type&country&from&to',
        templateUrl: 'tour-atlas-elite',
        controller: 'tours_SearchCtrl'
      }).state('order', {
        url: '/tours/order/:order',
        templateUrl: 'tour-order-detail',
        controller: 'tours_ord_det'
      });
      $urlRouterProvider.otherwise('/');
    }
  ]);
  // Source: src/html/scripts/tour-sales/saveHtmlToPdf.js
  angular.module('htmlToPdfSave', []);
  angular.module('htmlToPdfSave').directive('pdfSaveButton', [
    '$rootScope',
    '$pdfStorage',
    function ($rootScope, $pdfStorage) {
      return {
        restrict: 'A',
        link: function (scope, element, attrs) {
          $pdfStorage.pdfSaveButtons.push(element);
          scope.buttonText = 'Button';
          element.on('click', function () {
            var activePdfSaveId = attrs.pdfSaveButton;
            var activePdfSaveName = attrs.pdfName;
            $rootScope.$broadcast('savePdfEvent', {
              activePdfSaveId: activePdfSaveId,
              activePdfSaveName: activePdfSaveName
            });
          });
        }
      };
    }
  ]);
  angular.module('htmlToPdfSave').directive('pdfSaveContent', [
    '$rootScope',
    '$pdfStorage',
    function ($rootScope, $pdfStorage) {
      return {
        link: function (scope, element, attrs) {
          $pdfStorage.pdfSaveContents.push(element);
          var myListener = scope.$on('savePdfEvent', function (event, args) {
              var currentElement = element;
              var currentElementId = currentElement[0].getAttribute('pdf-save-content');
              // save a call of query selector because angular loads the element on load by default
              //	var elem = document.querySelectorAll('[pdf-save]') ;
              var elem = $pdfStorage.pdfSaveContents;
              var broadcastedId = args.activePdfSaveId;
              var broadcastedName = args.activePdfSaveName || 'default.pdf';
              //iterate through the element array to match the id
              for (var i = 0; i < elem.length; i++) {
                // handle the case of elem getting length
                //	if(i == 'length' || i == 'item')
                //		continue ;
                // if the event is received by other element than for whom it what propogated for continue
                if (!matchTheIds(broadcastedId, currentElementId))
                  continue;
                var single = elem[i];
                var singleElement = single[0];
                //var parent = single[0] ;
                var pdfId = singleElement.getAttribute('pdf-save-content');
                if (matchTheIds(pdfId, broadcastedId)) {
                  console.log('Id is same');
                  convertToPdf(elem, pdfId);
                  break;  // exit the loop once pdf gets printed
                }
              }
              function matchTheIds(elemId, broadcastedId) {
                return elemId == broadcastedId;
              }
              function convertToPdf(theElement, id) {
                //theElement = [theElement];
                convert(theElement, id);
              }
              function convert(theElement, id) {
                var quotes = $('div[pdf-save-content=' + id + ']')[0];
                html2canvas(quotes, {
                  onrendered: function (canvas) {
                    var pdf = new jsPDF('p', 'pt', 'letter');
                    for (var i = 0; i <= quotes.clientHeight / 980; i++) {
                      var srcImg = canvas;
                      var sX = 0;
                      var sY = 980 * i;
                      // start 980 pixels down for every new page
                      var sWidth = 900;
                      var sHeight = 980;
                      var dX = 0;
                      var dY = 0;
                      var dWidth = 900;
                      var dHeight = 980;
                      window.onePageCanvas = document.createElement('canvas');
                      onePageCanvas.setAttribute('width', 900);
                      onePageCanvas.setAttribute('height', 980);
                      var ctx = onePageCanvas.getContext('2d');
                      // details on this usage of this function: 
                      // https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API/Tutorial/Using_images#Slicing
                      ctx.drawImage(srcImg, sX, sY, sWidth, sHeight, dX, dY, dWidth, dHeight);
                      // document.body.appendChild(canvas);
                      var canvasDataURL = onePageCanvas.toDataURL('image/png', 1);
                      var width = onePageCanvas.width;
                      var height = onePageCanvas.clientHeight;
                      //! If we're on anything other than the first page,
                      // add another page
                      if (i > 0) {
                        pdf.addPage(612, 791);  //8.5" x 11" in pts (in*72)
                      }
                      //! now we declare that we're working on that page
                      pdf.setPage(i + 1);
                      //! now we add content to that page!
                      pdf.addImage(canvasDataURL, 'PNG', 20, 40, width * 0.62, height * 0.62);
                    }
                    //! after the for loop is finished running, we save the pdf.
                    pdf.save(broadcastedName);
                  }
                });  /*var element = $('[pdf-save-content='+id+']') ,
						cache_width = element.width(),
						 a4  =[ 595.28,  841.89];  // for a4 size paper width and height
						 $('body').scrollTop(0);
						 createPDF();
						//create pdf
						function createPDF(){
							getCanvas().then(function(canvas){
								console.log('resolved get canvas');
								var img = canvas.toDataURL("image/png"),
								doc = new jsPDF({
									unit:'px',
									format:'a4'
								});
								doc.addImage(img, 'JPEG', 20, 20);
								doc.save(broadcastedName);
								element.width(cache_width);
							})
						}
						// create canvas object
						function getCanvas(){
							element.width((a4[0]*1.33333) -80).css('max-width','none');
							return html2canvas(element,{
								imageTimeout:2000,
								removeContainer:true
							});
						}*/
              }
            });
          // handle the memory leak
          // unbind the event
          scope.$on('$destroy', myListener);
        }
      };
    }
  ]);
  angular.module('htmlToPdfSave').service('$pdfStorage', function () {
    this.pdfSaveButtons = [];
    this.pdfSaveContents = [];
  }).service('pdfSaveConfig', function () {
    this.pdfName = 'default.pdf';
  });
  // Source: src/html/scripts/tour-sales/config/analytics.js
  angular.module('tours').run([
    '$rootScope',
    '$injector',
    '$log',
    '$http',
    'settings',
    function ($rootScope, $injector, $log, $http, settings) {
      var $analytics;
      try {
        $analytics = $injector.get('$analytics');
      } catch (e) {
        // Error: [$injector:unpr]
        // just returned, analytics is not loaded
        $log.warn('$analytics not available');
        return;
      }
      $rootScope.$on('tourSearchQuery', function ($event, q) {
        // $log.debug('tourSearchQuery query', JSON.stringify(q));
        var path = '/recherche';
        if (q.type.toLowerCase() == 'vo')
          path += '/voyages-organise';
        if (q.country)
          path += '/' + q.country.split(':')[1];
        path += '/' + q.from + '/' + q.to + '/';  // $log.debug('$analytics.pageTrack', path);
                                                  // $analytics.pageTrack(path);
      });
      $rootScope.$on('tourProducthQuery', function ($event, tourName) {
        $log.debug('tourProducthQuery query', tourName);
        var path = '';
        if (tourName) {
          path = '/voyages-organise/' + tourName + '/';  // $log.debug('$analytics.pageTrack', path);
                                                         // $analytics.pageTrack(path);
        }
      });
      $rootScope.$on('bookCartSaved', function ($event, cart) {
        var path = '/checkout/';
        var type = cart.items[0]['@type'].toLowerCase();
        switch (type) {
        case 'air':
          path += 'air';
          break;
        case 'stayitem':
          path += 'stay';
          break;
        case 'omra':
          path += 'omra';
          break;
        case 'haj':
          path += 'hajj';
          break;
        case 'vo':
          path += 'voyages-organis\xe9s';
          break;
        default:
          path += type;
        }  //$log.info('checkout-update:cart:', path);
           // $analytics.pageTrack(path);
      });  /*$rootScope.$on('airOfferDetails', function ($event, quote) {
            var airline = _.str.slugify(quote.trip.segments[0].flights[0].marketer.code),
                airports = quote.trip.segments.map(function (seg) {
                    return _.str.slugify(seg.departure.location.code) + '/' + _.str.slugify(seg.arrival.location.code);
                }).join('/'),
                path = '/flights/offer/' + airline + '/' + airports;

            path += '/dtd:' + moment(quote.trip.segments[0].departure.date).diff(moment(), 'days');
            $log.debug('$analytics.pageTrack', path);
            $analytics.pageTrack(path);
        });*/
    }
  ]);
  // Source: src/html/scripts/tour-sales/controllers/departures-calendar.js
  angular.module('tours').controller('tours_TourQuoteCtrl', [
    '$scope',
    '$http',
    '$stateParams',
    '$location',
    'settings',
    '$log',
    function ($scope, $http, $stateParams, $location, settings, $log) {
      var isoDate = 'YYYY-MM-DD';
      var options = {
          adults: [
            1,
            2,
            3,
            4,
            5,
            6
          ],
          children: [
            0,
            1,
            2,
            3,
            4,
            5,
            6
          ],
          childAges: [
            1,
            2,
            3,
            4,
            5,
            6,
            7,
            8,
            9,
            10,
            11
          ]
        };
      function buildQuery() {
        var query = {};
        var from = moment($stateParams.from || 'invalid');
        var to = moment($stateParams.to || 'invalid');
        var ages;
        if (!from.isValid() || from.isBefore()) {
          from = moment().startOf('day');
        }
        if (!to.isValid() || to.isBefore(from) || to.isSame(from)) {
          to = moment(from);
          to.add('months', 1);
        }
        if (/\d{1,2}(,\d{1,2})*/.test($stateParams.children)) {
          ages = $stateParams.children.split(',');
        } else {
          ages = [];
        }
        query.tour = $stateParams.tour;
        query.from = from.toDate();
        query.to = to.toDate();
        query.adults = $stateParams.adults || 1;
        query.children = ages.length;
        query.ages = ages;
        return query;
      }
      function queryRates(query) {
        var params = {
            qt: 'search',
            tour: $stateParams.tour,
            from: moment(query.from).format(isoDate),
            to: moment(query.to).format(isoDate)
          };
        var url = settings.tours.quote;
        $http.get(url, { params: params }).success(function (data) {
          $log.debug('query', $scope.query);
          $scope.pricing = data[0].pricing[0];
          $scope.currency = $scope.pricing.currency;
          $log.debug($scope.pricing);
        }).error(function () {
          $log.error('Error querying rates', arguments);
        });
      }
      $scope.query = buildQuery();
      $log.debug('query', $scope.query);
      queryRates($scope.query);
      // fake
      function getData() {
        var deps = [], last, i = 1;
        deps.push(moment().startOf('day').add('days', 3).toDate());
        while (i < 10) {
          last = deps[i - 1];
          deps.push(moment(last).add('days', 5));
          i += 1;
        }
        return deps;
      }
      function isDepartue(d, deps) {
        var i = 0, len = deps.length;
        while (i < len) {
          if (d.isSame(deps[i])) {
            return true;
          }
          i += 1;
        }
        return false;
      }
      function buildDay(d, deps, month, week) {
        var day = {
            label: d.month() === month ? d.date() : '',
            date: moment(d).toDate(),
            currentMonth: d.month() === month,
            departure: isDepartue(d, departures)
          };
        week.push(day);
      }
      var departures = getData();
      var firstDayOfMonth = moment(departures[0]).startOf('month');
      var month = firstDayOfMonth.month();
      var d = moment(firstDayOfMonth).startOf('week');
      var weeks = [];
      var week = [];
      while (d.month() <= month) {
        buildDay(d, departures, month, week);
        d.add('days', 1);
        // week end
        if (week.length === 7) {
          weeks.push(week);
          week = [];
        }
      }
      while (week.length > 0 && week.length < 7) {
        buildDay(d, departures, month, week);
        d.add('days', 1);
      }
      weeks.push(week);
      $scope.weeks = weeks;
      $scope.showRates = function (d) {
        $scope.rates = 'Rate for ' + moment(d).format();
      };
      return;
      var q = $location.search();
      $log.log(q);
      var tourCode = $stateParams.tour;
      $scope.tourcontent = {};
      $scope.description = {};
      $scope.suppnbr = 0;
      $scope.quote = {};
      $scope.ddate = '';
      function initQuote() {
        var cur = $scope.quote.currency;
        $scope.quote = {
          status: 'quote',
          created: moment(),
          modified: moment(),
          pricing: {
            items: [],
            prices: []
          },
          trip: {
            content: {
              type: 'tour',
              tour: $scope.tourcontent
            },
            travellers: [{
                type: 'Traveller',
                classification: 'ADULT',
                id: 1
              }]
          },
          currency: cur
        };
      }
      var url = settings.tours.endpoint;
      $http.get(url + '?qt=search&tour=' + $stateParams.tour + '&from=' + q.from + '&to=' + q.to).success(function (data) {
        $scope.pricing = data[0].pricing[0];
        $scope.quote.currency = $scope.pricing.currency;
      });
      $scope.travellers = {
        adult: 1,
        child: 0,
        ages: []
      };
      $scope.childages = function () {
        $scope.travellers.ages = [];
        for (var i = 0; i < $scope.travellers.child; i++) {
          $scope.travellers.ages.push({
            i: i,
            v: 1
          });
        }
      };
      $scope.setquotetravellers = function () {
        initQuote();
        $scope.ddate = '';
        $scope.selectedrate = {};
        $scope.quote.trip.travellers = [];
        var travellerid = 1;
        // set adults
        for (var i = 0; i < $scope.travellers.adult; i++) {
          $scope.quote.trip.travellers.push({
            type: 'Traveller',
            classification: 'ADULT',
            id: travellerid++
          });
        }
        // set children
        for (var i = 0; i < $scope.travellers.child; i++) {
          $scope.quote.trip.travellers.push({
            type: 'Traveller',
            classification: 'CHILD',
            id: travellerid++,
            age: $scope.travellers.ages[i].v
          });
        }
      };
      $scope.loadproduct = function (ddate) {
        $scope.quote.trip.content.checkin = ddate;
        var ci = moment($scope.quote.trip.content.checkin, 'YYYY-MM-DDTHH:mm:SS.SSSZ');
        $scope.quote.trip.content.checkout = ci.add('days', $scope.tour.days.length);
        getselectedrates(ddate);
      };
      getselectedrates = function (ddate) {
        $scope.selectedRates = [];
        for (var i = 0; i < $scope.pricing.rates.length; i++) {
          /// RATE WILL NOT BE A TABLE
          for (var j = $scope.pricing.rates[i].lines.length - 1; j >= 0; j--) {
            var dp = moment(ddate);
            var ld = moment($scope.pricing.rates[i].lines[j].departure);
            if (ld.isSame(dp) && $scope.pricing.rates[i].lines[j].actif == true) {
              $scope.selectedRates.push({
                category: $scope.pricing.rates[i].category,
                ligne: $scope.pricing.rates[i].lines[j],
                selected: false
              });  //console.log("selected rate" ,rate.lines[j]);
            }
          }
          ;
        }
        ;
        if ($scope.selectedRates.length > 0)
          $scope.selectedRates[0].selected = true;
      };
      $scope.selectRate = function (index) {
        for (var i = $scope.selectedRates.length - 1; i >= 0; i--) {
          if (i == index)
            $scope.selectedRates[i].selected = true;
          else
            $scope.selectedRates[i].selected = false;
        }
        ;
      };
      $scope.selectedrate = {};
      $scope.selected = false;
      $scope.quoteloaditems = function (rate) {
        $scope.quote.pricing.items = [];
        $scope.selectedrate = rate;
        $scope.selected = true;
        // for(var i=0;i< $scope.travellers.adult;i++){
        $scope.quote.pricing.items.push({
          type: 'TourItem',
          product: {
            type: 'TourProduct',
            code: rate.category.code,
            childs: rate.ligne.childs,
            cancellation: rate.ligne.cancellation,
            supplements: rate.ligne.supplements
          },
          quantity: $scope.travellers.adult,
          prices: [
            {
              value: $scope.travellers.adult * rate.ligne.price,
              scope: 'TOTAL'
            },
            {
              value: rate.ligne.price,
              scope: 'UNIT'
            }
          ]
        });
        //}
        for (var i = 0; i < $scope.travellers.child; i++) {
          childage = $scope.travellers.ages[i].v;
          childrate = 0;
          var cliltrate = null;
          rate.ligne.childs.forEach(function (child) {
            if (childage <= child.to)
              cliltrate = child;
          });
          if (cliltrate == null) {
            childrate = rate.ligne.price;
          } else if (cliltrate.charge[1] == '%') {
            childrate = rate.ligne.price * cliltrate.charge[0] / 100;
          }
          /* else if (cliltrate.charge[1] == $scope.quote.currency) {
          console.log("selected child price " + cliltrate + " en " + $scope.quote.currency)
        }*/
          $scope.quote.pricing.items.push({
            type: 'TourItem',
            product: {
              type: 'TourProduct',
              code: rate.category.code,
              childs: rate.ligne.childs,
              cancellation: rate.ligne.cancellation,
              supplements: rate.ligne.supplements
            },
            quantity: 1,
            prices: [
              {
                value: childrate,
                scope: 'TOTAL'
              },
              {
                value: childrate,
                scope: 'UNIT'
              }
            ]
          });  //  if(rate.ligne.childs[])
               // totalprice=totalprice+rate.ligne.price;
        }
        updateTotalPrice();
      };
      $scope.quoteloadsupplements = function (supp, suppnbr) {
        for (var i = $scope.quote.pricing.items.length - 1; i >= 0; i--) {
          var item = $scope.quote.pricing.items[i];
          if (item.product.code == supp.name)
            $scope.quote.pricing.items.splice(i, 1);
        }
        ;
        if (supp.charge[2] === $scope.quote.currency)
          $scope.quote.pricing.items.push({
            type: 'Item',
            product: {
              type: 'Product',
              code: supp.name,
              name: supp.name
            },
            quantity: suppnbr,
            prices: [
              {
                value: parseInt(supp.charge[0] + 1) * (suppnbr * parseInt(supp.charge[1])),
                scope: 'TOTAL'
              },
              {
                value: parseInt(supp.charge[0] + 1) * parseInt(supp.charge[1]),
                scope: 'UNIT'
              }
            ]
          });
        if (supp.charge[2] == '%')
          $scope.quote.pricing.items.push({
            type: 'Item',
            product: {
              type: 'Product',
              code: supp.name,
              name: supp.name
            },
            quantity: suppnbr,
            prices: [
              {
                value: parseInt(supp.charge[0] + 1) * (suppnbr * parseInt(supp.charge[1]) * parseInt($scope.selectedrate.ligne.price) / 100),
                scope: 'TOTAL'
              },
              {
                value: parseInt(supp.charge[0] + 1) * parseInt(supp.charge[1]) * parseInt($scope.selectedrate.ligne.price) / 100,
                scope: 'UNIT'
              }
            ]
          });
        updateTotalPrice();
      };
      updateTotalPrice = function () {
        var tprice = 0;
        $scope.quote.pricing.prices = [];
        for (var i = $scope.quote.pricing.items.length - 1; i >= 0; i--) {
          var item = $scope.quote.pricing.items[i];
          for (var j = item.prices.length - 1; j >= 0; j--) {
            if (item.prices[j].scope == 'TOTAL')
              tprice = tprice + item.prices[j].value;
          }
        }
        $scope.quote.pricing.prices.push({
          value: tprice + ' ' + $scope.quote.currency,
          scope: 'TOTAL'
        });
      };
    }
  ]);
  // Source: src/html/scripts/tour-sales/controllers/order-detail.js
  angular.module('tours').controller('tours_ord_det', [
    '$scope',
    '$location',
    '$window',
    'settings',
    '$log',
    '$http',
    '$state',
    function ($scope, $location, $window, settings, $log, $http, $state) {
      var url = settings.tours.bookings + '/' + $state.params.order;
      var options = { headers: { 'authorized': settings.tours.authorized } };
      $http.get(url, options).success(onSearchResults);
      function pad(d) {
        return d < 10 ? '0' + d.toString() : d.toString();
      }
      function onSearchResults(data, status, fn, o) {
        switch (status) {
        case 200:
          $scope.status = 'found';
          $scope.order = data;
          break;
        default:
          $scope.status = 'error';
          $scope.error = data;
          $scope.order = {};
        }
        var order = $scope.order;
        $scope.showRL = false;
        $scope.trbyRoom = {
          single: 1,
          'double': 2,
          doubleWithChild: 3,
          triple: 3
        };
        $scope.order = order;
        $scope.rooms = Object.keys(order.rooms);
        $scope.roomingList = {
          single: [],
          'double': [],
          doubleWithChild: [],
          triple: []
        };
        for (var i = order.trip.roominglist.length - 1; i >= 0; i--) {
          for (var j = $scope.rooms.length - 1; j >= 0; j--) {
            if (order.trip.roominglist[i].room.split('-')[0] == $scope.rooms[j]) {
              for (var k = order.trip.roominglist[i].travelers.length - 1; k >= 0; k--) {
                for (var m = order.trip.travellers.length - 1; m >= 0; m--) {
                  if (order.trip.roominglist[i].travelers[k] == order.trip.travellers[m].id) {
                    if (order.trip.hasOwnProperty('flight')) {
                      for (var ii = order.trip.flight.length - 1; ii >= 0; ii--) {
                        if (order.trip.flight[ii].traveller == order.trip.travellers[m].id) {
                          if (order.trip.flight[ii].hasOwnProperty('arrival')) {
                            if (order.trip.flight[ii].arrival.hasOwnProperty('transfert') && order.trip.flight[ii].arrival.transfert == true && order.trip.flight[ii].arrival.hasOwnProperty('date')) {
                              order.trip.travellers[m].arrival = order.trip.flight[ii].arrival.date;
                              if (order.trip.flight[ii].arrival.hasOwnProperty('time'))
                                order.trip.travellers[m].arrival += ' at ' + pad(order.trip.flight[ii].arrival.time.hour) + ':' + pad(order.trip.flight[ii].arrival.time.min) + ' [' + order.trip.flight[ii].arrival.number.toUpperCase() + ']';
                            }
                          }
                          if (order.trip.flight[ii].hasOwnProperty('departure')) {
                            if (order.trip.flight[ii].departure.hasOwnProperty('transfert') && order.trip.flight[ii].departure.transfert == true && order.trip.flight[ii].departure.hasOwnProperty('date')) {
                              order.trip.travellers[m].departure = order.trip.flight[ii].departure.date;
                              if (order.trip.flight[ii].departure.hasOwnProperty('time'))
                                order.trip.travellers[m].departure += ' at ' + pad(order.trip.flight[ii].departure.time.hour) + ':' + pad(order.trip.flight[ii].departure.time.min) + ' [' + order.trip.flight[ii].departure.number.toUpperCase() + ']';
                            }
                          }
                        }
                      }
                      $scope.roomingList[$scope.rooms[j]].splice(0, 0, order.trip.travellers[m]);
                      break;
                    }
                  }
                }
                ;
              }
              ;
            }
          }
          ;
        }
        ;
        if (order.status == 'confirmed') {
          var cancellation = order.items[0].product.rate.cancellation;
          var checkin = moment(order.trip.content.checkin, 'YYYY-MM-DDTHH:mm:SS.SSSZ');
          if (cancellation.length > 0) {
            $scope.chargeConditions = cancellation[cancellation.length - 1].charge[0] > 0 ? 'Cancellation Charge Until ' + checkin.subtract(cancellation[cancellation.length - 1].start, 'days').format('DD/MM/YYYY') + ' : ' + (cancellation[cancellation.length - 1].charge[1] == '%' ? $scope.order.totals.total * cancellation[cancellation.length - 1].charge[0] / 1000 : cancellation[cancellation.length - 1].charge[0]) + ' ' + order.currency + String.fromCharCode(10) : 'Free Cancellation Until ' + checkin.subtract(cancellation[cancellation.length - 1].start, 'days').format('DD/MM/YYYY') + String.fromCharCode(10);
            for (var i = cancellation.length - 1; i > 0; i--) {
              checkin = moment(order.trip.content.checkin, 'YYYY-MM-DDTHH:mm:SS.SSSZ');
              $scope.chargeConditions += ' From ' + checkin.subtract(cancellation[i].start - 1, 'days').format('DD/MM/YYYY');
              checkin = moment(order.trip.content.checkin, 'YYYY-MM-DDTHH:mm:SS.SSSZ');
              $scope.chargeConditions += ' To ' + checkin.subtract(cancellation[i - 1].start, 'days').format('DD/MM/YYYY') + ' : ' + (cancellation[i - 1].charge[1] == '%' ? $scope.order.totals.total * cancellation[i - 1].charge[0] / 100 : cancellation[i - 1].charge[0]) + ' ' + order.currency + String.fromCharCode(10);
            }
            ;
          } else
            $scope.chargeConditions = 'no fees';
          order.calendarlink = 'http://www.google.com/calendar/event?action=TEMPLATE&text=' + order.items[0].product.parent.name + '&dates=' + checkin.format('YYYYMMDDTHHmmss') + 'Z/' + checkin.add(1, 'hours').format('YYYYMMDDTHHmmss') + 'Z&details=' + order.items[0].product.parent.name + '&location=Casablanca Morocco';
        }
      }
      ;
    }
  ]);
  // Source: src/html/scripts/tour-sales/controllers/search-form.js
  angular.module('tours').controller('tours_SearchFormCtrl', [
    '$scope',
    '$location',
    '$window',
    'settings',
    '$log',
    '$http',
    '$state',
    function ($scope, $location, $window, settings, $log, $http, $state) {
      // $log.debug('toursSearchFormCtrl init', settings);
      $scope.setting = settings;
      /* Converts an object into a key/value par with an optional prefix. Used for converting objects to a query string */
      var metaRouter = {};
      metaRouter.go = function (target, opts) {
        opts = opts || {};
        var route = settings.routes[target];
        if (!route) {
          throw new Error('Unknown route ' + target);
        }
        if (route.type === 'redirect') {
          var href = route.href.replace(':path', opts.path || '');
          href = href.replace(':query', qs(opts.query) || '');
          $log.debug('redirect', href);
          $window.location.href = href;
        } else if (route.type === 'state') {
          $state.go(route.name, opts);
        }
      };
      var qs = function (obj, prefix) {
        var str = [];
        for (var p in obj) {
          var k = prefix ? prefix + '[' + p + ']' : p, v = obj[k];
          str.push(angular.isObject(v) ? qs(v, k) : k + '=' + encodeURIComponent(v));
        }
        return str.join('&');
      };
      function themes(q) {
      }
      function langs(q) {
        var url = settings.tours.langAutocomplete.replace(':term', q);
        return $http.get(url).then(function (response) {
          return response.data;
        });
      }
      /**
         * returns autocomple result promise
         */
      function localities(q) {
        var url = settings.tours.localitiesAutocomplete.replace(':term', q);
        return $http.get(url).then(function (response) {
          $log.debug(response);
          return response.data;
        });
      }
      function countries(q) {
        var url = settings.tours.countriesAutocomplete.replace(':term', q);
        return $http.get(url).then(function (response) {
          $log.debug(response);
          return response.data;
        });
      }
      function submit() {
        $log.info('in_submit', $scope.query);
        var params = angular.extend({}, $scope.query);
        console.log('submit', $scope.query);
        if (params.from) {
          params.from = moment(params.from).format('YYYY-MM-DD');
          //var futureMonthPlus = moment(params.from).add(1, 'M');
          //params.to = moment(futureMonthPlus).endOf('month').format('YYYY-MM-DD');
          // params.to = moment(params.from).add(60, 'days').format('YYYY-MM-DD');
          params.to = moment(params.to).format('YYYY-MM-DD');
        }
        /*if (params.to) {
                var futureMonthPlus = moment(params.from).add(1, 'M');
                params.to = moment(futureMonthPlus).endOf('month').format('YYYY-MM-DD');
            }*/
        if (params.departure) {
          params.departure = params.departure.code;
        }
        if (params.vcity) {
          params.vcity = params.vcity.code;
        }
        if (params.b2bdep && params.b2bdep.code != undefined) {
          params.departure = params.b2bdep.code;
          params.depname = params.b2bdep.name;
        }
        if (params.theme) {
          params.theme = params.theme;  // will search by code
        }
        /*if (params.theme.toLowerCase() == 'tout')
                delete params.theme;
            */
        if (params.country) {
          params.country = params.country.code + ':' + params.country.name;  // will search by code
        }
        params.type = settings.templates.type;
        params.lang = params.lang.code ? params.lang.code : 'fr';
        metaRouter.go('search', params);
      }
      $window.onload = function () {
        // console.log("windows location", $window.location);
        $scope.holderVar = $location.search();
        // console.log('location search', $location.search(), $scope.holderVar);
        var length = Object.keys($location.search());
        if (length > 0) {
          var params = {
              type: $location.search().type,
              from: $location.search().from,
              to: $location.search().to,
              lang: $location.search().lang || 'fr'
            };
        } else if (length == 0) {
          var params = {
              type: settings.templates.type,
              lang: 'fr',
              from: moment().format('YYYY-MM-DD')
            };
          // params.to = moment(params.from).add(30, 'days').format('YYYY-MM-DD');
          params.to = moment(params.from).add(3, 'M').format('YYYY-MM-DD');
        }
        metaRouter.go('search', params);
      };
      $scope.$watch('query.from', function (fresh, old) {
        // console.log('fresh, old', fresh, old);
        // console.log('fresh, old', $scope.query.from, $scope.query.to);
        if (fresh === old)
          return;
        var min = moment(fresh).add(1, 'days');
        var to = moment($scope.query.to || 'invalid');
        if (to.isValid() && to.isBefore(min)) {
          $scope.query.to = min.toDate();
        }
        $scope.options.minEndDate = min.toDate();
        $scope.options.minEndMonth = moment(min).startOf('month').toDate();
      });
      /* $http.get(settings.tours.themesAutocomplete.replace(':term', '')).then(function (response) {
                 $scope.options.themes = response.data;
             });*/
      function toggleCalendar($event, cal) {
        $event.preventDefault();
        $event.stopPropagation();
        angular.forEach($scope.calendarsOpen, function (value, key) {
          // close others
          $scope.calendarsOpen[key] = false;
        });
        $scope.calendarsOpen[cal] = !$scope.calendarsOpen[cal];
      }
      angular.extend($scope, {
        themes: themes,
        langs: langs,
        localities: localities,
        submit: submit,
        toggleCalendar: toggleCalendar,
        calendarsOpen: {},
        countries: countries,
        options: {
          minStartDate: moment().startOf('day').toDate(),
          minEndDate: moment().add(1, 'days').startOf('day').toDate(),
          minEndMonth: moment().add(1, 'days').startOf('month').toDate(),
          datepickerTo: { initDate: '$parent.$parent.options.minEndDate' },
          langs: settings.default.langs,
          b2bdep: settings.default.b2bdep,
          themes: settings.default.themes,
          countries: settings.default.countries || []
        }
      });
      $scope.destOps = [];
      var countries = $scope.options.countries;
      $scope.destOps.push({
        label: 'Destination',
        value: {
          'code': 'DestinationCode',
          'name': 'DestinationName'
        }
      });
      for (var i = 0; i <= countries.length; i++) {
        if (countries[i]) {
          var o = {
              label: countries[i].name,
              value: countries[i]
            };
          $scope.destOps.push(o);
        }
      }
      $scope.destSelection = $scope.destOps[0].value;
      $scope.themeOps = [];
      var themes = $scope.options.themes;
      $scope.themeOps.push({
        label: 'Th\xe8me',
        value: 'Th\xe8me'
      });
      for (var i = 0; i <= themes.length; i++) {
        if (themes[i]) {
          var o = {
              label: themes[i].name,
              value: themes[i].name
            };
          $scope.themeOps.push(o);
        }
      }
      $scope.themeSelection = $scope.themeOps[0].value;
      if ($scope.query.country) {
        $scope.destSelection = $scope.query.country;
      }
      if ($scope.query.theme) {
        $scope.themeSelection = $scope.query.theme;
      }
      $scope.$watch('destSelection', function (newVal) {
        // console.log('destSelection newVal', newVal)
        if (newVal.code !== 'DestinationCode')
          $scope.query.country = newVal;
      });
      $scope.$watch('themeSelection', function (newVal) {
        // console.log('themeSelection newVal', newVal)
        if (newVal !== 'Th\xe8me')
          $scope.query.theme = newVal;
      });
    }
  ]);
  ;
  angular.module('ui.bootstrap.datepicker').controller('DatepickerController', [
    '$scope',
    '$attrs',
    '$parse',
    '$interpolate',
    '$timeout',
    '$log',
    'dateFilter',
    'datepickerConfig',
    function ($scope, $attrs, $parse, $interpolate, $timeout, $log, dateFilter, datepickerConfig) {
      datepickerConfig.showWeeks = false;
      var self = this, ngModelCtrl = { $setViewValue: angular.noop };
      // nullModelCtrl;
      // Modes chain
      this.modes = [
        'day',
        'month',
        'year'
      ];
      // Configuration attributes
      angular.forEach([
        'formatDay',
        'formatMonth',
        'formatYear',
        'formatDayHeader',
        'formatDayTitle',
        'formatMonthTitle',
        'minMode',
        'maxMode',
        'showWeeks',
        'startingDay',
        'yearRange'
      ], function (key, index) {
        self[key] = angular.isDefined($attrs[key]) ? index < 8 ? $interpolate($attrs[key])($scope.$parent) : $scope.$parent.$eval($attrs[key]) : datepickerConfig[key];
      });
      // Watchable date attributes
      angular.forEach([
        'minDate',
        'maxDate'
      ], function (key) {
        if ($attrs[key]) {
          $scope.$parent.$watch($parse($attrs[key]), function (value) {
            self[key] = value ? new Date(value) : null;
            self.refreshView();
          });
        } else {
          self[key] = datepickerConfig[key] ? new Date(datepickerConfig[key]) : null;
        }
      });
      if (angular.isDefined($attrs.initDate)) {
        $scope.$parent.$watch($parse($attrs.initDate), function (value) {
          if (!ngModelCtrl.$modelValue) {
            self.activeDate = value ? new Date(value) : new Date();
            self.refreshView();
          }
        });
      }
      $scope.datepickerMode = $scope.datepickerMode || datepickerConfig.datepickerMode;
      $scope.uniqueId = 'datepicker-' + $scope.$id + '-' + Math.floor(Math.random() * 10000);
      this.activeDate = angular.isDefined($attrs.initDate) ? $scope.$parent.$eval($attrs.initDate) : new Date();
      $scope.isActive = function (dateObject) {
        if (self.compare(dateObject.date, self.activeDate) === 0) {
          $scope.activeDateId = dateObject.uid;
          return true;
        }
        return false;
      };
      this.init = function (ngModelCtrl_) {
        ngModelCtrl = ngModelCtrl_;
        ngModelCtrl.$render = function () {
          self.render();
        };
      };
      this.render = function () {
        if (ngModelCtrl.$modelValue) {
          var date = new Date(ngModelCtrl.$modelValue), isValid = !isNaN(date);
          if (isValid) {
            this.activeDate = date;
          } else {
            $log.error('Datepicker directive: "ng-model" value must be a Date object, a number of milliseconds since 01.01.1970 or a string representing an RFC2822 or ISO 8601 date.');
          }
          ngModelCtrl.$setValidity('date', isValid);
        }
        this.refreshView();
      };
      this.refreshView = function () {
        if (this.element) {
          this._refreshView();
          var date = ngModelCtrl.$modelValue ? new Date(ngModelCtrl.$modelValue) : null;
          ngModelCtrl.$setValidity('date-disabled', !date || this.element && !this.isDisabled(date));
        }
      };
      this.createDateObject = function (date, format) {
        var model = ngModelCtrl.$modelValue ? new Date(ngModelCtrl.$modelValue) : null;
        return {
          date: date,
          label: dateFilter(date, format),
          selected: model && this.compare(date, model) === 0,
          disabled: this.isDisabled(date),
          current: this.compare(date, new Date()) === 0
        };
      };
      this.isDisabled = function (date) {
        return this.minDate && this.compare(date, this.minDate) < 0 || this.maxDate && this.compare(date, this.maxDate) > 0 || $attrs.dateDisabled && $scope.dateDisabled({
          date: date,
          mode: $scope.datepickerMode
        });
      };
      // Split array into smaller arrays
      this.split = function (arr, size) {
        var arrays = [];
        while (arr.length > 0) {
          arrays.push(arr.splice(0, size));
        }
        return arrays;
      };
      $scope.select = function (date) {
        if ($scope.datepickerMode === self.minMode) {
          var dt = ngModelCtrl.$modelValue ? new Date(ngModelCtrl.$modelValue) : new Date(0, 0, 0, 0, 0, 0, 0);
          dt.setFullYear(date.getFullYear(), date.getMonth(), date.getDate());
          ngModelCtrl.$setViewValue(dt);
          ngModelCtrl.$render();
        } else {
          self.activeDate = date;
          $scope.datepickerMode = self.modes[self.modes.indexOf($scope.datepickerMode) - 1];
        }
      };
      $scope.move = function (direction) {
        var year = self.activeDate.getFullYear() + direction * (self.step.years || 0), month = self.activeDate.getMonth() + direction * (self.step.months || 0);
        self.activeDate.setFullYear(year, month, 1);
        self.refreshView();
      };
      $scope.toggleMode = function (direction) {
        direction = direction || 1;
        if ($scope.datepickerMode === self.maxMode && direction === 1 || $scope.datepickerMode === self.minMode && direction === -1) {
          return;
        }
        $scope.datepickerMode = self.modes[self.modes.indexOf($scope.datepickerMode) + direction];
      };
      // Key event mapper
      $scope.keys = {
        13: 'enter',
        32: 'space',
        33: 'pageup',
        34: 'pagedown',
        35: 'end',
        36: 'home',
        37: 'left',
        38: 'up',
        39: 'right',
        40: 'down'
      };
      var focusElement = function () {
        $timeout(function () {
          self.element[0].focus();
        }, 0, false);
      };
      // Listen for focus requests from popup directive
      $scope.$on('datepicker.focus', focusElement);
      $scope.keydown = function (evt) {
        var key = $scope.keys[evt.which];
        if (!key || evt.shiftKey || evt.altKey) {
          return;
        }
        evt.preventDefault();
        evt.stopPropagation();
        if (key === 'enter' || key === 'space') {
          if (self.isDisabled(self.activeDate)) {
            return;  // do nothing
          }
          $scope.select(self.activeDate);
          focusElement();
        } else if (evt.ctrlKey && (key === 'up' || key === 'down')) {
          $scope.toggleMode(key === 'up' ? 1 : -1);
          focusElement();
        } else {
          self.handleKeyDown(key, evt);
          self.refreshView();
        }
      };
    }
  ]);
  /*
        //http://outgoing.fractalite.com/tours?from=2016-07-01&lang=fr&limit=100&qt=search&skip=0&to=2016-09-30&type=vo
        /*function initSearch() {


            var params = {
                type: settings.templates.type,
                from: $scope.query.from ? moment($scope.query.from).format('YYYY-MM-DD') : moment().format('YYYY-MM-DD')
            };

            params.to = moment(params.from).add(30, 'days').format('YYYY-MM-DD');
            // params.to = moment(futureMonthPlus).endOf('month').format('YYYY-MM-DD');

            console.log('initSearch just called', params);

            metaRouter.go('search', params);
        }


        */
  // Source: src/html/scripts/tour-sales/controllers/search.js
  angular.module('tours').controller('tours_SearchCtrl', [
    '$scope',
    '$http',
    '$stateParams',
    '$state',
    '$location',
    'settings',
    '$window',
    '$log',
    function ($scope, $http, $stateParams, $state, $location, settings, $window, $log) {
      // $log.info('tours_SearchCtrl:', settings);
      // $log.info('stateParams:', $stateParams)
      //$log.debug("search/ stateparams", $location.search(), $stateParams);
      var to = $stateParams.to;
      var from = $stateParams.from;
      var departure = $stateParams.departure;
      var depname = $stateParams.depname;
      var theme = $stateParams.theme;
      var lang = $stateParams.lang ? $stateParams.lang : 'fr';
      var vcity = $stateParams.vcity;
      var country = $stateParams.country;
      var skip = 0;
      var limit = 100;
      var type = $stateParams.type || 'VO';
      // will be from web
      var langs = settings.default.langs;
      var b2bdep = settings.default.b2bdep;
      var olang = langs[0];
      var odep;
      for (var i = langs.length - 1; i >= 0; i--) {
        if (langs[i].code === lang)
          olang = langs[i];
      }
      ;
      if (b2bdep) {
        for (var i = b2bdep.length - 1; i >= 0; i--) {
          if (b2bdep[i].name === depname)
            odep = b2bdep[i];
        }
        ;
      }
      if (odep === undefined)
        odep = departure;
      var lg = olang.code;
      $scope.query = {
        from: from,
        to: to,
        departure: departure,
        theme: theme,
        vcity: vcity,
        lang: lg,
        skip: skip,
        limit: limit,
        type: type,
        depname: depname,
        b2bdep: odep,
        country: country
      };
      //$log.debug('emit tourSearchQuery', JSON.stringify($scope.query));
      $scope.$emit('tourSearchQuery', $scope.query);
      $scope.context = 'search';
      //console.log("country ", country);
      // settings.tours.endpoints.search
      var params = { qt: 'search' };
      var url = settings.tours.search;
      if (from && to) {
        //$log.info('from_to 1', from, to)
        var checkin = moment(from || 'invalid', 'YYYY-MM-DD'), checkout = moment(to || 'invalid', 'YYYY-MM-DD'), current = moment().format('YYYY-MM-DD');
        if (checkin.isValid() && checkout.isValid() && checkin.isBefore(current)) {
          from = current;
          to = moment().add(120, 'days').format('YYYY-MM-DD');
          //$log.info('from&to', from, to);
          $stateParams.from = from;
          $stateParams.to = to;
          $scope.query.from = from;
          $location.search('from', from);
          $location.search('to', to);
        }
        var countryCode;
        if (country) {
          countryCode = country.split(':')[0];
          $scope.query.country = {
            code: countryCode,
            name: country.split(':')[1]
          };
        }
        params = {
          qt: 'search',
          from: from,
          vcity: vcity,
          to: to,
          city: departure,
          lang: lang,
          skip: skip,
          limit: limit,
          type: type,
          depname: depname,
          country: countryCode
        };
        if (theme && theme.toLowerCase() !== 'tout') {
          params.theme = theme;
        }
        $scope.status = 'searching';
      } else {
        var out = fromStateParam($stateParams);
        $stateParams.from = moment(out.checkin, 'YYYY-MM-DD').format('YYYY-MM-DD');
        $stateParams.to = moment(out.checkout, 'YYYY-MM-DD').format('YYYY-MM-DD');
        $state.transitionTo($state.current, $stateParams, {
          reload: true,
          inherit: false,
          notify: true
        });
        $scope.status = 'filling';
      }
      var options = {
          headers: { 'authorized': settings.tours.authorized },
          params: params
        };
      $http.get(url, options).success(onSearchResults);
      function fromStateParam(input) {
        var output = Object.create(null);
        output.checkin = moment().add(1, 'days').format('YYYY-MM-DD');
        output.checkout = moment().add(60, 'days').format('YYYY-MM-DD');
        return output;
      }
      function decode(tour) {
        var products = [];
        var product;
        if (tour.hasOwnProperty('pricing')) {
          if (tour.pricing[0] !== undefined && tour.pricing[0].rates !== undefined) {
            var rates = tour.pricing[0].rates;
            for (var i = 0; i < rates.length; i++) {
              var ispromo = false;
              var length = rates[i].lines.length || 0;
              var promosProductLines = [];
              for (var j = 0; j < length; j++) {
                if (rates[i].lines[j].price && rates[i].lines[j].priceYield) {
                  if (+rates[i].lines[j].price > +rates[i].lines[j].priceYield) {
                    ispromo = true;
                    product = {
                      code: rates[i].category.code,
                      name: rates[i].category.name,
                      startingAt: rates[i].lines[j].price,
                      ystartingAt: rates[i].lines[j].priceYield,
                      ispromo: ispromo,
                      currency: tour.pricing[0].currency
                    };
                    promosProductLines.push(product);
                  }
                }
              }
              if (promosProductLines.length > 0) {
                product = promosProductLines[0];
              } else {
                product = {
                  code: rates[i].category.code,
                  name: rates[i].category.name,
                  startingAt: rates[i].lines[0].price,
                  ystartingAt: rates[i].lines[0].priceYield,
                  ispromo: ispromo,
                  currency: tour.pricing[0].currency
                };
              }
              ;
              products.push(product);
            }
            products.sort(comparePrice);
          } else {
            console.log('no pricing for tour', tour._id || tour.code);
          }
          tour.products = products;
          tour.href = settings.routes.tour.href.replace(':tour', tour.code);
          tour.href = tour.href + '?from=' + from + '&to=' + to + '&lang=' + lang;
        }
        return tour;
      }
      function getMinPrice() {
        // There's no real number bigger than plus Infinity
        var lowest = Number.POSITIVE_INFINITY;
        // var highest = Number.NEGATIVE_INFINITY;
        var tmp;
        var rates = $scope.pricing.rates;
        for (var i = rates.length - 1; i >= 0; i--) {
          var lines = rates[i].lines;
          for (var j = lines.length - 1; j >= 0; j--) {
            var tmp = lines[j].priceYield;
            if (tmp < lowest)
              lowest = tmp;  //if (tmp > highest) highest = tmp;
          }
        }
        return lowest;
      }
      function comparePrice(producta, productb) {
        //return producta.startingAt - productb.startingAt;
        if (producta.startingAt < productb.startingAt)
          return -1;
        if (producta.startingAt > productb.startingAt)
          return 1;
        return 0;
      }
      function onSearchResults(data, status, fn, o) {
        //console.log("onSearchResults", status);
        switch (status) {
        case 404:
        case 204:
          $scope.status = 'no content';
          break;
        case 206:
        case 200:
          $scope.status = 'found';
          $scope.tours = data.map(decode);
          break;
        default:
          $scope.status = 'error';
          $scope.error = data;
        }
      }
      // simple date picker 
      $scope.singleDatePicker = {
        picker: null,
        options: {
          singleDatePicker: true,
          pickerClasses: 'custom-display',
          buttonClasses: 'btn',
          applyButtonClasses: 'btn-primary',
          cancelButtonClasses: 'btn-danger',
          minDate: moment(),
          locale: {
            applyLabel: 'valider',
            cancelLabel: 'annuler',
            customRangeLabel: 'Custom range',
            separator: ' - ',
            format: 'DD/MM/YYYY',
            weekLabel: 'S',
            daysOfWeek: [
              'Di',
              'Lu',
              'Ma',
              'Me',
              'Je',
              'Ve',
              'Sa'
            ],
            monthNames: [
              'Janvier',
              'F\xe9vrier',
              'Mars',
              'Avril',
              'Mai',
              'Juin',
              'Juillet',
              'Ao\xfbt',
              'Septembre',
              'Octobre',
              'Novembre',
              'Decembre'
            ],
            'firstDay': 1
          },
          eventHandlers: {
            'apply.daterangepicker': function (event, picker) {
              $scope.query.from = $scope.singleDatePicker.date;
            }
          }
        }
      };
      if ($scope.query !== undefined && $stateParams.from) {
        $scope.singleDatePicker.date = $stateParams.from;
      } else {
        $scope.singleDatePicker.date = moment();
      }
    }
  ]);
  ;
  // Source: src/html/scripts/tour-sales/controllers/tour-orders.js
  angular.module('tours').controller('tours_ords', [
    '$scope',
    '$location',
    '$window',
    'settings',
    '$log',
    '$http',
    '$state',
    function ($scope, $location, $window, settings, $log, $http, $state) {
      clear();
      // serach();
      function onSearchResults(data, status, fn, o) {
        switch (status) {
        case 204:
          $scope.status = 'no content';
          $scope.orders = [];
          break;
        case 206:
        case 200:
          $scope.status = 'found';
          $scope.orders = data.map(decode);
          break;
        default:
          $scope.status = 'error';
          $scope.error = data;
          $scope.orders = [];
        }
      }
      function clear() {
        $scope.query = {};
        $scope.orders = [];
        intskiplimit();
      }
      function intskiplimit() {
        $scope.query.skip = 0;
        $scope.query.limit = 20;
      }
      function serach() {
        var created;
        var departureDate;
        var client;
        var traveller;
        var number;
        var status;
        var mod = 'list';
        var url = settings.tours.bookings;
        if ($scope.query.created != undefined)
          created = moment($scope.query.created).format('DD/MM/YYYY');
        // I hate this format, will be changed in ws
        if ($scope.query.deprating != undefined)
          departureDate = moment($scope.query.deprating).format('DD/MM/YYYY');
        //if($scope.query.created != undefined)
        client = '';
        if ($scope.query.traveller != undefined)
          traveller = $scope.query.traveller;
        if ($scope.query.number != undefined)
          number = $scope.query.number;
        if ($scope.query.status != undefined)
          status = $scope.query.status;
        var params = {
            qt: 'filter',
            created: created,
            departureDate: departureDate,
            client: client,
            traveller: traveller,
            number: number,
            mod: mod,
            status: status,
            skip: $scope.query.skip,
            limit: $scope.query.limit
          };
        var options = {
            headers: { authorized: settings.tours.authorized },
            params: params
          };
        console.log('options', options);
        $http.get(url, options).success(onSearchResults);
      }
      function toggleCalendar($event, cal) {
        $event.preventDefault();
        $event.stopPropagation();
        angular.forEach($scope.calendarsOpen, function (value, key) {
          $scope.calendarsOpen[key] = false;
        });
        $scope.calendarsOpen[cal] = !$scope.calendarsOpen[cal];
      }
      function decode(order) {
        order.href = '#/tours/order/' + order.number;
        order.moreTr = false;
        return order;
      }
      $scope.showMoreTravellers = function (index) {
        $scope.orders[index].moreTr = !$scope.orders[index].moreTr;
      };
      function previous() {
        $scope.query.skip -= $scope.query.limit;
        serach();
      }
      function next() {
        $scope.query.skip += $scope.query.limit;
        serach();
      }
      angular.extend($scope, {
        clear: clear,
        next: next,
        intskiplimit: intskiplimit,
        previous: previous,
        serach: serach,
        calendarsOpen: {},
        toggleCalendar: toggleCalendar
      });
    }
  ]);
  // Source: src/html/scripts/tour-sales/controllers/tour-quote.js
  angular.module('tours').controller('tours_TourQuoteCtrl', [
    '$scope',
    '$http',
    '$stateParams',
    '$rootScope',
    '$timeout',
    '$location',
    'settings',
    'tourQuoteService',
    '$window',
    '$log',
    '$filter',
    function ($scope, $http, $stateParams, $rootScope, $timeout, $location, settings, tourQuoteService, $window, $log, $filter) {
      $scope.roomnbr = 1;
      $scope.rooms = [1];
      var isoDate = 'YYYY-MM-DD';
      var options = {
          adults: [
            1,
            2,
            3,
            4,
            5,
            6
          ],
          children: [
            0,
            1,
            2,
            3,
            4,
            5,
            6
          ],
          ages: [
            1,
            2,
            3,
            4,
            5,
            6,
            7,
            8,
            9,
            10,
            11
          ],
          quantities: [
            0,
            0
          ],
          boardQte: [
            0,
            0
          ]
        };
      var omraOptions = {
          single: {
            adults: [1],
            chds: [0]
          },
          double: {
            adults: [
              1,
              2
            ],
            chds: [
              0,
              1,
              2
            ]
          },
          triple: {
            adults: [
              1,
              2,
              3
            ],
            chds: [
              0,
              1,
              2
            ]
          },
          quadruple: {
            adults: [
              1,
              2,
              3,
              4
            ],
            chds: [0]
          }
        };
      var request = { children: [] };
      function getMinPrice() {
        // There's no real number bigger than plus Infinity
        var lowest = Number.POSITIVE_INFINITY;
        // var highest = Number.NEGATIVE_INFINITY;
        var tmp;
        var rates = $scope.pricing.rates;
        for (var i = rates.length - 1; i >= 0; i--) {
          var lines = rates[i].lines;
          for (var j = lines.length - 1; j >= 0; j--) {
            var tmp = lines[j].priceYield;
            if (tmp < lowest)
              lowest = tmp;  //if (tmp > highest) highest = tmp;
          }
        }
        $scope.minPrice = lowest;  //$scope.maxPrice = highest;
      }
      function roomTypeChanged() {
        var t = $scope.query.type;
        $scope.nbrOfAdults = omraOptions[t]['adults'];
        $scope.query.maxchildren = omraOptions[t]['chds'];
        angular.extend($scope.query, {
          single: 0,
          double: 0,
          triple: 0,
          quadruple: 0,
          doubleWithChild: 0,
          adults: 1,
          children: 0
        });
        $scope.query[t] = 1;
        $scope.showRates = false;
        $scope.selectedDate = null;  //adultCountChanged();
      }
      function adultCountChanged() {
        if ($scope.tour.type === 'Tour' || $scope.tour.type === 'VO') {
          $scope.query.adults = $scope.query.single + ($scope.query.double + $scope.query.doubleWithChild) * 2 + $scope.query.triple * 3 + $scope.query.quadruple * 4;
        }
        var N = $scope.query.adults + $scope.query.children + 1;
        options.boardQte = Array.apply(null, { length: N }).map(Number.call, Number);
        options.quantities = [
          0,
          $scope.query.adults
        ];
        $scope.products = null;
        $scope.product = null;
        $scope.query.maxchildren = [0];
        var nbr = $scope.query.double * 3 + $scope.query.triple;
        //console.log("nbr ", nbr);
        for (var i = 1; i <= nbr; i++) {
          $scope.query.maxchildren.push(i);
        }
        ;  //console.log("$scope.query.maxchildren ", $scope.query.maxchildren);
      }
      /**
         * Listen for child count change to push/pop elements from ages
         */
      function childCountChanged() {
        var ages = $scope.query.ages;
        //console.log('childCountChanged',count)
        var i = 0;
        while (ages.length < $scope.query.doubleWithChild) {
          ages.push({
            'i': i++,
            'v': $scope.query.age
          });
        }
        // remove elements if length > count
        while (ages.length > $scope.query.doubleWithChild) {
          ages.pop();
        }
        var N = $scope.query.adults + $scope.query.children + 1;
        options.boardQte = Array.apply(null, { length: N }).map(Number.call, Number);  ////console.log("in childCountChanged",ages.length,$scope.query.ages)
      }
      function setChildren() {
        var ages = $scope.query.ages;
        //console.log('setChildren ages children', $scope.query.ages, $scope.query.children);
        var i = 0;
        while (i < $scope.query.children) {
          //$scope.query.ages[i] = 0;
          //i++;
          ages.push({
            'i': i++,
            'v': $scope.query.age
          });
        }
        // remove elements if length > count
        while (ages.length > $scope.query.children) {
          ages.pop();
        }  //console.log("in setChildren", ages.length, $scope.query.ages)
      }
      function addchildage() {
        var ages = $scope.query.ages;
        ages.push(query.age);
      }
      // Should go to a servce in v1, to nodejs in v2 to tour-server in v3...
      function _getDepartures(rates) {
        // all we need is rates[n].lines aggregated in one arre (reduce...etc)
        var result = [];
        rates.map(function (rate) {
          return rate.lines;
        }).reduce(function (reduced, lines) {
          var i = lines.length, tmp;
          while (i--) {
            tmp = lines[i].departure.split('T')[0];
            if (reduced.indexOf(tmp) === -1) {
              reduced.push(tmp);
            }
          }
          return reduced;
        }, result);
        result.sort();
        return result;
      }
      /**
         * Process http success
         */
      function _processRatesResponse(data) {
        if (data != undefined && data[0] != undefined && data[0].pricing != undefined && data[0].pricing[0] != undefined) {
          $scope.pricing = data[0].pricing[0];
          $scope.currency = $scope.pricing.currency;
          $scope.departures = _getDepartures($scope.pricing.rates);
        }
        $log.debug('pricing', $scope.pricing);
        $log.debug('dates', $scope.departures);
        updateCalendar($scope.departures);
        getMinPrice();
      }
      function _processRatesError() {
        $log.error('Error querying rates', arguments);
        $scope.error = arguments;
      }
      function queryRates(query) {
        $log.debug('queryRates: query', query);
        var params = {
            qt: 'search',
            tour: query.tour,
            from: moment(query.from).format(isoDate),
            to: moment(query.to).format(isoDate),
            lang: query.lang
          };
        var options = {
            headers: { 'authorized': settings.tours.authorized },
            params: params
          };
        //var url = settings.tours.search;
        var url = settings.tours.endpoint;
        //console.log('--------------url -----------', url);
        // this should be in settings. And we shouldn't call ratesGroup
        // there should be a getDepartures service then a quoteDeparture service...
        $http.get(url, options).success(_processRatesResponse).error(_processRatesError).finally(function () {
        });
      }
      // Builds a data object for a day to be used in calendar.
      function _buildDay(d, deps, month, week) {
        var date = d.format(isoDate), day = {
            label: d.month() === month ? d.date() : '',
            date: moment.utc(d).startOf('day').toDate(),
            currentMonth: d.month() === month,
            departure: deps.indexOf(date) > -1
          };
        //console.log('build day', day);
        week.push(day);
      }
      function _getDateRate(date, lines) {
        var i = lines.length;
        var mDate = moment.utc(date);
        while (i--) {
          if (moment(lines[i].departure).isSame(mDate, 'day')) {
            var ln = lines[i];
            ln.code = $scope.pricing.code;
            return ln;
          }
        }
        return null;
      }
      function updateCalendar(departures) {
        var firstOfMonth = moment.utc(departures[0], isoDate).startOf('month');
        //console.log("firstOfMonth ",firstOfMonth);
        var month = firstOfMonth.month();
        var d = moment.utc(firstOfMonth).startOf('isoWeek');
        var weeks = [], week = [];
        //console.log('firstDayOfMonth',firstOfMonth,'month',month,'d',d)    ;
        //console.log('(d.month(',d.month(),'month',month)    ;
        while (d.isBefore(firstOfMonth, 'day') || d.month() === month) {
          _buildDay(d, departures, month, week);
          d.add('days', 1);
          // week end
          if (week.length === 7) {
            weeks.push(week);
            week = [];
          }
        }
        while (week.length > 0 && week.length < 7) {
          _buildDay(d, departures, month, week);
          d.add('days', 1);
        }
        weeks.push(week);
        $scope.weeks = weeks;
        $scope.firstOfMonth = firstOfMonth.toDate();
      }
      function goToMonth(date, diff) {
        var m = 'month';
        var operation = diff > 0 ? 'add' : 'subtract';
        var target = moment(date)[operation](m, 1).startOf(m);
        var q = $scope.query;
        q.from = target.toDate();
        q.to = moment(target).endOf(m).toDate();
        queryRates(q);
      }
      function nextMonth(date) {
        goToMonth(date, 1);
      }
      function previousMonth(date) {
        goToMonth(date, -1);
      }
      function showProducts(date) {
        $scope.depDate = moment(date).format('DD-MM-YYYY');
        $scope.arivDate = moment(date).add($scope.tour.days.length, 'days').format('DD-MM-YYYY');
        var categories = $scope.pricing.rates, category, rate, selection = [], i = categories.length;
        while (i--) {
          category = categories[i];
          rate = _getDateRate(date, category.lines);
          //console.log("selected rate ", rate);
          if (rate !== null) {
            if (rate.promo) {
              rate.priceYield = rate.promo.value;  //rawProduct.promo = rate.promo.name;
            }
            // if ($scope.query.triple === 1){
            // }
            selection.unshift({
              code: category.category.code,
              name: category.category.name,
              rate: rate
            });
          } else {
            console.warn('no rate for ' + date + ' in cat' + category.category);
          }
        }
        //console.log("showProducts products ", selection);
        $scope.products = selection;
        $scope.product = null;
        $scope.selectedDate = date;
        $scope.showRates = true;
      }
      function showRules(p) {
        p.rate.showRules = !p.rate.showRules;
      }
      function sendFormStatus() {
        $scope.productButtonSelected = false;
      }
      function selectProduct(p) {
        $scope.productButtonSelected = true;
        $scope.clicked = true;
        $scope.devisOn = true;
        var query = $scope.query;
        query.currency = $scope.currency;
        $scope.product = p;
        //console.log("selectProduct ", p);
        //console.log(" devis tour quote : ", $scope.devisOn);
        $scope.quote = tourQuoteService.quote($scope.tour, p, query);
        /*
               for (var i = 0 ; i<query.adults ; i++) {
                 $scope.quote.trip.travellers.push( {"classification": "ADULT","id": i,"type": "Traveller"});
               };
                for (var i = 0 ; i<query.ages.length ; i++) {
                 $scope.quote.trip.travellers.push( {"classification": "CHILD","age": query.ages[i].v ,"id": query.adults+i,"type": "Traveller"} );

             };*/
        $scope.paxes = query.adults + query.ages.length;
      }
      function checkDisabledConditions() {
        //console.log('checkDisabledConditions $scope.products', $scope.products, $scope.productButtonSelected)
        //if (($scope.products == null || $scope.products.length <= 0) && $scope.productButtonSelected == false)
        if (angular.isArray($scope.products) && $scope.products.length > 0 && $scope.productButtonSelected === true)
          return false;
        else
          return true;
      }
      function optionSelected(opt) {
        return opt.qty > 0;
      }
      function quantityChanged(item) {
        if (item['@type'] === 'tourExtra' && item.product.type === 'board') {
          for (var i = $scope.quote.items.length - 1; i >= 0; i--) {
            var it = $scope.quote.items[i];
            //console.log("it is ", item);
            if (it != item && it['@type'] === 'tourExtra' && it.product.type === 'board') {
              $scope.quote.totals.total = $scope.quote.totals.total - it.totals.total;
              it.qty = 0;
              it.totals.total = 0;
            }
          }
        }
        ;
        var oldTotal = item.totals.total || 0;
        item.totals.total = item.product.price * item.qty;
        var diff = item.totals.total - oldTotal;
        $scope.quote.totals.total += diff;
      }
      function errorCallback(error) {
        $scope.error = error;
      }
      function cartSaveFailure(error) {
        $scope.error = error;
        $log.error('cart saving failed', error);
      }
      function cartSaveSuccess() {
        $scope.status = 'checkoutRedirect';
        $log.debug('cart saved', arguments);
        $window.location.href = settings.links.checkout;
      }
      function book(quote) {
        /*
               $http.delete('/carts')
                .then(function() {
                $http.put('/carts',$scope.quote).then(cartSaveSuccess, cartSaveFailure);
            }); */
        $scope.quote.rooms = {
          single: $scope.query.single,
          double: $scope.query.double,
          doubleWithChild: $scope.query.doubleWithChild,
          triple: $scope.query.triple,
          quadruple: $scope.query.quadruple
        };
        $http.post('/carts', $scope.quote).then(function (res) {
          if (angular.isArray(res.data)) {
            res.data = res.data[0];
          }
          $scope.$emit('bookCartSaved', res.data);
          $window.location.href = '/ngapps/checkout#/' + res.data._id;
        }, function failed() {
          $log.error('cart saving failed', arguments);
        });
      }
      function requestSaved() {
        $scope.requestStatus = 'success';
        if (window.ga) {
          window.ga('send', 'event', 'voyage', 'demande', $rootScope.meta && $rootScope.meta.title);
        }
      }
      function requestSaveFailed() {
        $scope.requestStatus = 'failed';
      }
      function sendReservation() {
        $scope.requestStatus = 'saving';
        var productName = '';
        for (var i = $scope.query.ages.length - 1; i >= 0; i--) {
          request.children.push({ age: $scope.query.ages[i] });
        }
        request.adults = $scope.query.adults;
        if (angular.isArray($scope.products) && $scope.products.length > 0) {
          if ($scope.products[0].parent) {
            productName = $scope.products[0].parent.name + ' ' + $scope.products[0].name;
          }
        }
        request.product = {
          _id: $scope.query.tour,
          name: productName
        };
        request.departure = $scope.query.from;
        $log.debug('request', $scope.request);
        //return;
        $http.post('/travel-product-requests', $scope.request).success(requestSaved).error(requestSaveFailed);
      }
      function clearRates() {
        $scope.showRates = false;
        $scope.selectedDate = null;
      }
      function initChildAges() {
        var children = $scope.query.children;
        var length = children.length;
        for (var i = 0; i < length; i++) {
          $scope.query.ages[i] = 1;
        }
      }
      function buildQuery() {
        var from = moment($stateParams.from || 'invalid', isoDate), to = moment($stateParams.to || 'invalid', isoDate), lang = $stateParams.lang, ages, adults = /\d/.test($stateParams.adults) ? parseInt($stateParams.adults, 10) : 1;
        /*if (!from.isValid() || from.isBefore()) {
                from = moment().startOf('day');
            }*/
        if (!to.isValid() || to.isBefore(from, 'day') || to.isSame(from, 'day')) {
          to = moment(from);
          to.add('months', 1);
        }
        // regex should not allow 0 or above 12
        if (/\d{1,2}(,\d{1,2})*/.test($stateParams.children)) {
          ages = $stateParams.children.split(',').map(function (element) {
            var a = parseInt(element, 10);
            return 0 < a && a < 12 ? a : 0;
          });
        } else {
          ages = [];
        }
        return {
          tour: $stateParams.tour,
          from: from.toDate(),
          to: to.toDate(),
          lang: lang,
          adults: 0,
          single: 0,
          double: 0,
          doubleWithChild: 0,
          triple: 0,
          quadruple: 0,
          ages: [],
          children: [],
          age: 0,
          maxchildren: [0],
          children: 0,
          type: 'single'
        };
      }
      //type: 'single'
      angular.extend($scope, {
        childCountChanged: childCountChanged,
        setChildren: setChildren,
        addchildage: addchildage,
        nextMonth: nextMonth,
        previousMonth: previousMonth,
        showProducts: showProducts,
        selectProduct: selectProduct,
        showRules: showRules,
        optionSelected: optionSelected,
        quantityChanged: quantityChanged,
        book: book,
        adultCountChanged: adultCountChanged,
        getQuote: '',
        sendFormStatus: sendFormStatus,
        productButtonSelected: false,
        checkDisabledConditions: checkDisabledConditions,
        sendReservation: sendReservation,
        request: request,
        roomTypeChanged: roomTypeChanged,
        nbrOfAdults: [1],
        clearRates: clearRates,
        initChildAges: initChildAges,
        depDate: null,
        generatePdfTarifs: generatePdfTarifs,
        loadingTarif: false,
        devisOn: false,
        depDate: null,
        options: options,
        query: buildQuery()
      });
      $log.debug('query', $scope.query);
      queryRates($scope.query);
      //******** generate tarifs pdf ******//
      function generatePdfTarifs() {
        var date = $filter('date')($scope.currentDate, 'yyyy-MM-dd');
        $scope.loadingTarif = true;
        kendo.pdf.defineFont({
          'DejaVu Sans': 'https://kendo.cdn.telerik.com/2016.1.112/styles/fonts/DejaVu/DejaVuSans.ttf',
          'DejaVu Sans|Bold': 'https://kendo.cdn.telerik.com/2016.1.112/styles/fonts/DejaVu/DejaVuSans-Bold.ttf',
          'DejaVu Sans|Bold|Italic': 'https://kendo.cdn.telerik.com/2016.1.112/styles/fonts/DejaVu/DejaVuSans-Oblique.ttf',
          'DejaVu Sans|Italic': 'https://kendo.cdn.telerik.com/2016.1.112/styles/fonts/DejaVu/DejaVuSans-Oblique.ttf'
        });
        //console.log(' in generate devis as pdf');
        $timeout(function () {
          kendo.drawing.drawDOM('#tarifs', {
            paperSize: 'A4',
            margin: '1cm',
            scale: 0.7
          }).then(function (group) {
            kendo.drawing.pdf.saveAs(group, 'devis ' + $scope.tour.name + '-' + date + '.pdf');
            $scope.loadingTarif = false;
            //console.log(' end generate devis as pdf');
            $scope.$apply();
          });
        }, 10);
      }
    }
  ]);
  /*$scope.childrenAges = [
            { id: 0, age: 0 },
            { id: 1, age: 1 },
            { id: 2, age: 2 },
            { id: 3, age: 3 },
            { id: 4, age: 4 },
            { id: 5, age: 5 },
            { id: 6, age: 6 },
            { id: 7, age: 7 },
            { id: 8, age: 8 },
            { id: 9, age: 9 },
            { id: 10, age: 10 },
            { id: 11, age: 11 }
        ];*/
  // Source: src/html/scripts/tour-sales/controllers/tour.js
  angular.module('tours').controller('tours_TourCtrl', [
    '$scope',
    '$http',
    '$q',
    '$stateParams',
    '$location',
    '$timeout',
    'settings',
    '$log',
    'tourQuoteService',
    '$rootScope',
    '$anchorScroll',
    '$window',
    '$filter',
    function ($scope, $http, $q, $stateParams, $location, $timeout, settings, $log, tourQuoteService, $rootScope, $anchorScroll, $window, $filter) {
      // $log.log("tours_TourCtrl ", settings);
      var tour = {};
      var kendoGroupe = null;
      // Get description
      var url = settings.tours.descriptions;
      function showMoreDaysProgram() {
        $scope.daysProgram = !$scope.daysProgram;  //console.log("------------ program days -------------", $scope.daysProgram);
      }
      $scope.daysProgram = false;
      var _options = { headers: { authorized: settings.tours.authorized } };
      var promises = {
          description: $http.get(url + '?qt=byTour&tour=' + $stateParams.tour + '&lang=' + $stateParams.lang, _options),
          tourData: $http.get(settings.tours.endpoint + '/' + $stateParams.tour, _options)
        };
      function setup(resolvedData) {
        ////console.log("in setup data", resolvedData);
        var description = resolvedData.description.data[0];
        angular.extend(tour, { description: description });
        var data = resolvedData.tourData.data;
        $scope.pdfImage = data.photos[0].url.replace('http', 'https');
        data.photos.forEach(function (p, i) {
          //settings.tour.imgrsz
          p.url = i === 0 ? 'https://imgrsz.atlasvoyages.com/img/1920x1000/' + p.url : 'https://imgrsz.atlasvoyages.com/img/750x450/' + p.url;  //p.url = p.url.replace("http", "https");
                                                                                                                                                //p.url = p.url.replace("https://imgrsz.atlasvoyages.com/img/750x450/http", "https");
        });
        var facebookMeta = {
            title: data.name,
            description: description.lead,
            image: data.photos[0].url,
            url: 'https://www.atlasvoyages.com/ngapps/vo-sales#/tour/' + $stateParams.tour + '?from=' + $stateParams.from + '&to=' + $stateParams.to + '&lang=fr'
          };
        data.facebookMeta = facebookMeta;
        angular.extend(tour, data);
        $scope.tour = tour;
        // $log.debug("emit tourProducthQuery", JSON.stringify($scope.tour.name));
        // $scope.$emit("tourProducthQuery", $scope.tour.name);
        $scope.context = 'product';
      }
      $q.all(promises).then(setup);
      $scope.myInterval = 4000;
      $scope.roomnbr = 1;
      $scope.rooms = [1];
      var isoDate = 'YYYY-MM-DD';
      var options = {
          adults: [
            1,
            2,
            3,
            4,
            5,
            6
          ],
          children: [
            0,
            1,
            2,
            3,
            4,
            5,
            6
          ],
          ages: [
            1,
            2,
            3,
            4,
            5,
            6,
            7,
            8,
            9,
            10,
            11
          ],
          quantities: [
            0,
            0
          ],
          boardQte: [
            0,
            0
          ]
        };
      var omraOptions = {
          single: {
            adults: [1],
            chds: [0]
          },
          double: {
            adults: [
              1,
              2
            ],
            chds: [
              0,
              1,
              2
            ]
          },
          triple: {
            adults: [
              1,
              2,
              3
            ],
            chds: [
              0,
              1,
              2
            ]
          },
          quadruple: {
            adults: [
              1,
              2,
              3,
              4
            ],
            chds: [0]
          }
        };
      var request = { children: [] };
      function getMinPrice() {
        // There's no real number bigger than plus Infinity
        var lowest = Number.POSITIVE_INFINITY;
        // var highest = Number.NEGATIVE_INFINITY;
        var tmp, date, departureDate;
        var rates = $scope.pricing.rates;
        for (var i = rates.length - 1; i >= 0; i--) {
          var lines = rates[i].lines;
          for (var j = 0; j < lines.length; j++) {
            tmp = lines[j].priceYield;
            if (lines[j].promo && lines[j].promo.value < tmp) {
              tmp = lines[j].promo.value;  //console.log('--------------------- lines in rates  to get the min price ', lines);
            } else if (lines[j].quadruple && lines[j].quadruple < tmp) {
              tmp = lines[j].quadruple;
            } else if (lines[j].tripleReduction && lines[j].tripleReduction[0] < tmp) {
              tmp = lines[j].tripleReduction[0];
            }
            date = lines[j].departure;
            if (tmp < lowest) {
              lowest = tmp;
              departureDate = date;
            }  //if (tmp > highest) highest = tmp;
          }
        }
        $scope.minPrice = lowest;
        $scope.departureDate = moment(departureDate).format('DD-MM-YYYY');  //$scope.maxPrice = highest;
      }
      function roomTypeChanged() {
        var t = $scope.query.type;
        $scope.nbrOfAdults = omraOptions[t]['adults'];
        $scope.query.maxchildren = omraOptions[t]['chds'];
        angular.extend($scope.query, {
          single: 0,
          double: 0,
          triple: 0,
          quadruple: 0,
          doubleWithChild: 0,
          adults: 1,
          children: 0
        });
        $scope.query[t] = 1;
        $scope.showRates = false;  //$scope.selectedDate = null;
                                   //adultCountChanged();
                                   //$scope.products = null;
                                   //$scope.product = null;
      }
      function clearRates() {
        $scope.showRates = false;  //$scope.selectedDate = null;
                                   //$scope.products = null;
                                   //$scope.product = null;
      }
      function scrollTo(id) {
        ////console.log('scrolling id', id);
        $location.hash(id);
        $anchorScroll();
      }
      function buildQuery() {
        // $log.debug('$stateParams --------------------------', $stateParams);
        var from = moment($stateParams.from || 'invalid', isoDate), to = moment($stateParams.to || 'invalid', isoDate), lang = $stateParams.lang ? $stateParams.lang : 'fr', ages, adults = /\d/.test($stateParams.adults) ? parseInt($stateParams.adults, 10) : 1;
        if (!from.isValid()) {
          //|| from.isBefore()
          from = moment().startOf('day');
        }
        if (!to.isValid() || to.isBefore(from, 'day') || to.isSame(from, 'day')) {
          to = moment(from);
          to.add('months', 1);
        }
        // regex should not allow 0 or above 12
        if (/\d{1,2}(,\d{1,2})*/.test($stateParams.children)) {
          ages = $stateParams.children.split(',').map(function (element) {
            var a = parseInt(element, 10);
            return 0 < a && a < 12 ? a : 0;
          });
        } else {
          ages = [];
        }
        return {
          tour: $stateParams.tour,
          from: from.toDate(),
          to: to.toDate(),
          lang: lang,
          adults: 0,
          ages: [],
          children: [],
          single: 0,
          double: 0,
          doubleWithChild: 0,
          triple: 0,
          quadruple: 0,
          age: 0,
          maxchildren: [0],
          children: 0,
          type: ''
        };
      }
      /**
     * Listen for child count change to push/pop elements from ages
     */
      function childCountChanged() {
        var ages = $scope.query.ages;
        ////console.log('childCountChanged',count)
        var i = 0;
        while (ages.length < $scope.query.doubleWithChild) {
          ages.push({
            i: i++,
            v: $scope.query.age
          });
        }
        // remove elements if length > count
        while (ages.length > $scope.query.doubleWithChild) {
          ages.pop();
        }  // //console.log("in childCountChanged",ages.length,$scope.query.ages)
      }
      function setChildren() {
        var ages = $scope.query.ages;
        var i = 0;
        while (ages.length < $scope.query.children) {
          ages.push({
            i: i++,
            v: $scope.query.age
          });
        }
        // remove elements if length > count
        while (ages.length > $scope.query.children) {
          ages.pop();
        }  //console.log("in setChildren", ages.length, $scope.query.ages);
      }
      function addchildage() {
        var ages = $scope.query.ages;
        ages.push(query.age);
      }
      $scope.singleOps = [];
      $scope.doubleOps = [];
      for (var i = 0; i <= 3; i++) {
        var o = {
            label: i,
            value: i
          };
        $scope.singleOps.push(o);
        $scope.doubleOps.push(o);
      }
      ;
      $scope.tripleOps = [];
      for (var i = 0; i <= 1; i++) {
        var o = {
            label: i,
            value: i
          };
        $scope.tripleOps.push(o);
      }
      ;
      $scope.childrenOps = [{
          label: '0',
          value: '0'
        }];
      $scope.agesOps = [];
      for (var i = 0; i <= 11; i++) {
        var o = {
            label: i,
            value: i
          };
        $scope.agesOps.push(o);
      }
      $scope.singleSelection = 0;
      $scope.doubleSelection = 0;
      $scope.tripleSelection = 0;
      $scope.childrenSelection = 0;
      $scope.agesSelection = 0;
      $scope.$watch('singleSelection', function (newVal) {
        $scope.query.single = newVal;
        if ($scope.tour !== undefined) {
          adultCountChanged();
          sendFormStatus();
        }
      });
      $scope.$watch('doubleSelection', function (newVal) {
        $scope.query.double = newVal;
        if ($scope.tour !== undefined) {
          adultCountChanged();
          sendFormStatus();
        }
      });
      $scope.$watch('tripleSelection', function (newVal) {
        $scope.query.triple = newVal;
        if ($scope.tour !== undefined) {
          adultCountChanged();
          sendFormStatus();
        }
      });
      $scope.$watch('childrenSelection', function (newVal) {
        $scope.query.children = newVal;
        if ($scope.tour !== undefined) {
          setChildren();
          sendFormStatus();
        }
      });
      $scope.$watch('agesSelection', function (newVal) {
        // $scope.query.ages[$index] = newVal;
        if ($scope.tour !== undefined) {
          setChildren();
          adultCountChanged();
          sendFormStatus();
        }
      });
      function adultCountChanged() {
        // console.log("--------------------- hdfgkjdhgkjhdfjkgh ----------------", $scope.tour);
        if ($scope.tour.type === 'Tour' || $scope.tour.type === 'VO' || $scope.tour.type === 'OMRA') {
          $scope.query.adults = $scope.query.single + ($scope.query.double + $scope.query.doubleWithChild) * 2 + $scope.query.triple * 3 + $scope.query.quadruple * 4;
        }
        var N = $scope.query.adults + 1;
        options.boardQte = Array.apply(null, { length: N }).map(Number.call, Number);
        options.quantities = [
          0,
          $scope.query.adults
        ];
        //$scope.products = null;
        //$scope.product = null;
        $scope.query.maxchildren = [0];
        // var nbr = $scope.query.double * 3 + $scope.query.triple;
        var nbr = $scope.query.double;
        //console.log("nbr ", nbr);
        for (var i = 1; i <= nbr; i++) {
          $scope.query.maxchildren.push(i);
        }  //console.log("$scope.query.maxchildren ", $scope.query.maxchildren);
      }
      // Should go to a servce in v1, to nodejs in v2 to tour-server in v3...
      function _getDepartures(rates) {
        // all we need is rates[n].lines aggregated in one arre (reduce...etc)
        var result = [];
        rates.map(function (rate) {
          return rate.lines;
        }).reduce(function (reduced, lines) {
          var i = lines.length, tmp;
          while (i--) {
            tmp = lines[i].departure.split('T')[0];
            if (reduced.indexOf(tmp) === -1) {
              reduced.push(tmp);
            }
          }
          return reduced;
        }, result);
        result.sort();
        return result;
      }
      /**
     * Process http success
     */
      function _processRatesResponse(data) {
        if (data != undefined && data[0] != undefined && data[0].pricing != undefined && data[0].pricing[0] != undefined) {
          $scope.pricing = data[0].pricing[0];
          $scope.currency = $scope.pricing.currency;
          $scope.departures = _getDepartures($scope.pricing.rates);
        }
        // $log.debug("pricing", $scope.pricing);
        // $log.debug("dates", $scope.departures);
        // console.log("------------ date departues  ------------", $scope.departures);
        updateCalendar($scope.departures);
        getMinPrice();  // generatePdfOnit();
      }
      function _processRatesError() {
        $log.error('Error querying rates', arguments);
        $scope.error = arguments;
      }
      function queryRates(query) {
        // $log.debug("queryRates: query", query);
        //console.log('--------------------------query in set date ', query);
        var params = {
            qt: 'search',
            tour: query.tour,
            from: moment(query.from).format(isoDate),
            to: moment(query.to).format(isoDate),
            lang: query.lang
          };
        var options = {
            headers: { authorized: settings.tours.authorized },
            params: params
          };
        var url = settings.tours.endpoint;
        // this should be in settings. And we shouldn't call ratesGroup
        // there should be a getDepartures service then a quoteDeparture service...
        $http.get(url, options).success(_processRatesResponse).error(_processRatesError).finally(function () {
        });
      }
      // Builds a data object for a day to be used in calendar.
      function _buildDay(d, deps, month, week) {
        var date = d.format(isoDate), day = {
            label: d.month() === month ? d.date() : '',
            date: moment.utc(d).startOf('day').toDate(),
            currentMonth: d.month() === month,
            departure: deps.indexOf(date) > -1,
            selected: false
          };
        ////console.log('build day', day);
        week.push(day);
      }
      function _getDateRate(date, lines) {
        var i = lines.length;
        var mDate = moment.utc(date);
        while (i--) {
          if (moment(lines[i].departure).isSame(mDate, 'day')) {
            var ln = lines[i];
            ln.code = $scope.pricing.code;
            //console.log('---------------------- get date rate ', ln);
            return ln;
          }
        }
        return null;
      }
      function updateCalendar(departures) {
        var firstOfMonth = moment.utc(departures[0], isoDate).startOf('month');
        ////console.log("firstOfMonth ",firstOfMonth);
        var month = firstOfMonth.month();
        var d = moment.utc(firstOfMonth).startOf('isoWeek');
        var weeks = [], week = [];
        ////console.log('firstDayOfMonth',firstOfMonth,'month',month,'d',d)    ;
        ////console.log('(d.month(',d.month(),'month',month)    ;
        while (d.isBefore(firstOfMonth, 'day') || d.month() === month) {
          _buildDay(d, departures, month, week);
          d.add('days', 1);
          // week end
          if (week.length === 7) {
            weeks.push(week);
            week = [];
          }
        }
        while (week.length > 0 && week.length < 7) {
          _buildDay(d, departures, month, week);
          d.add('days', 1);
        }
        weeks.push(week);
        $scope.weeks = weeks;
        $scope.firstOfMonth = firstOfMonth.toDate();
      }
      function goToMonth(date, diff) {
        var m = 'month';
        var operation = diff > 0 ? 'add' : 'subtract';
        var target = moment(date)[operation](1, m).startOf(m);
        var q = $scope.query;
        q.from = target.toDate();
        q.to = moment(target).endOf(m).toDate();
        // $log.debug("goToMonth query", q);
        queryRates(q);
      }
      function nextMonth(date) {
        goToMonth(date, 1);
      }
      function previousMonth(date) {
        goToMonth(date, -1);
      }
      // $scope.departureDate = null;
      function showProducts(date) {
        //console.log("date", date);
        $scope.depDate = moment(date).format('DD-MM-YYYY');
        $scope.arivDate = moment(date).add($scope.tour.days.length, 'days').format('DD-MM-YYYY');
        var categories = $scope.pricing.rates, category, rate, selection = [], i = categories.length;
        while (i--) {
          category = categories[i];
          ////console.log("----------------------selected categories ", category);
          rate = _getDateRate(date, category.lines);
          ////console.log("----------------------selected rate ", rate);
          if (rate !== null) {
            if (rate.promo) {
              rate.priceYield = rate.promo.value;  ////console.log("----------------------selected  promo rate ", rate);
                                                   //rawProduct.promo = rate.promo.name;
            }
            selection.unshift({
              code: category.category.code,
              name: category.category.name,
              rate: rate,
              quadruple: category.category.quadruple
            });
          } else {
          }
        }
        //  //console.log("showProducts products ",selection);
        $scope.products = selection;
        $scope.product = null;
        for (var i = 0; i < $scope.weeks.length; i++) {
          for (var j = 0; j < $scope.weeks[i].length; j++) {
            date = new moment(new moment(date).format('DD/MM/YYYY'), 'DD/MM/YYYY');
            $scope.weeks[i][j].date = new moment(new moment($scope.weeks[i][j].date).format('DD/MM/YYYY'), 'DD/MM/YYYY');
            if (date.isSame($scope.weeks[i][j].date)) {
              $scope.weeks[i][j].selected = true;
            } else {
              $scope.weeks[i][j].selected = false;
            }
          }
        }
      }
      function showRules(p) {
        p.rate.showRules = !p.rate.showRules;
      }
      function sendFormStatus() {
        $scope.productButtonSelected = false;
        $scope.product = null;
      }
      function selectProduct(p) {
        $scope.productButtonSelected = true;
        $scope.devisOn = true;
        var query = $scope.query;
        query.currency = $scope.currency;
        $scope.product = p;
        //console.log("selectProduct ", p);
        $scope.quote = tourQuoteService.quote($scope.tour, p, query);
        /*

        for (var i = 0 ; i<query.adults ; i++) {
        $scope.quote.trip.travellers.push( {"classification": "ADULT","id": i,"type": "Traveller"});

        };
      for (var i = 0 ; i<query.ages.length ; i++) {
        $scope.quote.trip.travellers.push( {"classification": "CHILD","age": query.ages[i].v ,"id": query.adults+i,"type": "Traveller"} );

      };*/
        $scope.paxes = query.adults + query.ages.length;
      }
      function checkDisabledConditions() {
        if (angular.isArray($scope.products) && $scope.products.length > 0 && $scope.productButtonSelected === true)
          return false;
        else
          return true;
      }
      function optionSelected(opt) {
        return opt.qty > 0;
      }
      function quantityChanged(item) {
        if (item['@type'] === 'tourExtra' && item.product.type === 'board') {
          for (var i = $scope.quote.items.length - 1; i >= 0; i--) {
            var it = $scope.quote.items[i];
            ////console.log("it is ", item);
            if (it != item && it['@type'] === 'tourExtra' && it.product.type === 'board') {
              $scope.quote.totals.total = $scope.quote.totals.total - it.totals.total;
              it.qty = 0;
              it.totals.total = 0;
            }
          }
        }
        var oldTotal = item.totals.total || 0;
        item.totals.total = item.product.price * item.qty;
        var diff = item.totals.total - oldTotal;
        $scope.quote.totals.total += diff;
      }
      function errorCallback(error) {
        $scope.error = error;
      }
      function cartSaveFailure(error) {
        $scope.error = error;
        $log.error('cart saving failed', error);
      }
      function cartSaveSuccess() {
        $scope.status = 'checkoutRedirect';
        // $log.debug("cart saved", arguments);
        $window.location.href = settings.links.checkout;
      }
      function book(quote) {
        /*
						   $http.delete('/carts')
							.then(function() {
							$http.put('/carts',$scope.quote).then(cartSaveSuccess, cartSaveFailure);
						}); */
        $scope.quote.rooms = {
          single: $scope.query.single,
          double: $scope.query.double,
          doubleWithChild: $scope.query.doubleWithChild,
          triple: $scope.query.triple,
          quadruple: $scope.query.quadruple
        };
        //console.log('in book')
        $http.post('/carts', $scope.quote).then(function (res) {
          //console.log("saveCard..tour");
          if (angular.isArray(res.data)) {
            res.data = res.data[0];
          }
          $scope.$emit('bookCartSaved', res.data);
          $window.location.href = '/ngapps/checkout#/' + res.data._id;
        }, function failed() {
          $log.error('cart saving failed', arguments);
        });
      }
      function requestSaved() {
        $scope.requestStatus = 'success';
        if (window.ga) {
          window.ga('send', 'event', 'voyage', 'demande', $rootScope.meta && $rootScope.meta.title);
        }
      }
      function requestSaveFailed() {
        $scope.requestStatus = 'failed';
      }
      function initChildAges() {
        var children = $scope.query.children;
        var length = children.length;
        for (var i = 0; i < length; i++) {
          $scope.query.ages[i] = 1;
        }
      }
      function sendReservation() {
        $scope.requestStatus = 'saving';
        var productName = '';
        for (var i = $scope.query.ages.length - 1; i >= 0; i--) {
          request.children.push({ age: $scope.query.ages[i] });
        }
        request.adults = $scope.query.adults;
        if (angular.isArray($scope.products) && $scope.products.length > 0) {
          if ($scope.products[0].parent) {
            productName = $scope.products[0].parent.name + ' ' + $scope.products[0].name;
          }
        }
        request.product = {
          _id: $scope.query.tour,
          name: productName
        };
        request.departure = $scope.query.from;
        // $log.debug("request", $scope.request);
        //return;
        $http.post('/travel-product-requests', $scope.request).success(requestSaved).error(requestSaveFailed);
      }
      angular.extend($scope, {
        childCountChanged: childCountChanged,
        setChildren: setChildren,
        addchildage: addchildage,
        nextMonth: nextMonth,
        previousMonth: previousMonth,
        showProducts: showProducts,
        selectProduct: selectProduct,
        showRules: showRules,
        optionSelected: optionSelected,
        quantityChanged: quantityChanged,
        book: book,
        adultCountChanged: adultCountChanged,
        roomTypeChanged: roomTypeChanged,
        getQuote: '',
        sendFormStatus: sendFormStatus,
        productButtonSelected: false,
        checkDisabledConditions: checkDisabledConditions,
        sendReservation: sendReservation,
        request: request,
        depDate: null,
        nbrOfAdults: [1],
        clearRates: clearRates,
        initChildAges: initChildAges,
        scrollTo: scrollTo,
        generatePDF: generatePDF,
        loadingProgram: false,
        date: null,
        generatePdfTarifs: generatePdfTarifs,
        loadingTarif: false,
        devisOn: false,
        arivDate: null,
        pdfImage: null,
        options: options,
        query: buildQuery(),
        showMoreDaysProgram: showMoreDaysProgram
      });
      // $log.debug("query", $scope.query);
      queryRates($scope.query);
      //****** pdwith kendo
      $scope.currentDate = new Date();
      var someDate = new Date();
      var numberOfDaysToAdd = 6;
      someDate.setDate(someDate.getDate() + numberOfDaysToAdd);
      function generatePDF() {
        //generatePdfOnit
        //console.log("generate program as pdf");
        $scope.loadingProgram = true;
        kendo.pdf.defineFont({
          'DejaVu Sans': 'https://kendo.cdn.telerik.com/2016.1.112/styles/fonts/DejaVu/DejaVuSans.ttf',
          'DejaVu Sans|Bold': 'https://kendo.cdn.telerik.com/2016.1.112/styles/fonts/DejaVu/DejaVuSans-Bold.ttf',
          'DejaVu Sans|Bold|Italic': 'https://kendo.cdn.telerik.com/2016.1.112/styles/fonts/DejaVu/DejaVuSans-Oblique.ttf',
          'DejaVu Sans|Italic': 'https://kendo.cdn.telerik.com/2016.1.112/styles/fonts/DejaVu/DejaVuSans-Oblique.ttf'
        });
        // $timeout(function() {
        kendo.drawing.drawDOM('#program', {
          template: $('#page-template').html(),
          paperSize: 'A4',
          margin: '1cm',
          scale: 0.6,
          forcePageBreak: '.page-break',
          multiPage: true
        }).then(function (group) {
          //console.log(" ending generating group", group);
          kendoGroupe = group;
          var date = $filter('date')($scope.currentDate, 'yyyy-MM-dd');
          //console.log(" begin  saving pdf", kendoGroupe);
          kendo.drawing.pdf.saveAs(kendoGroupe, 'programme ' + $scope.tour.name + '-' + date + '.pdf');
          $scope.loadingProgram = false;
          $scope.$apply();
        });  //}, 100);
      }
      function generatePDF2() {
        var date = $filter('date')($scope.currentDate, 'yyyy-MM-dd');
        //console.log(" begin  saving pdf", kendoGroupe);
        kendo.drawing.pdf.saveAs(kendoGroupe, 'programme ' + $scope.tour.name + '-' + date + '.pdf');  //console.log("end saving pdf");
      }
      //******** generate tarifs pdf ******//
      function generatePdfTarifs() {
        var date = $filter('date')($scope.currentDate, 'yyyy-MM-dd');
        $scope.loadingTarif = true;
        kendo.pdf.defineFont({
          'DejaVu Sans': 'https://kendo.cdn.telerik.com/2016.1.112/styles/fonts/DejaVu/DejaVuSans.ttf',
          'DejaVu Sans|Bold': 'https://kendo.cdn.telerik.com/2016.1.112/styles/fonts/DejaVu/DejaVuSans-Bold.ttf',
          'DejaVu Sans|Bold|Italic': 'https://kendo.cdn.telerik.com/2016.1.112/styles/fonts/DejaVu/DejaVuSans-Oblique.ttf',
          'DejaVu Sans|Italic': 'https://kendo.cdn.telerik.com/2016.1.112/styles/fonts/DejaVu/DejaVuSans-Oblique.ttf'
        });
        //console.log("in generate tarifs as pdf");
        $timeout(function () {
          kendo.drawing.drawDOM('#tarifs', {
            paperSize: 'A4',
            margin: '1cm',
            scale: 0.7
          }).then(function (group) {
            kendo.drawing.pdf.saveAs(group, 'devis ' + $scope.tour.name + '-' + date + '.pdf');
            $scope.loadingTarif = false;
            $scope.$apply();
          });
        }, 10);
      }
    }
  ]);
  /*if ($scope.query.type.toLowerCase() === 'quadruple') {

                	selection.unshift({
					code: category.category.code,
					name: category.category.name,
					rate: rate,
					hasQuadruple :false //category.category.quadruple
				});

              }else{

                	selection.unshift({
					code: category.category.code,
					name: category.category.name,
					rate: rate,
					hasQuadruple :true


				});


      };*/
  // $http.get(url + "?qt=byTour&tour=" + $stateParams.tour + "&lang=" + $stateParams.lang, _options).success(function (data) {
  // 	angular.extend(tour, {
  // 		description: data[0]
  // 	});
  // });
  // Get "tour" :
  // TODO there must be only one call to get full tour (data sheet+ description)
  // api should serve those two MERGED.
  // $http.get(settings.tours.endpoint + "/" + $stateParams.tour, _options).success(function (data) {
  // 	$scope.pdfImage = data.photos[0].url.replace("http", "https");
  // 	data.photos.forEach(function (p) {
  // 		//settings.tour.imgrsz
  // 		p.url = "https://imgrsz.atlasvoyages.com/img/750x450/" + p.url;
  // 		//p.url = p.url.replace("http", "https");
  // 		//p.url = p.url.replace("https://imgrsz.atlasvoyages.com/img/750x450/http", "https");
  // 	});
  // 	var facebookMeta = {
  // 		title: data.name,
  // 		description: data.description.lead,
  // 		image: data.photos[0].url,
  // 		url: "https://www.atlasvoyages.com/ngapps/vo-sales#/tour/" + $stateParams.tour + "?from=" + $stateParams.from + "&to=" + $stateParams.to + "&lang=fr"
  // 	};
  // 	data.facebookMeta = facebookMeta;
  // 	angular.extend(tour, data);
  // 	$log.debug('emit tourProducthQuery', JSON.stringify($scope.tour.name));
  // 	$scope.$emit('tourProducthQuery', $scope.tour.name);
  // 	$scope.context = 'product';
  // });
  angular.module('tours').directive('mySelect', [
    '$window',
    function ($window) {
      function main(scope, element, attrs) {
        // console.log('mySelect directive', scope.ops, scope.selection);
        // Selecting model value
        for (var idx in scope.ops) {
          if (scope.ops[idx].value == scope.selection) {
            scope.selectedOpt = scope.ops[idx];
          }
        }
        // Is a mobile device
        var isMobile = false;
        if (/ipad|iphone|android/gi.test($window.navigator.userAgent)) {
          isMobile = true;
        }
        // Select an option
        scope.selectOpt = function (opt) {
          scope.selection = opt.value;
          //scope.selectedOpt = opt;
          optionsDom.removeClass('active');
          backdrop.removeClass('active');
        };
        scope.$watch('selection', function (newVal) {
          for (var idx in scope.ops) {
            if (typeof newVal == 'object' && JSON.stringify(newVal) == JSON.stringify(scope.ops[idx].value)) {
              scope.selectedOpt = scope.ops[idx];
            } else if (scope.ops[idx].value == newVal) {
              scope.selectedOpt = scope.ops[idx];
            }
          }
        });
        // DOM References
        var labelDom = element.find('.my-select-label');
        var optionsDom = element.find('.my-select-ops');
        var backdrop = element.find('.my-select-backdrop');
        var mobileSelect = element.find('select');
        // DOM Event Listeners
        labelDom.on('click', function (e) {
          rePositionOps();
          optionsDom.toggleClass('active');
          backdrop.toggleClass('active');
        });
        backdrop.on('click', function (e) {
          optionsDom.removeClass('active');
          backdrop.removeClass('active');
        });
        element.on('keydown', function (ev) {
          switch (ev.which) {
          case 37:
          // left arrow
          case 38:
            // top arrow
            preSelectPrev();
            break;
          case 39:
          // right arrow
          case 40:
            // down arrow
            preSelectNext();
            break;
          case 13:
            // enter key
            preSelectPush();
          }
        });
        // Initialization
        rePositionOps();
        $($window).on('resize', function () {
          rePositionOps();
        });
        if (isMobile) {
          mobileSelect.addClass('active');
        }
        // Positioning options
        function rePositionOps() {
          optionsDom.width(labelDom.width());
          optionsDom.css({});
          // Mobile ops
          mobileSelect.width(labelDom.outerWidth());
          mobileSelect.height(labelDom.outerHeight());
          mobileSelect.css({});  // console.log("rePositionOps", optionsDom); 
        }
        // PreSelection logic:
        //  This controls option selecting and highlighting by pressing the arrow
        //  keys.
        var preSelected = 0;
        function updatePreSelection() {
          optionsDom.children().filter('.preselected').removeClass('preselected');
          optionsDom.find('div').eq(preSelected).addClass('preselected');  // console.log(preSelected);
        }
        updatePreSelection();
        function preSelectNext() {
          // console.log(scope.ops.length);
          preSelected = (preSelected + 1) % scope.ops.length;
          updatePreSelection();
        }
        function preSelectPrev() {
          // console.log(scope.ops.length);
          preSelected = (preSelected - 1) % scope.ops.length;
          updatePreSelection();
        }
        function preSelectPush() {
          scope.selectOpt(scope.ops[preSelected]);
          scope.$apply();
        }
      }
      return {
        link: main,
        scope: {
          ops: '=mySelect',
          selection: '=selection'
        },
        template: '<div class="my-select-label" tabindex="0" title="{{selectedOpt.label}}"><span class="my-select-label-text">{{selectedOpt.label}}</span><span class="my-select-caret"><svg viewBox="0 0 100 60"><polyline points="10,10 50,50 90,10" style="fill:none;stroke:#c30800;stroke-width:8;stroke-linecap:round;"/></svg></span></div><div class="my-select-backdrop"></div><div class="my-select-ops"><div ng-repeat="o in ops" ng-click="selectOpt(o)">{{o.label}}</div></div><select ng-options="opt.value as opt.label for opt in ops" ng-model="selection"></select>'
      };
    }
  ]);
  // Source: src/html/scripts/tour-sales/services/tour-quote.js
  angular.module('tours').factory('tourQuoteService', function () {
    function addExtras(rawProduct, quote) {
      var extras = rawProduct.rate.supplements;
      var items = quote.items, charge;
      angular.forEach(extras, function (extra, index) {
        charge = extra.charge.slice(1);
        // TODO charge returned by tour is [UNIT,VALUE]
        // but should be [VALUE,UNIT]
        //charge.push(charge.shift());
        if (extra.charge[0] === '-') {
          charge[0] = -charge[0];
        }
        var day = '';
        if (extra.code != undefined && extra.code.indexOf('#') > -1) {
          var arrayOfStrings = extra.code.split('#');
          day = ' on ' + moment(quote.trip.content.checkin).add(parseInt(arrayOfStrings[1]) - 1, 'days').format('YYYY-MM-DD');
        }
        items.push({
          $type: 'tourExtra',
          '@type': 'tourExtra',
          product: {
            code: extra.code || rawProduct.code + ':opt:' + index,
            name: rawProduct.name + ' - ' + extra.name + day,
            type: extra.type,
            price: charge[0]
          },
          qty: 0,
          totals: { total: 0 }
        });
      });
    }
    function createItem(type, product, travellers, parent) {
      travellers = travellers || [];
      // if(product.name.indexOf(":") <= -1)
      //  product.name =  name+": "+product.name;
      product.parent = {
        'name': parent.name,
        'type': parent.type
      };
      // console.log("parent ",parent);
      //product.translationDate = parent.translationDate;
      //var product.rate.departure
      var arrivalDates = [];
      var departures = [];
      if (parent.translationDate == undefined || parent.translationDate == 0) {
        var d = moment(product.rate.departure);
        arrivalDates.push(d.format('YYYY-MM-DD'));
        departures.push(d.add(parent.days.length, 'days').format('YYYY-MM-DD'));
      } else
        // support departure date translation  , parent.translationDate>0
        {
          for (var i = 0; i <= parent.translationDate; i++) {
            var d = moment(product.rate.departure).add(parseInt(i), 'days');
            arrivalDates.push(d.format('YYYY-MM-DD'));
            //2014-12-25
            departures.push(d.add(parent.days.length - 1, 'days').format('YYYY-MM-DD'));  //2014-12-25
          }
          ;
        }
      product.departuresDates = departures;
      product.arrivalDates = arrivalDates;
      var adnbr = 0;
      for (var i = travellers.length - 1; i >= 0; i--) {
        if (travellers[i].classification === 'ADULT')
          adnbr++;
      }
      return {
        $type: type,
        '@type': type,
        product: product,
        travellers: travellers,
        qty: adnbr,
        totals: { total: product.price * adnbr }
      };
    }
    function quote(tour, rawProduct, query) {
      var quote = {
          trip: {},
          items: [],
          totals: { total: 0 }
        };
      var travellers = [];
      var adults = [];
      var children = [], child, adult;
      quote.trip.travellers = [];
      // console.log("quote tour ",tour);
      var adnbr = 1;
      var chnbr = 1;
      while (travellers.length < query.adults) {
        adult = {
          'classification': 'ADULT',
          'id': adnbr++,
          'type': 'Traveller'
        };
        travellers.push(adult);
        adults.push(adult);
      }
      // console.log("quote ages ", query.ages, rawProduct.rate.childs);
      while (children.length < query.ages.length) {
        var rules = rawProduct.rate.childs;
        var isch = false;
        var i = 0;
        while (i < rules.length) {
          if (query.ages[children.length] <= rules[i].to) {
            isch = true;
          }
          i++;
        }
        if (isch) {
          child = {
            'classification': 'CHILD',
            'id': adnbr + chnbr++,
            'type': 'Traveller',
            age: query.ages[children.length]
          };
          children.push(child);
          travellers.push(child);
        } else {
          adult = {
            'classification': 'ADULT',
            'id': adnbr++,
            'type': 'Traveller',
            age: query.ages[children.length]
          };
          travellers.push(adult);
          adults.push(adult);
        }  // using children.length as index since it's growing
      }
      // console.log("quote children ", children, travellers);
      if (rawProduct.rate.promo) {
        //rawProduct.rate.priceYield = rawProduct.rate.promo.value;
        rawProduct.promo = rawProduct.rate.promo.name;
        rawProduct.rate.tripleReduction[0] = rawProduct.rate.promo.triple;
      }
      rawProduct.price = rawProduct.rate.priceYield;
      rawProduct.code = tour.code + ':' + rawProduct.code + ':' + rawProduct.rate.code + ':' + query.lang;
      // rawProduct.code = rawProduct.code
      /////////// will be deleted when doubleWith child will be removed from old booking processs //////////
      if (query.doubleWithChild > 0)
        quote.items.push(createItem(tour.type, rawProduct, adults, tour));
      else
        quote.items.push(createItem(tour.type, rawProduct, travellers, tour));
      /////////////////////////////////////////////////////////////////////////////////////////////////////
      quote.trip.content = {};
      quote.currency = query.currency;
      quote.trip.content.checkin = rawProduct.rate.departure;
      quoteChildren(rawProduct, children, quote.items, tour);
      // console.log('tour.typetour.typetour.type', tour.type, query.single, query.triple);
      if (tour.type === 'Tour' || tour.type === 'VO' || tour.type === 'OMRA') {
        // console.log('tourQuoteService', query);
        if (query.single != 0) {
          quote.items.push({
            $type: 'tourExtra',
            '@type': 'tourExtra',
            product: {
              code: rawProduct.code + ':opt:supp',
              name: 'Single Supplements',
              price: rawProduct.rate.supplmtSingleYield
            },
            qty: query.single,
            totals: { total: query.single * rawProduct.rate.supplmtSingleYield }
          });
        }
        if (query.triple != 0) {
          var qte = 3;
          if (tour.type === 'OMRA')
            qte = query.adults;
          quote.items.push({
            $type: 'tourExtra',
            '@type': 'tourExtra',
            product: {
              code: rawProduct.code + ':opt:supp',
              name: 'Triple Discount',
              price: rawProduct.rate.tripleReduction[1] === '%' ? -1 * rawProduct.rate.priceYield * rawProduct.rate.tripleReduction[0] / 100 : rawProduct.rate.tripleReduction[0] - rawProduct.rate.priceYield
            },
            qty: rawProduct.rate.tripleReduction[1] === '%' ? query.triple : qte * query.triple,
            totals: { total: rawProduct.rate.tripleReduction[1] === '%' ? query.triple * -1 * rawProduct.rate.priceYield * rawProduct.rate.tripleReduction[0] / 100 : qte * query.triple * (rawProduct.rate.tripleReduction[0] - rawProduct.rate.priceYield) }
          });
        }
        ;
        if (query.quadruple != 0) {
          var qte = 4;
          if (tour.type === 'OMRA')
            qte = query.adults;
          quote.items.push({
            $type: 'tourExtra',
            '@type': 'tourExtra',
            product: {
              code: rawProduct.code + ':opt:supp',
              name: 'Quadruple Discount',
              price: rawProduct.rate.quadruple - rawProduct.rate.priceYield
            },
            qty: qte * query.quadruple,
            totals: { total: qte * query.quadruple * (rawProduct.rate.quadruple - rawProduct.rate.priceYield) }
          });
        }
        ;
      }
      ;
      // calculate total
      quote.totals.total = quote.items.reduce(function (total, item) {
        return total + item.totals.total;
      }, 0);
      quote.trip.travellers = travellers;
      addExtras(rawProduct, quote);
      return quote;
    }
    function quoteChildren(product, children, items, tour) {
      var standardPrice = product.rate.price, rules = product.rate.childs, len = rules.length, childItemsMap = {};
      // console.log("quoteChildren ", children);
      children.forEach(function (child) {
        var i = 0;
        while (i < len) {
          if (child.age < rules[i].to) {
            // TODO .to should be called .under
            // console.log('creating rule ', child, rules[i], childItemsMap, product);
            return _addChildToItems(child, rules[i], childItemsMap, product, tour);
          }
          i++;
        }
      });
      //      console.log("childItemsMap", childItemsMap);
      // Now that we have aggregated children into items
      // do a 'list.addAll(map.values)'
      for (var k in childItemsMap) {
        items.push(childItemsMap[k]);
      }
    }
    function _addChildToItems(child, rule, childItemsMap, _product, tour) {
      var key = 'child' + rule.to;
      var item = childItemsMap[key];
      var product;
      if (!item) {
        product = {
          code: _product.code + ':chd' + rule.to,
          name: _product.name + ' - child under ' + rule.to + ' years',
          price: calculateCharge(rule.charge, _product.rate.priceYield),
          rate: _product.rate
        };
        item = childItemsMap[key] = createItem(tour.type, product, undefined, tour);
      }
      item.travellers.push(child);
      item.qty += 1;
      item.totals.total += item.product.price;
      return item;
    }
    /**
         * given charge [value,unit] and basePrice
         * returns the relative charge if unit is % or flat charge if unit
         * is currency
         */
    function calculateCharge(charge, basePrice) {
      if (charge[1] === '%') {
        return charge[0] * basePrice / 100;
      } else {
        return charge[0];
      }
    }
    return { quote: quote };
  });
}());