function getFirstTextLine(commentString) {
  if (!commentString) { return; }
      
  var lines = commentString.split('\n');
  var MARKDOWN_CHARS = {
    '#': true,
    '-': true,
    '>': true,
    '`': true
  };

  for (var i = 0; i < lines.length; ++i) {
    // Skip code lines.
    if (lines[i].indexOf('    ') == 0) {
      continue;
    }

    // Skip empty lines.
    if ($.trim(lines[i]).length == 0) {
      continue;
    }

    // Skip control lines.
    if (MARKDOWN_CHARS[$.trim(lines[i])[0]]) {
      continue;
    }

    return getMarkedDown(lines[i]);
  }

  return '';
}

function getMarkedDown(string) {
  return Markdown.getSanitizingConverter().makeHtml(string || '');
}

function HeaderCtrl($scope, UserService) {
 $scope.$watch( function () { return UserService.currentUser(); }, function (currentUser) {
    $scope.user = currentUser;
  }, true);

  $('#repoSearch').typeahead({
      name: 'repositories',
      remote: {
        url: '/api/find/repository?query=%QUERY',
        filter: function(data) {
          var datums = [];
          for (var i = 0; i < data.repositories.length; ++i) {
            var repo = data.repositories[i];
            datums.push({
              'value': repo.name,
              'tokens': [repo.name, repo.namespace],
              'repo': repo
            });
          }
          return datums;
        }
      },
      template: function (datum) {
        template = '<div class="repo-mini-listing">';
        template += '<i class="icon-hdd icon-large"></i>'
        template += '<span class="name">' + datum.repo.namespace +'/' + datum.repo.name + '</span>'
        if (datum.repo.description) {
          template += '<span class="description">' + getFirstTextLine(datum.repo.description) + '</span>'
        }

        template += '</div>'
        return template;
      },

  });

  $('#repoSearch').on('typeahead:selected', function (e, datum) {
      $('#repoSearch').typeahead('setQuery', '');
      document.location = '#/repository/' + datum.repo.namespace + '/' + datum.repo.name
  });
}

function PlansCtrl($scope, UserService, PlanService) {
  $scope.plans = PlanService.planList();

  $scope.$watch( function () { return UserService.currentUser(); }, function (currentUser) {
    $scope.user = currentUser;
  }, true);

  $scope.buyNow = function(plan) {
    if ($scope.user && !$scope.user.anonymous) {
      document.location = '#/user?plan=' + plan;
    } else {
      $('#signinModal').modal({});
    }
  };
}

function GuideCtrl($scope, Restangular) {
}

function RepoListCtrl($scope, Restangular, UserService) {
  $scope.$watch( function () { return UserService.currentUser(); }, function (currentUser) {
    $scope.user = currentUser;
  }, true);

  $scope.getCommentFirstLine = function(commentString) {
    return getMarkedDown(getFirstTextLine(commentString));
  };

  $scope.getMarkedDown = function(string) {
    if (!string) { return ''; }
    return getMarkedDown(string);
  };

  $scope.loading = true;
  $scope.public_repositories = null;
  $scope.private_repositories = null;

  // Load the list of personal repositories.
  var repositoryPrivateFetch = Restangular.all('repository/');
  repositoryPrivateFetch.getList({'public': false, 'sort': true}).then(function(resp) {
    $scope.private_repositories = resp.repositories;
    $scope.loading = !($scope.public_repositories && $scope.private_repositories);
  });

  // Load the list of public repositories.
  var options = {'public': true, 'private': false, 'sort': true, 'limit': 10};
  var repositoryPublicFetch = Restangular.all('repository/');
    repositoryPublicFetch.getList(options).then(function(resp) {
    $scope.public_repositories = resp.repositories;
    $scope.loading = !($scope.public_repositories && $scope.private_repositories);
  });
}

function LandingCtrl($scope, $timeout, Restangular, UserService) {
  $('.form-signup').popover();

  $scope.$watch( function () { return UserService.currentUser(); }, function (currentUser) {
    if (!currentUser.anonymous) {
      $scope.loadMyRepos();
    }

    $scope.user = currentUser;
  }, true);

  $scope.awaitingConfirmation = false;
  $scope.registering = false;

  $scope.getCommentFirstLine = function(commentString) {
    return getMarkedDown(getFirstTextLine(commentString));
  };

  $scope.browseRepos = function() {
    document.location = '/#/repository';
  };

  $scope.register = function() {
    $('.form-signup').popover('hide');
    $scope.registering = true;

    var newUserPost = Restangular.one('user/');
    newUserPost.customPOST($scope.newUser).then(function() {
      $scope.awaitingConfirmation = true;
      $scope.registering  = false;

      mixpanel.alias($scope.newUser.username);
      mixpanel.people.set_once({
        '$email': $scope.newUser.email,
        '$username': $scope.newUser.username,
        '$created': new Date(),
        'verified': false
      });
    }, function(result) {
      $scope.registering  = false;
      $scope.registerError = result.data.message;
      $timeout(function() {
        $('.form-signup').popover('show');
      });
    });
  };

  $scope.loadMyRepos = function() {
      $scope.loadingmyrepos = true;

      // Load the list of repositories.
      var params = {
          'limit': 5,
          'public': false,
          'sort': true
      };

      var repositoryFetch = Restangular.all('repository/');
      repositoryFetch.getList(params).then(function(resp) {
      $scope.myrepos = resp.repositories;
      $scope.loadingmyrepos = false;
    });
  };
}

function RepoCtrl($scope, Restangular, $routeParams, $rootScope) {
  var tabs = ['current-image', 'image-history'];

  $rootScope.title = 'Loading...';
   
  $scope.showTab = function(tabName) {
    for (var i = 0; i < tabs.length; ++i) {
      $('#' + tabs[i]).hide();
      $('#' + tabs[i] + '-tab').removeClass('active');
    }

    $('#' + tabName).show();
    $('#' + tabName + '-tab').addClass('active');

    if (tabName == 'image-history') {
      $scope.listImages();
    }
  };

  $scope.editDescription = function() {
    if (!$scope.repo.can_write) { return; }

    if (!$scope.markdownDescriptionEditor) {
      var converter = Markdown.getSanitizingConverter();
      var editor = new Markdown.Editor(converter, '-description');
      editor.run();
      $scope.markdownDescriptionEditor = editor;
    }

    $('#wmd-input-description')[0].value = $scope.repo.description;
    $('#editModal').modal({});
  };

  $scope.saveDescription = function() {
    $('#editModal').modal('hide');
    $scope.repo.description = $('#wmd-input-description')[0].value;
    $scope.repo.put();
  };

  $scope.parseDate = function(dateString) {
    return Date.parse(dateString);
  };

  $scope.getCommentFirstLine = function(commentString) {
    return getMarkedDown(getFirstTextLine(commentString));
  };

  $scope.getTimeSince= function(createdTime) {
      return moment($scope.parseDate(createdTime)).fromNow();
  };

  $scope.getMarkedDown = function(string) {
    if (!string) { return ''; }
    return getMarkedDown(string);
  };
    
  $scope.listImages = function() {
    if ($scope.imageHistory) { return; }

    var imageFetch = Restangular.one('repository/' + namespace + '/' + name + '/image');
    imageFetch.get().then(function(resp) {
      $scope.imageHistory = resp.images;
      var tree = new ImageHistoryTree(namespace, name, resp.images, $scope.currentTag,
                                      $scope.getCommentFirstLine, $scope.getTimeSince);
      tree.draw('image-history-container');
    });
  };

  $scope.getTagCount = function(repo) {
    if (!repo) { return 0; }
    var count = 0;
    for (var tag in repo.tags) {
      ++count;
    }
    return count;
  };

  var namespace = $routeParams.namespace;
  var name = $routeParams.name;
  var tag = $routeParams.tag || 'latest';

  $scope.loading = true;

  var repositoryFetch = Restangular.one('repository/' + namespace + '/' + name);
  repositoryFetch.get().then(function(repo) {
    $rootScope.title = namespace + '/' + name;
    $scope.repo = repo;
    $scope.currentTag = repo.tags[tag] || repo.tags['latest'];

    var clip = new ZeroClipboard($('#copyClipboard'),  { 'moviePath': 'static/lib/ZeroClipboard.swf' });
    clip.on('complete', function() {
      // Resets the animation.
      var elem = $('#clipboardCopied')[0];
      elem.style.display = 'none';
      
      // Show the notification.
      setTimeout(function() {
        elem.style.display = 'block';
      }, 1);
    });

    $scope.loading = false;
  }, function() {
    $scope.repo = null;
    $scope.loading = false;
    $rootScope.title = 'Unknown Repository';
  });
}

function RepoAdminCtrl($scope, Restangular, $routeParams, $rootScope) {
  var namespace = $routeParams.namespace;
  var name = $routeParams.name;

  $('#userSearch').typeahead({
    name: 'users',
    remote: {
      url: '/api/users/%QUERY',
      filter: function(data) {
        var datums = [];
        for (var i = 0; i < data.users.length; ++i) {
          var user = data.users[i];
          datums.push({
            'value': user,
            'tokens': [user],
            'username': user
          });
        }
        return datums;
      }
    },
    template: function (datum) {
      template = '<div class="user-mini-listing">';
      template += '<i class="icon-user icon-large"></i>'
      template += '<span class="name">' + datum.username + '</span>'
      template += '</div>'
      return template;
    },
  });

  $('#userSearch').on('typeahead:selected', function(e, datum) {
    $('#userSearch').typeahead('setQuery', '');
    $scope.addNewPermission(datum.username);
  });

  $scope.addNewPermission = function(username) {
    // Don't allow duplicates.
    if ($scope.permissions[username]) { return; }

    // Need the $scope.apply for both the permission stuff to change and for
    // the XHR call to be made.
    $scope.$apply(function() {
      $scope.addRole(username, 'read')
    });
  };

  $scope.deleteRole = function(username) {
    var permissionDelete = Restangular.one('repository/' + namespace + '/' + name + '/permissions/' + username);
    permissionDelete.customDELETE().then(function() {
      delete $scope.permissions[username];
    }, function(result) {
      if (result.status == 409) {
        $('#onlyadminModal').modal({});
      } else {
        $('#cannotchangeModal').modal({});
      }
    });
  };

  $scope.addRole = function(username, role) {
    var permission = {
      'role': role
    };

    var permissionPost = Restangular.one('repository/' + namespace + '/' + name + '/permissions/' + username);
    permissionPost.customPOST(permission).then(function() {
      $scope.permissions[username] = permission;
      $scope.permissions = $scope.permissions;
    }, function(result) {
      $('#cannotchangeModal').modal({});
    });
  };

  $scope.setRole = function(username, role) {
    var permission = $scope.permissions[username];
    var currentRole = permission.role;
    permission.role = role;
   
    var permissionPut = Restangular.one('repository/' + namespace + '/' + name + '/permissions/' + username);
    permissionPut.customPUT(permission).then(function() {}, function(result) {
      if (result.status == 409) {
        permission.role = currentRole;
        $('#onlyadminModal').modal({});
      } else {
        $('#cannotchangeModal').modal({});
      }
    });
  };

  $scope.askChangeAccess = function(newAccess) {
    $('#make' + newAccess + 'Modal').modal({});
  };

  $scope.changeAccess = function(newAccess) {
    $('#make' + newAccess + 'Modal').modal('hide');

    var visibility = {
      'visibility': newAccess
    };
    var visibilityPost = Restangular.one('repository/' + namespace + '/' + name + '/changevisibility');
    visibilityPost.customPOST(visibility).then(function() {
      $scope.repo.is_public = newAccess == 'public';
    }, function() {
      $('#cannotchangeModal').modal({});
    });
  };

  $scope.askDelete = function() {
    $('#confirmdeleteModal').modal({});
  };

  $scope.deleteRepo = function() {
    $('#confirmdeleteModal').modal('hide');

    var deleteAction = Restangular.one('repository/' + namespace + '/' + name);
    deleteAction.customDELETE().then(function() {
      $scope.repo = null;
      
      setTimeout(function() {
          document.location = '/#/repository';
      }, 1000);
    }, function() {
      $('#cannotchangeModal').modal({});
    });
  };

  $scope.loading = true;

  // Fetch the repository information.
  var repositoryFetch = Restangular.one('repository/' + namespace + '/' + name);
  repositoryFetch.get().then(function(repo) {
    $scope.repo = repo;
    $scope.loading = !($scope.permissions && $scope.repo);
  }, function() {
    $scope.permissions = null;
    $rootScope.title = 'Unknown Repository';
    $scope.loading = false;
  });

  // Fetch the permissions.
  var permissionsFetch = Restangular.one('repository/' + namespace + '/' + name + '/permissions');
  permissionsFetch.get().then(function(resp) {
    $rootScope.title = 'Settings - ' + namespace + '/' + name;
    $scope.permissions = resp.permissions;
    $scope.loading = !($scope.permissions && $scope.repo);
  }, function() {
    $scope.permissions = null;
    $rootScope.title = 'Unknown Repository';
    $scope.loading = false;
  });
}

function UserAdminCtrl($scope, Restangular, PlanService, KeyService, $routeParams) {
  $scope.plans = PlanService.planList();

  var subscribedToPlan = function(sub) {
    $scope.subscription = sub;
    $scope.subscribedPlan = PlanService.getPlan(sub.plan);
    $scope.planUsagePercent = sub.usedPrivateRepos * 100 / $scope.subscribedPlan.privateRepos;

    if (sub.usedPrivateRepos > $scope.subscribedPlan.privateRepos) {
      $scope.errorMessage = 'You are using more private repositories than your plan allows, please upgrate your subscription to avoid disruptions in your service.';
    }

    $scope.planLoading = false;
    $scope.planChanging = false;

    mixpanel.people.set({
      'plan': sub.plan
    });
  }

  $scope.planLoading = true;
  var getSubscription = Restangular.one('user/plan');
  getSubscription.get().then(subscribedToPlan, function() {
    // User has no subscription
    $scope.planLoading = false;
  });

  $scope.planChanging = false;
  $scope.subscribe = function(planId) {
    var submitToken = function(token) {
      $scope.$apply(function() {
        mixpanel.track('plan_subscribe');

        $scope.planChanging = true;
        $scope.errorMessage = undefined;

        var subscriptionDetails = {
          token: token.id,
          plan: planId,
        };

        var createSubscriptionRequest = Restangular.one('user/plan');
        createSubscriptionRequest.customPUT(subscriptionDetails).then(subscribedToPlan, function() {
          // Failure
          $scope.errorMessage = 'Unable to subscribe.';
        });
      });
    };

    var planDetails = PlanService.getPlan(planId)
    StripeCheckout.open({
      key:         KeyService.stripePublishableKey,
      address:     false, // TODO change to true
      amount:      planDetails.price,
      currency:    'usd',
      name:        'Quay ' + planDetails.title + ' Subscription',
      description: 'Up to ' + planDetails.privateRepos + ' private repositories',
      panelLabel:  'Subscribe',
      token:       submitToken
    });
  };

  $scope.changeSubscription = function(planId) {
    $scope.planChanging = true;
    $scope.errorMessage = undefined;

    var subscriptionDetails = {
      plan: planId,
    };

    var changeSubscriptionRequest = Restangular.one('user/plan');
    changeSubscriptionRequest.customPUT(subscriptionDetails).then(subscribedToPlan, function() {
      // Failure
      $scope.errorMessage = 'Unable to change subscription.';
      $scope.planChanging = false;
    });
  };

  $scope.cancelSubscription = function() {
    $scope.changeSubscription('free');
  };

  // Show the subscribe dialog if a plan was requested.
  var requested = $routeParams['plan']
  if (requested !== undefined && requested !== 'free') {
    if (PlanService.getPlan(requested) !== undefined) {
      $scope.subscribe(requested);
    }
  }
}