/**
 * An element which displays a form for manually starting a dockerfile build.
 */
angular.module('quay').directive('dockerfileBuildForm', function () {
  var directiveDefinitionObject = {
    priority: 0,
    templateUrl: '/static/directives/dockerfile-build-form.html',
    replace: false,
    transclude: false,
    restrict: 'C',
    scope: {
      'repository': '=repository',
      'startNow': '=startNow',
      'isReady': '=isReady',
      'uploadFailed': '&uploadFailed',
      'uploadStarted': '&uploadStarted',
      'buildStarted': '&buildStarted',
      'buildFailed': '&buildFailed',
      'missingFile': '&missingFile',
      'uploading': '=uploading',
      'building': '=building'
    },
    controller: function($scope, $element, ApiService) {
      $scope.internal = {'hasDockerfile': false};
      $scope.pull_entity = null;
      $scope.is_public = true;

      var handleBuildFailed = function(message) {
        message = message || 'Dockerfile build failed to start';

        var result = false;
        if ($scope.buildFailed) {
          result = $scope.buildFailed({'message': message});
        }

        if (!result) {
          bootbox.dialog({
            "message": message,
            "title": "Cannot start Dockerfile build",
            "buttons": {
              "close": {
                "label": "Close",
                "className": "btn-primary"
              }
            }
          });
        }
      };

      var handleUploadFailed = function(message) {
        message = message || 'Error with file upload';

        var result = false;
        if ($scope.uploadFailed) {
          result = $scope.uploadFailed({'message': message});
        }

        if (!result) {
          bootbox.dialog({
            "message": message,
            "title": "Cannot upload file for Dockerfile build",
            "buttons": {
              "close": {
                "label": "Close",
                "className": "btn-primary"
              }
            }
          });
        }
      };

      var handleMissingFile = function() {
        var result = false;
        if ($scope.missingFile) {
          result = $scope.missingFile({});
        }

         if (!result) {
          bootbox.dialog({
            "message": 'A Dockerfile or an archive containing a Dockerfile is required',
            "title": "Missing Dockerfile",
            "buttons": {
              "close": {
                "label": "Close",
                "className": "btn-primary"
              }
            }
          });
        }
      };

      var startBuild = function(fileId) {
        $scope.building = true;

        var repo = $scope.repository;
        var data = {
          'file_id': fileId
        };

        if (!$scope.is_public && $scope.pull_entity) {
          data['pull_robot'] = $scope.pull_entity['name'];
        }

        var params = {
          'repository': repo.namespace + '/' + repo.name,
        };

        ApiService.requestRepoBuild(data, params).then(function(resp) {
          $scope.building = false;
          $scope.uploading = false;

          if ($scope.buildStarted) {
            $scope.buildStarted({'build': resp});
          }
        }, function(resp) {
          $scope.building = false;
          $scope.uploading = false;

          handleBuildFailed(resp.message);
        });
      };

      var conductUpload = function(file, url, fileId, mimeType) {
        if ($scope.uploadStarted) {
          $scope.uploadStarted({});
        }

        var request = new XMLHttpRequest();
        request.open('PUT', url, true);
        request.setRequestHeader('Content-Type', mimeType);
        request.onprogress = function(e) {
          $scope.$apply(function() {
            var percentLoaded;
            if (e.lengthComputable) {
              $scope.upload_progress = (e.loaded / e.total) * 100;
            }
          });
        };
        request.onerror = function() {
          $scope.$apply(function() {
            handleUploadFailed();
          });
        };
        request.onreadystatechange = function() {
          var state = request.readyState;
          if (state == 4) {
            $scope.$apply(function() {
              startBuild(fileId);
              $scope.uploading = false;
            });
            return;
          }
        };
        request.send(file);
      };

      var startFileUpload = function(repo) {
        $scope.uploading = true;
        $scope.uploading_progress = 0;

        var uploader = $element.find('#file-drop')[0];
        if (uploader.files.length == 0) {
          handleMissingFile();
          $scope.uploading = false;
          return;
        }

        var file = uploader.files[0];
        $scope.upload_file = file.name;

        var mimeType = file.type || 'application/octet-stream';
        var data = {
          'mimeType': mimeType
        };

        var getUploadUrl = ApiService.getFiledropUrl(data).then(function(resp) {
          conductUpload(file, resp.url, resp.file_id, mimeType);
        }, function() {
          handleUploadFailed('Could not retrieve upload URL');
        });
      };

      var checkIsReady = function() {
        $scope.isReady = $scope.internal.hasDockerfile && ($scope.is_public || $scope.pull_entity);
      };

      $scope.$watch('pull_entity', checkIsReady);
      $scope.$watch('is_public', checkIsReady);
      $scope.$watch('internal.hasDockerfile', checkIsReady);

      $scope.$watch('startNow', function() {
        if ($scope.startNow && $scope.repository && !$scope.uploading && !$scope.building) {
          startFileUpload();
        }
      });
    }
  };
  return directiveDefinitionObject;
});