(function () {
  'use strict';
  // Source: src/html/scripts/checkout/index.js
  /**
 * @ngdoc overview
 * @name checkout
 * Checkout module
 */
  angular.module('checkout', [
    'ui.bootstrap',
    'ui.router',
    'oc.lazyLoad'
  ]).config([
    'datepickerConfig',
    'datepickerPopupConfig',
    function (datepickerConfig, datepickerPopupConfig) {
      datepickerConfig.showWeeks = false;
      datepickerConfig.dayFormat = 'd';
      datepickerConfig.startingDay = 1;
      datepickerConfig.datepickerMode = 'year';
      datepickerPopupConfig.toggleWeeksText = null;
      datepickerPopupConfig.showButtonBar = false;  //datepickerConfig.da
    }
  ]).config([
    '$sceProvider',
    '$stateProvider',
    '$urlRouterProvider',
    '$httpProvider',
    function ($sceProvider, $stateProvider, $urlRouterProvider, $httpProvider) {
      function resolveCart($http, $stateParams) {
        return $http.get('/carts/' + $stateParams.cart).then(function (res) {
          return res.data;
        }, function () {
          return null;
        });
      }
      function loadDependencies(deps, $ocLazyLoad) {
        var flattened = [];
        angular.forEach(deps, function (val, key) {
          flattened.push({
            name: key,
            files: val
          });
        });
        return $ocLazyLoad.load(flattened);
      }
      function sortPanes(a, b) {
        return a.weight - b.weight;
      }
      $stateProvider.state('checkout', {
        url: '/:cart',
        templateUrl: 'checkout-form',
        controller: 'CheckoutCtrl',
        resolve: {
          countries: [
            '$http',
            function ($http) {
              return $http.get('https://s3-eu-west-1.amazonaws.com/jsdn/countries_fr.json').then(function (res) {
                var countries = [];
                for (var code in res.data) {
                  countries.push({
                    code: code,
                    name: res.data[code]
                  });
                }
                return countries;
              });
            }
          ],
          cart: [
            '$http',
            '$stateParams',
            function ($http, $stateParams) {
              return resolveCart($http, $stateParams);
            }
          ],
          paymentMethods: [
            '$http',
            '$stateParams',
            function ($http, $stateParams) {
              return $http.get('/payment-methods?cart=' + $stateParams.cart).then(function (res) {
                return res.data;
              }, function () {
                return [];
              });
            }
          ],
          panes: [
            '$http',
            '$stateParams',
            '$ocLazyLoad',
            function ($http, $stateParams, $ocLazyLoad) {
              return $http.get('/checkout-panes?cart=' + $stateParams.cart).then(function (res) {
                var pane, result = {
                    summary: [],
                    form: []
                  };
                var deps = {};
                for (var i = 0; i < res.data.length; i++) {
                  pane = res.data[i];
                  //result[pane.type][pane.id] = pane;
                  result[pane.type].push(pane);
                  if (pane.dependencies) {
                    angular.extend(deps, pane.dependencies);
                  }
                  if (pane.templates) {
                    for (var id in pane.templates) {
                      $templateCache.put(id, pane.templates[id]);
                    }
                  }
                }
                // sort stuff by weight
                result.summary.sort(sortPanes);
                result.form.sort(sortPanes);
                return loadDependencies(deps, $ocLazyLoad).then(function () {
                  return result;
                }, function (error) {
                  throw new Error('Could not load panes dependencies.' + error);
                });
              }, function () {
                return [];
              });
            }
          ]
        }
      }).state('processing', {
        url: '/:cart/processing',
        templateUrl: 'checkout-processing',
        controller: 'ProcessingCtrl'
      }).state('complete', {
        url: '/:cart/complete',
        templateUrl: 'checkout-complete',
        controller: 'CheckoutCompleteCtrl',
        resolve: {
          cart: [
            '$http',
            '$stateParams',
            function ($http, $stateParams) {
              return resolveCart($http, $stateParams);
            }
          ],
          panes: [
            '$http',
            '$stateParams',
            '$ocLazyLoad',
            function ($http, $stateParams, $ocLazyLoad) {
              return $http.get('/checkout-panes?cart=' + $stateParams.cart).then(function (res) {
                var pane, result = { summary: [] };
                var deps = {};
                for (var i = res.data.length - 1; i >= 0; i--) {
                  pane = res.data[i];
                  if (pane.type !== 'summary') {
                    continue;
                  }
                  pane = res.data[i];
                  //result[pane.type][pane.id] = pane;
                  result.summary.push(pane);
                  if (pane.dependencies) {
                    angular.extend(deps, pane.dependencies);
                  }
                  if (pane.templates) {
                    for (var id in pane.templates) {
                      $templateCache.put(id, pane.templates[id]);
                    }
                  }
                }
                // sort stuff by weight
                result.summary.sort(sortPanes);
                return loadDependencies(deps, $ocLazyLoad).then(function () {
                  return result;
                }, function (error) {
                  throw new Error('Could not load panes dependencies.' + error);
                });
              }, function () {
                return [];
              });
            }
          ]
        }
      }).state('error', {
        url: '/:cart/error',
        templateUrl: 'checkout-error',
        controller: 'CheckoutErrorCtrl',
        resolve: {
          cart: [
            '$http',
            '$stateParams',
            function ($http, $stateParams) {
              return resolveCart($http, $stateParams);
            }
          ]
        }
      });
      // otherwise 404
      $urlRouterProvider.otherwise('/');
      $httpProvider.defaults.headers.common.Accept = 'application/json';
    }
  ]);
  // Source: src/html/scripts/checkout/analytics.js
  angular.module('checkout').run([
    '$rootScope',
    '$injector',
    '$log',
    function ($rootScope, $injector, $log) {
      if (!window.ga) {
        $log.debug('no ga');
        return;
      }
      var $analytics;
      try {
        $analytics = $injector.get('$analytics');
      } catch (e) {
        // Error: [$injector:unpr]
        // just returned, analytics is not loaded
        $log.warn('$analytics not available');
        return;
      }
      var ga = window.ga;
      /*
              $rootScope.$on('cartLoaded', function (cart) {
                $log.info('checkout start');

                angular.forEach(cart.items , function(item) {
                  ga('ec:addProduct', itemToGa(item));
                });

                ga('ec:setAction', 'checkout', {'step': 1});

                //ga('send', 'event');
                ga('send', 'pageview');

              });

              $rootScope.$on('checkoutPayment', function (cart, payment) {
                $log.info('checkout payment');
                angular.forEach(cart.items , function(item) {
                  ga('ec:addProduct', itemToGa(item));
                });

                ga('ec:setAction', 'checkout', {'step': 2});

                //ga('send', 'event');
                ga('send', 'pageview');


                //$analytics.pageTrack('/checkout/payment');
            });*/
      // may be move this to checkout complete
      // ga will can handle duplicates with transaction id ?
      $rootScope.$on('checkoutComplete', function ($event, cart) {
        $log.info('checkout complete', cart);
        angular.forEach(cart.items, function (item) {
          ga('ec:addProduct', itemToGa(item));
        });
        ga('ec:setAction', 'purchase', {
          id: cart.orderNumber || cart._id,
          revenue: cart.totals.total
        });
        //ga('send', 'event');
        ga('send', 'pageview', '/checkout/complete');
      });
      $rootScope.$on('checkoutUpdateCartSuccess', function ($event, cart) {
        $log.info('checkout update cart:', cart);
        var path = '/checkout/', type = cart.items[0]['@type'] ? cart.items[0]['@type'].toLowerCase() : 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;
        }
        $analytics.pageTrack(path);
      });
      $rootScope.$on('checkoutError', function ($event, cart) {
        $log.info('checkout error');
        //cartId = ($event.cart && $event.cart._id) || 'NC';
        $analytics.eventTrack('checkoutError', { category: 'checkout' });
      });
      $rootScope.$on('cartExpired', function ($event, cart) {
        $log.info('cart expired');
        $analytics.eventTrack('cartExpired', { category: 'checkout' });
      });
      function itemToGa(item) {
        return {
          id: item.type || item['@type'],
          category: item.type || item['@type'],
          name: item.type || item['@type'],
          quantity: 1,
          price: item.totals.total
        };
      }
    }
  ]);
  // Source: src/html/scripts/checkout/controllers/checkout.js
  angular.module('checkout').controller('CheckoutCtrl', [
    '$scope',
    '$window',
    '$rootScope',
    '$http',
    '$timeout',
    '$log',
    '$modal',
    'settings',
    'cart',
    '$state',
    '$q',
    'paymentMethods',
    'panes',
    'countries',
    function CheckoutCtrl($scope, $window, $rootScope, $http, $timeout, $log, $modal, settings, cart, $state, $q, paymentMethods, panes, countries) {
      var cartExpires;
      //$log.debug('panes', panes);
      function init() {
        if (cart === null) {
          $window.location.href = '/404';
          return false;
        } else if (cart.status === 'complete') {
          $state.go('complete', { cart: cart._id });
        } else if (cart.status === 'errored') {
          $state.go('error', { cart: cart._id });
        } else {
          // timeout on cart expiry so as not to have problems later
          if (cart.expires) {
            $log.debug('cart expires ' + cart.expires);
            var expires = moment(cart.expires).diff(moment());
            cartExpires = $timeout(expireCart, expires);
          }
          //    orders.get().then(init);
          angular.extend($scope, {
            operations: {},
            order: cart,
            paymentMethods: paymentMethods,
            settings: settings,
            saveOption: saveOption,
            toPayment: toPayment,
            toggleCalendar: toggleCalendar,
            calendars: {},
            options: {
              greetings: [
                'Mr',
                'Mme'
              ],
              countries: countries
            },
            panes: panes
          });
          $rootScope.$emit('cartLoaded', cart);
          $scope.$on('$destroy', destroy);
        }
      }
      function destroy() {
        if (cartExpires) {
          cartExpires.clear();  //clear(cartExpires);
        }
      }
      function toggleCalendar($event, cal) {
        $event.preventDefault();
        $event.stopPropagation();
        var oldvalue = $scope.calendars[cal];
        $scope.calendars = {};
        $scope.calendars[cal] = !oldvalue;
      }
      function expireCart() {
        $rootScope.$emit('cartExpired', cart);
        $state.go('error', {
          cart: cart.number,
          error: 'expired'
        });
      }
      function toPayment(paymentMethod) {
        paymentMethod.disabled = true;
        $scope.paymentMethod = paymentMethod;
        if ($scope.checkoutForm && $scope.checkoutForm.$invalid) {
          $log.error('Cannot update order since form is invalid.');
          return false;
        }
        cart.status = 'checkout';
        saveCart().then(continueToPayment, cartNotSaved);
      }
      function saveOption() {
        // enure status == checkout
        cart.status = 'checkout';
        saveCart().then(function (c) {
          $scope.cart = c;
          var opts = {
              templateUrl: 'cart-save-message',
              scope: $scope,
              backdrop: 'static',
              controller: 'SavedMessageCtrl'
            };
          var message = $modal.open(opts);  /*
                                message.result.then(function () {
                                    if (paymentSuccessfull(payment)) {

                                        $scope.$emit('checkoutComplete', cart);
                                        $state.go('complete', {
                                            cart: $scope.cart._id
                                        });
                                    }
                                });
                                */
        }, cartNotSaved);
      }
      /**
		 *
		 *
		 */
      function customTypes(cart) {
        // lodge n'a pas @type ==> laisser le traitement comme avant
        if (cart.items[0]['@type']) {
          return cart.items.filter(function (item) {
            item['@type'].toLowerCase() === 'customtopay';
          });
        } else
          return [];
      }
      function saveCart() {
        var def = $q.defer();
        var cstmTypes = customTypes(cart);
        //if for is pristine && valid(has already been saved)
        if (cart.orderNumber || $scope.checkoutForm && $scope.checkoutForm.$pristine && cstmTypes.length == 0) {
          def.resolve(cart);
          return def.promise;
        }
        $scope.operations.cartSaving = true;
        $http.put('/carts/' + cart._id, cart).success(function (body) {
          console.log('cart saved success', body);
          body._id = body._id || cart._id;
          angular.extend(cart, body);
          if (body.status === 'errored') {
            var e = new Error('Cart saved but has issues');
            e.cart = body;
            def.reject(e);
          } else {
            if ($scope.checkoutForm) {
              $scope.checkoutForm.$setPristine();
            }
            $rootScope.$broadcast('cart saved', body);
            //if(cart.status && ['', 'filled'].indexOf(cart.status.toLowerCase() > -1)) {
            $scope.$emit('checkoutUpdateCartSuccess', cart);
            //}
            def.resolve(body);
          }
          $scope.operations.cartSaving = false;
        }).error(function (status) {
          console.log('error while updating cart', status);
          var e = new Error('Could not update cart. Server response ' + status);
          $log.error(e, arguments);
          e.cart = cart;
          def.reject(e);
          $scope.operations.cartSaving = false;
        });
        return def.promise;
      }
      function cartNotSaved(error) {
        $rootScope.$emit('checkoutError', error);
        // may be we should use "inconsistent". errored sounds weird...
        if (error.cart && error.cart.status === 'errored') {
          $state.go('error', { cart: cart._id });
        }
      }
      function continueToPayment(cart) {
        // should mark cart as saved
        // so we don't have to recreate it if user does not change data
        $scope.cart = cart;
        var opts = {
            templateUrl: 'payment-popup',
            controller: 'PaymentCtrl',
            size: 'lg',
            windowClass: 'payment-popup',
            scope: $scope,
            backdrop: 'static'
          };
        var paymentModal = $modal.open(opts);
        paymentModal.result.then(function (payment) {
          if (paymentSuccessfull(payment)) {
            $scope.$emit('checkoutComplete', cart);
            $state.go('complete', { cart: $scope.cart._id });
          }
        }, function (error) {
          $scope.$emit('checkoutError', error);
        });
      }
      function paymentSuccessfull(payment) {
        return [
          'authorized',
          'received',
          'processed',
          'cleared'
        ].indexOf(payment.status > -1);
      }
      init();
    }
  ]);
  // Source: src/html/scripts/checkout/controllers/complete.js
  angular.module('checkout').controller('CheckoutCompleteCtrl', [
    '$scope',
    'cart',
    'panes',
    '$state',
    '$http',
    '$log',
    'settings',
    '$filter',
    '$timeout',
    'paymentMethods',
    '$window',
    'GoogleTagManager',
    function ($scope, cart, panes, $state, $http, $log, settings, $filter, $timeout, paymentMethods, $window, GoogleTagManager) {
      if (cart === null) {
        window.location.href = '/404';
      }
      if (cart.status === 'errored') {
        return $state.go('error', { cart: cart._id });
      } else if (cart.status === 'processing') {
        return $state.go('processing', { cart: cart._id });
      } else if (cart.status !== 'complete') {
        return $state.go('checkout', { cart: cart._id });
      }
      $scope.cart = cart;
      $scope.order = cart;
      $scope.panes = panes;
      $scope.settings = settings;
      var category = null;
      var lobs = cart.items.map(function (item) {
          // @type is still used but deprecated
          // lobs MUST update to type
          return item['@type'] || item.type;
        }).filter(function (type) {
          return type !== 'fee';
        }).map(function (type) {
          return type.toLowerCase();
        });
      var transactionProducts;
      if (lobs.indexOf('air') > -1) {
        GoogleTagManager.push({ 'event': 'confirmation_vol' });
        transactionProducts = cart.items.map(function (item, i) {
          return {
            'sku': item.number,
            'name': cart.trip.segments[0].departure.location.name + '-' + cart.trip.segments[0].arrival.location.name,
            'category': 'vol',
            'price': item.totals.TOTAL,
            'quantity': item.quantity
          };
        });
      } else if (lobs.indexOf('lodge') > -1) {
        GoogleTagManager.push({ 'event': 'confirmation_hotel' });
        transactionProducts = cart.items.map(function (item, i) {
          return {
            'sku': item.type + '-' + (item.type !== 'fee' ? item.product.code : item.fee ? item.fee.code : null),
            'name': cart.trip.segments[0].property.name + '_' + cart.trip.segments[0].property.address.country + '_' + cart.trip.segments[0].property.address.location,
            'category': 'hotel',
            'price': item.totals.total,
            'quantity': item.quantity
          };
        });
      } else if (lobs.indexOf('vo') > -1 || lobs.indexOf('omra') > -1) {
        GoogleTagManager.push({ 'event': 'confirmation_vo' });
        transactionProducts = cart.items.map(function (item, i) {
          return {
            'sku': item.product.code,
            'name': item.product.name,
            'category': 'hotel',
            'price': item.totals.total,
            'quantity': item.qty
          };
        });
      }
      GoogleTagManager.push({
        'event': 'achats',
        'transactionId': cart.orderNumber || cart._id,
        'transactionAffiliation': 'Atlasvoyages',
        'transactionTotal': cart.totals.total,
        'transactionProducts': transactionProducts
      });
      console.log('dataLayer', $window.dataLayer);
      // payement methode
      function init(payment) {
        console.log(' geting payment : ', payment);
        $scope.paymentOrder = payment[0];
      }
      function methodsQueryFailed() {
        console.log(' failed geting payment');
      }
      paymentMethods.getPaymentByOrder($scope.order).then(init, methodsQueryFailed);
      //******** generate commande pdf ******//
      $scope.currentDate = new Date();
      $scope.loadingCommande = false;
      $scope.generatePdfCommande = function () {
        var date = $filter('date')($scope.currentDate, 'yyyy-MM-dd');
        $scope.loadingCommande = 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 commande as pdf');
        $timeout(function () {
          kendo.drawing.drawDOM('#commande', {
            paperSize: 'A4',
            margin: '1cm',
            scale: 0.7
          }).then(function (group) {
            kendo.drawing.pdf.saveAs(group, 'commande N\xb0 ' + $scope.cart._id + '-' + date + '.pdf');
            $scope.loadingCommande = false;
            $scope.$apply();
          });
        }, 10);
      };
      //******** generate recette pdf ******//
      $scope.loadingRecette = false;
      $scope.generatePdfRecette = function () {
        var date = $filter('date')($scope.currentDate, 'yyyy-MM-dd');
        $scope.loadingRecette = 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 bon de recette as pdf');
        $timeout(function () {
          kendo.drawing.drawDOM('#recette', {
            paperSize: 'A4',
            margin: '1cm',
            scale: 0.7
          }).then(function (group) {
            kendo.drawing.pdf.saveAs(group, 'bon_recette N\xb0 ' + $scope.cart._id + '-' + date + '.pdf');
            $scope.loadingRecette = false;
            $scope.$apply();
          });
        }, 10);
      }  // if $scope.order not complete redirect to /
;
    }
  ]);
  // Source: src/html/scripts/checkout/controllers/error.js
  angular.module('checkout').controller('CheckoutErrorCtrl', [
    '$scope',
    'cart',
    '$http',
    '$log',
    'settings',
    function CheckoutCtrl($scope, cart, $http, $log, settings) {
      if (cart === null || cart.status !== 'errored') {
        window.location.href = '/404';
      }
      $scope.cart = cart;
      $scope.settings = settings;
    }
  ]);
  // Source: src/html/scripts/checkout/controllers/payment.js
  angular.module('checkout').controller('PaymentCtrl', [
    '$scope',
    '$window',
    '$timeout',
    '$log',
    '$sce',
    '$q',
    '$http',
    '$ocLazyLoad',
    '$modalInstance',
    '$rootScope',
    function PaymentCtrl($scope, $window, $timeout, $log, $sce, $q, $http, $ocLazyLoad, $modalInstance, $rootScope) {
      $scope.statuses = {
        IDLE: 0,
        LOADING: 10,
        SUBMITING_PAYMENT: 11,
        PAYMENT_ERROR: 30
      };
      var confirmAction = {
          label: 'Confirmer',
          run: submitPayment,
          primary: true,
          busy: false
        };
      /**
		 * creates a payment object with data from cart.
		 * - if the payment method requires a redirect
		 *   it saves payment to let the  method add
		 *   redirect info on the server side
		 * - if method defines a form for additional payment info
		 *   loads any dependencies then sets template path in scope
		 *   so it can be loaded in view (and filled by user)
		 * - otherwise, the method is supposed to be a direct payment method
		 *   therefore POST payment as is.
		 *
		 */
      function init() {
        var method = $scope.paymentMethod;
        var payment = createPayment($scope.cart, method);
        console.log('payemettttt', payment, method);
        $scope.payment = payment;
        $scope.status = 'processing';
        if (method.redirect) {
          // payment redirect need saving payment first
          savePayment(payment).then(paymentRedirect, displayServerError);
        } else if (method.form) {
          if (method.form.dependencies) {
            $ocLazyLoad.load(method.form.dependencies).then(setupPaymentForm, displayServerError);
          } else {
            setupPaymentForm();
          }
        } else {
          submitPayment();
        }
      }
      function customTypes(cart) {
        // lodge n'a pas @type ==> laisser le traitement comme avant
        if (cart.items[0]['@type']) {
          return cart.items.filter(function (item) {
            return item['@type'].toLowerCase() == 'vo' || item['@type'].toLowerCase() == 'customtopay';
          });
        } else
          return [];
      }
      function createPayment(cart, method) {
        return {
          status: 'intended',
          method: method.code,
          order: cart._id || cart.number,
          total: customTypes(cart).length > 0 && $scope.cart.totals.toPay ? $scope.cart.totals.toPay : $scope.cart.totals.total
        };
      }
      function setupPaymentForm() {
        $scope.formTemplate = $scope.paymentMethod.form.template;
        $scope.submitPayment = submitPayment;
        $scope.actions = [
          confirmAction,
          {
            label: 'Fermer',
            run: cancel
          }
        ];
        $scope.status = 'idle';
      }
      function savePayment(payment) {
        var def = $q.defer();
        confirmAction.busy = true;
        $scope.status = 'saving';
        $http.post('/payments', payment).success(function (body) {
          console.log('save payment success ...');
          $scope.$broadcast('payment created', body);
          def.resolve(body);
          confirmAction.busy = false;
          $scope.status = 'idle';
        }).error(function () {
          var e = new Error('Could not create payment. Server response ' + status);
          console.error(e, arguments);
          def.reject(arguments[1]);
          confirmAction.busy = false;
          $scope.status = 'error';
        });
        return def.promise;
      }
      function submitPayment() {
        savePayment($scope.payment).then(paymentDone, displayServerError);
      }
      /**
		 * closes modal returning payment object to parent
		 */
      function paymentDone(payment) {
        console.log('paymentDone', payment);
        if (payment.status === 'rejected') {
          $scope.status = 'error';
          // rejection has message
          $scope.error = payment.error;
          $scope.actions = [{
              label: 'Fermer',
              run: cancel
            }];
        } else {
          $scope.status = 'processing';
          $modalInstance.close(payment);
        }  // close
      }
      function cancel() {
        $modalInstance.dismiss('cancel');
      }
      function paymentRedirect(payment) {
        if (!payment.redirect) {
          throw new Error('Cannot process payment redirect. Payment has no redirect info.');
        }
        var info = payment.redirect;
        var removeRedirectDoneListener = $scope.$on('paymentRedirectDone', function (p) {
            removeRedirectDoneListener();
            paymentDone(p);
          });
        if (info.method === 'GET' && payment.method.toLowerCase() === 'payzone') {
          $window.location.href = info.url;
          return;
        }
        // security hole ? If the server side gets hacked... Not otherwise :P ?
        info.url = $sce.trustAsResourceUrl(info.url);
        if (info.type === 'html') {
          info.data = $sce.trustAsHtml(info.data);
        }
        $scope.paymentRedirect = info;
        $scope.status = 'idle';
        $rootScope.$broadcast('gateway.redirect', info);
      }
      function displayServerError(status, res, body) {
        $scope.status = 'error';
        //$scope.statuses.PAYMENT_ERROR;
        if (body) {
          $scope.errorMessage = body.message;
        } else {
          $scope.errorMessage = 'An unexpected error happend while trying to continue to payment. Please call the support team for further details';
        }
        $scope.actions = [{
            label: 'Fermer',
            run: cancel
          }];
      }
      init();
    }
  ]).directive('offsitePayment', [
    '$timeout',
    function ($timeout) {
      return {
        replace: true,
        scope: {},
        template: '<form action="{{redirect.url}}" method="POST" name="redirectForm">{{redirect.data}}</form>',
        link: function ($scope, element, $attrs) {
          $scope.$on($attrs['event'], function (event, redirect) {
            if (redirect.url) {
              if (redirect.method === 'GET') {
                window.location.href = redirect.url;
                return;
              } else if (redirect.method === 'POST' && redirect.type === 'html') {
                $scope.redirect = redirect;
                $timeout(function () {
                  console.log('element', element);
                  $(element).submit();
                });
              }
            }
          });
        }
      };
    }
  ]);
  // Source: src/html/scripts/checkout/controllers/processing.js
  angular.module('checkout').controller('ProcessingCtrl', [
    '$scope',
    '$state',
    '$timeout',
    '$stateParams',
    '$http',
    '$log',
    'settings',
    function ProcessingCtrl($scope, $state, $timeout, $stateParams, $http, $log, settings) {
      var cartCheck = $timeout(getCart, 2000);
      $scope.$on('$destroy', function () {
        $timeout.cancel(cartCheck);
      });
      function getCart() {
        $http.get('/carts/' + $stateParams.cart).success(function (data, status, headers, config) {
          if (data.status === 'processing') {
            cartCheck = $timeout(getCart, 2000);
          } else {
            $state.go('complete', { cart: $stateParams.cart });
          }
        }).error(function (data, status, headers, config) {
          if (status === 404) {
            $timeout.cancel(cartCheck);
            window.location.href = '/404';
          } else {
            $state.go('error', { cart: $stateParams.cart });
          }
        });
      }
    }
  ]);
  // Source: src/html/scripts/checkout/controllers/saved-message.js
  angular.module('checkout').controller('SavedMessageCtrl', [
    '$scope',
    '$state',
    '$log',
    function ProcessingCtrl($scope, $state, $log) {
    }
  ]);
  // Source: src/html/scripts/checkout/directives/ui-datepicker.js
  angular.module('ui.bootstrap.datepicker').controller('DatepickerController', [
    '$scope',
    '$attrs',
    '$parse',
    '$interpolate',
    '$timeout',
    '$log',
    'dateFilter',
    'datepickerConfig',
    function ($scope, $attrs, $parse, $interpolate, $timeout, $log, dateFilter, datepickerConfig) {
      console.log('DatepickerController');
      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)) {
        console.log($attrs.initDate, $parse($attrs.initDate));
        $scope.$parent.$watch($parse('$parent.$parent.' + $attrs.initDate), function (value) {
          console.log('initdare ' + 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,
          classes: $attrs.dateClasses && $scope.dateClasses({
            date: date,
            mode: $scope.datepickerMode
          }) || ''
        };
      };
      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();
        }
      };
    }
  ]);
  // Source: src/html/scripts/checkout/filters/name.js
  angular.module('checkout').filter('name', function () {
    var vals = [
        'prefix',
        'first',
        'last'
      ];
    return function (input) {
      if (!input) {
        return '';
      } else if (typeof input === 'string') {
        return input;
      } else {
        return vals.map(function (field) {
          return input[field] || '';
        }).join(' ');
      }
    };
  });
  // Source: src/html/scripts/checkout/filters/toWords.js
  angular.module('checkout').filter('words', function () {
    function isInteger(x) {
      return x % 1 === 0;
    }
    return function (value) {
      if (value && isInteger(value))
        return toWords(value);
      return value;
    };
  });
  var th = [
      '',
      'mille',
      'million',
      'billion',
      'trillion'
    ];
  var dg = [
      'z\xe9ro',
      'un',
      'deux',
      'trois',
      'quatre',
      'cinq',
      'six',
      'sept',
      'huit',
      'neuf'
    ];
  var tn = [
      'dix',
      'onze',
      'douze',
      'treize',
      'quatorze',
      'quinze',
      'seize',
      'dix-sept',
      'dix-huit',
      'dix-neuf'
    ];
  var tw = [
      'vingt',
      'trente',
      'quarante',
      'cinquante',
      'soixante',
      'soixante-dix',
      'quatre-vingt',
      'quatre-vingt-dix'
    ];
  function toWords(s) {
    s = s.toString();
    s = s.replace(/[\, ]/g, '');
    if (s != parseFloat(s))
      return 'not a number';
    var x = s.indexOf('.');
    if (x == -1)
      x = s.length;
    if (x > 15)
      return 'too big';
    var n = s.split('');
    var str = '';
    var sk = 0;
    for (var i = 0; i < x; i++) {
      if ((x - i) % 3 == 2) {
        if (n[i] == '1') {
          str += tn[Number(n[i + 1])] + ' ';
          i++;
          sk = 1;
        } else if (n[i] != 0) {
          str += tw[n[i] - 2] + ' ';
          sk = 1;
        }
      } else if (n[i] != 0) {
        str += dg[n[i]] + ' ';
        if ((x - i) % 3 == 0)
          str += 'cent ';
        sk = 1;
      }
      if ((x - i) % 3 == 1) {
        if (sk)
          str += th[(x - i - 1) / 3] + ' ';
        sk = 0;
      }
    }
    if (x != s.length) {
      var y = s.length;
      str += 'point ';
      for (var i = x + 1; i < y; i++)
        str += dg[n[i]] + ' ';
    }
    return str.replace(/\s+/g, ' ');
  }
  window.toWords = toWords;
  // Source: src/html/scripts/checkout/mocks/panes/remarks.js
  /*
angular.module('checkout')
  .controller('PaymentCtrl', function PaymentCtrl($scope, paymentMethods) {
    

    
    function init(methods){
      $scope.paymentMethods = methods;
      $scope.payment = {};
        
      // if one select it by default
      if (methods.length === 1) {
        $scope.payment.method = methods[0];
        $scope.singleMethod = true;
      }
      else {
        $scope.singleMethod = false;
      }
    }
    
    function methodsQueryFailed() {
      $scope.errors.paymentMethods = "Failed to load payment methods";
    }
    
    paymentMethods.query($scope.order).then(init, methodsQueryFailed);

    
    
  });
  */
  // Source: src/html/scripts/checkout/mocks/panes/travellers.js
  /*
angular.module('checkout')
  .controller('PaymentCtrl', function PaymentCtrl($scope, paymentMethods) {
    

    
    function init(methods){
      $scope.paymentMethods = methods;
      $scope.payment = {};
        
      // if one select it by default
      if (methods.length === 1) {
        $scope.payment.method = methods[0];
        $scope.singleMethod = true;
      }
      else {
        $scope.singleMethod = false;
      }
    }
    
    function methodsQueryFailed() {
      $scope.errors.paymentMethods = "Failed to load payment methods";
    }
    
    paymentMethods.query($scope.order).then(init, methodsQueryFailed);

    
    
  });
*/
  // Source: src/html/scripts/checkout/services/gtm.js
  angular.module('checkout').service('GoogleTagManager', [
    '$window',
    function ($window) {
      this.push = function (data) {
        try {
          $window.dataLayer.push(data);
        } catch (e) {
        }
      };
    }
  ]);
  // Source: src/html/scripts/checkout/services/itemtypes.js
  /*
angular.module('checkout')
  .service('Itemtypes', function Itemtypes() {
    // AngularJS will instantiate a singleton by calling "new" on this function
  });
*/
  // Source: src/html/scripts/checkout/services/payment-methods.js
  angular.module('checkout').factory('paymentMethods', [
    '$q',
    '$http',
    '$log',
    function paymentMethods($q, $http, $log) {
      function query(cart) {
        var def = $q.defer();
        $http.get('/payment-methods?order=' + cart._id).success(function (data) {
          def.resolve(data);
        }).error(function () {
          def.reject(arguments);
        });
        return def.promise;
      }
      function preparePayment(cart, payment) {
        var method = payment.method;
        var def = $q.defer();
        // TODO loop through payments and get the one with status PENDING
        $log.debug('preparePayment method', method);
        $http.get('/payment-methods/' + method.code + '?checkout=1').success(function (data) {
          def.resolve(data);
        }).error(function () {
          def.reject('Unable to process order payement');
        });
        return def.promise;
      }
      function getPaymentByOrder(cart) {
        var order = cart._id;
        console.log(' id cart : ', order);
        var def = $q.defer();
        // TODO loop through payments and get the one with status PENDING
        $log.debug('Payment by order', order);
        $http.get('/payments?qt=byCode&code=' + order).success(function (data) {
          def.resolve(data);
        }).error(function () {
          def.reject('Unable to process order payement');
        });
        return def.promise;
      }
      // AngularJS will instantiate a singleton by calling "new" on this function
      return {
        process: preparePayment,
        query: query,
        getPaymentByOrder: getPaymentByOrder
      };
    }
  ]);
}());