/*
 * Copyright 2013 gitblit.com.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.gitblit.manager;

import java.io.IOException;
import java.net.URI;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

import javax.servlet.http.HttpServletRequest;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.gitblit.Constants;
import com.gitblit.Constants.AccessPermission;
import com.gitblit.Constants.AccessRestrictionType;
import com.gitblit.Constants.FederationToken;
import com.gitblit.Constants.Transport;
import com.gitblit.IStoredSettings;
import com.gitblit.Keys;
import com.gitblit.fanout.FanoutNioService;
import com.gitblit.fanout.FanoutService;
import com.gitblit.fanout.FanoutSocketService;
import com.gitblit.models.FederationModel;
import com.gitblit.models.RepositoryModel;
import com.gitblit.models.RepositoryUrl;
import com.gitblit.models.UserModel;
import com.gitblit.service.FederationPullService;
import com.gitblit.transport.git.GitDaemon;
import com.gitblit.transport.ssh.SshDaemon;
import com.gitblit.utils.HttpUtils;
import com.gitblit.utils.StringUtils;
import com.gitblit.utils.TimeUtils;
import com.gitblit.utils.WorkQueue;
import com.google.inject.Inject;
import com.google.inject.Provider;
import com.google.inject.Singleton;

/**
 * Services manager manages long-running services/processes that either have no
 * direct relation to other managers OR require really high-level manager
 * integration (i.e. a Gitblit instance).
 *
 * @author James Moger
 *
 */
@Singleton
public class ServicesManager implements IServicesManager {

	private final Logger logger = LoggerFactory.getLogger(getClass());

	private final ScheduledExecutorService scheduledExecutor = Executors.newScheduledThreadPool(5);

	private final Provider<WorkQueue> workQueueProvider;

	private final IStoredSettings settings;

	private final IGitblit gitblit;

	private FanoutService fanoutService;

	private GitDaemon gitDaemon;

	private SshDaemon sshDaemon;

	@Inject
	public ServicesManager(
			Provider<WorkQueue> workQueueProvider,
			IStoredSettings settings,
			IGitblit gitblit) {

		this.workQueueProvider = workQueueProvider;

		this.settings = settings;
		this.gitblit = gitblit;
	}

	@Override
	public ServicesManager start() {
		configureFederation();
		configureFanout();
		configureGitDaemon();
		configureSshDaemon();

		return this;
	}

	@Override
	public ServicesManager stop() {
		scheduledExecutor.shutdownNow();
		if (fanoutService != null) {
			fanoutService.stop();
		}
		if (gitDaemon != null) {
			gitDaemon.stop();
		}
		if (sshDaemon != null) {
			sshDaemon.stop();
		}
		workQueueProvider.get().stop();
		return this;
	}

	protected String getRepositoryUrl(HttpServletRequest request, String username, RepositoryModel repository) {
		String gitblitUrl = settings.getString(Keys.web.canonicalUrl, null);
		if (StringUtils.isEmpty(gitblitUrl)) {
			gitblitUrl = HttpUtils.getGitblitURL(request);
		}
		StringBuilder sb = new StringBuilder();
		sb.append(gitblitUrl);
		sb.append(Constants.R_PATH);
		sb.append(repository.name);

		// inject username into repository url if authentication is required
		if (repository.accessRestriction.exceeds(AccessRestrictionType.NONE)
				&& !StringUtils.isEmpty(username)) {
			sb.insert(sb.indexOf("://") + 3, username + "@");
		}
		return sb.toString();
	}

	/**
	 * Returns a list of repository URLs and the user access permission.
	 *
	 * @param request
	 * @param user
	 * @param repository
	 * @return a list of repository urls
	 */
	@Override
	public List<RepositoryUrl> getRepositoryUrls(HttpServletRequest request, UserModel user, RepositoryModel repository) {
		if (user == null) {
			user = UserModel.ANONYMOUS;
		}
		String username = StringUtils.encodeUsername(UserModel.ANONYMOUS.equals(user) ? "" : user.username);

		List<RepositoryUrl> list = new ArrayList<RepositoryUrl>();

		// http/https url
		if (settings.getBoolean(Keys.git.enableGitServlet, true)) {
			AccessPermission permission = user.getRepositoryPermission(repository).permission;
			if (permission.exceeds(AccessPermission.NONE)) {
				Transport transport = Transport.fromString(request.getScheme());
				if (permission.atLeast(AccessPermission.PUSH) && !acceptPush(transport)) {
					// downgrade the repo permission for this transport
					// because it is not an acceptable PUSH transport
					permission = AccessPermission.CLONE;
				}
				list.add(new RepositoryUrl(getRepositoryUrl(request, username, repository), permission));
			}
		}

		// ssh daemon url
		String sshDaemonUrl = getSshDaemonUrl(request, user, repository);
		if (!StringUtils.isEmpty(sshDaemonUrl)) {
			AccessPermission permission = user.getRepositoryPermission(repository).permission;
			if (permission.exceeds(AccessPermission.NONE)) {
				if (permission.atLeast(AccessPermission.PUSH) && !acceptPush(Transport.SSH)) {
					// downgrade the repo permission for this transport
					// because it is not an acceptable PUSH transport
					permission = AccessPermission.CLONE;
				}

				list.add(new RepositoryUrl(sshDaemonUrl, permission));
			}
		}

		// git daemon url
		String gitDaemonUrl = getGitDaemonUrl(request, user, repository);
		if (!StringUtils.isEmpty(gitDaemonUrl)) {
			AccessPermission permission = getGitDaemonAccessPermission(user, repository);
			if (permission.exceeds(AccessPermission.NONE)) {
				if (permission.atLeast(AccessPermission.PUSH) && !acceptPush(Transport.GIT)) {
					// downgrade the repo permission for this transport
					// because it is not an acceptable PUSH transport
					permission = AccessPermission.CLONE;
				}
				list.add(new RepositoryUrl(gitDaemonUrl, permission));
			}
		}

		// add all other urls
		// {0} = repository
		// {1} = username
		for (String url : settings.getStrings(Keys.web.otherUrls)) {
			if (url.contains("{1}")) {
				// external url requires username, only add url IF we have one
				if (!StringUtils.isEmpty(username)) {
					list.add(new RepositoryUrl(MessageFormat.format(url, repository.name, username), null));
				}
			} else {
				// external url does not require username
				list.add(new RepositoryUrl(MessageFormat.format(url, repository.name), null));
			}
		}

		// sort transports by highest permission and then by transport security
		Collections.sort(list, new Comparator<RepositoryUrl>() {

			@Override
			public int compare(RepositoryUrl o1, RepositoryUrl o2) {
				if (!o1.isExternal() && o2.isExternal()) {
					// prefer Gitblit over external
					return -1;
				} else if (o1.isExternal() && !o2.isExternal()) {
					// prefer Gitblit over external
					return 1;
				} else if (o1.isExternal() && o2.isExternal()) {
					// sort by Transport ordinal
					return o1.transport.compareTo(o2.transport);
				} else if (o1.permission.exceeds(o2.permission)) {
					// prefer highest permission
					return -1;
				} else if (o2.permission.exceeds(o1.permission)) {
					// prefer highest permission
					return 1;
				}

				// prefer more secure transports
				return o1.transport.compareTo(o2.transport);
			}
		});

		// consider the user's transport preference
		RepositoryUrl preferredUrl = null;
		Transport preferredTransport = user.getPreferences().getTransport();
		if (preferredTransport != null) {
			Iterator<RepositoryUrl> itr = list.iterator();
			while (itr.hasNext()) {
				RepositoryUrl url = itr.next();
				if (url.transport.equals(preferredTransport)) {
					itr.remove();
					preferredUrl = url;
					break;
				}
			}
		}
		if (preferredUrl != null) {
			list.add(0, preferredUrl);
		}

		return list;
	}

	/* (non-Javadoc)
	 * @see com.gitblit.manager.IServicesManager#isServingRepositories()
	 */
	@Override
	public boolean isServingRepositories() {
		return isServingHTTP()
				|| isServingGIT()
				|| isServingSSH();
	}

	/* (non-Javadoc)
	 * @see com.gitblit.manager.IServicesManager#isServingHTTP()
	 */
	@Override
	public boolean isServingHTTP() {
		return settings.getBoolean(Keys.git.enableGitServlet, true);
	}

	/* (non-Javadoc)
	 * @see com.gitblit.manager.IServicesManager#isServingGIT()
	 */
	@Override
	public boolean isServingGIT() {
		return gitDaemon != null && gitDaemon.isRunning();
	}

	/* (non-Javadoc)
	 * @see com.gitblit.manager.IServicesManager#isServingSSH()
	 */
	@Override
	public boolean isServingSSH() {
		return sshDaemon != null && sshDaemon.isRunning();
	}

	protected void configureFederation() {
		boolean validPassphrase = true;
		String passphrase = settings.getString(Keys.federation.passphrase, "");
		if (StringUtils.isEmpty(passphrase)) {
			logger.info("Federation passphrase is blank! This server can not be PULLED from.");
			validPassphrase = false;
		}
		if (validPassphrase) {
			// standard tokens
			for (FederationToken tokenType : FederationToken.values()) {
				logger.info(MessageFormat.format("Federation {0} token = {1}", tokenType.name(),
						gitblit.getFederationToken(tokenType)));
			}

			// federation set tokens
			for (String set : settings.getStrings(Keys.federation.sets)) {
				logger.info(MessageFormat.format("Federation Set {0} token = {1}", set,
						gitblit.getFederationToken(set)));
			}
		}

		// Schedule or run the federation executor
		List<FederationModel> registrations = gitblit.getFederationRegistrations();
		if (registrations.size() > 0) {
			FederationPuller executor = new FederationPuller(registrations);
			scheduledExecutor.schedule(executor, 1, TimeUnit.MINUTES);
		}
	}

	protected boolean acceptPush(Transport byTransport) {
		if (byTransport == null) {
			logger.info("Unknown transport, push rejected!");
			return false;
		}

		Set<Transport> transports = new HashSet<Transport>();
		for (String value : settings.getStrings(Keys.git.acceptedPushTransports)) {
			Transport transport = Transport.fromString(value);
			if (transport == null) {
				logger.info(String.format("Ignoring unknown registered transport %s", value));
				continue;
			}

			transports.add(transport);
		}

		if (transports.isEmpty()) {
			// no transports are explicitly specified, all are acceptable
			return true;
		}

		// verify that the transport is permitted
		return transports.contains(byTransport);
	}

	protected void configureGitDaemon() {
		int port = settings.getInteger(Keys.git.daemonPort, 0);
		String bindInterface = settings.getString(Keys.git.daemonBindInterface, "localhost");
		if (port > 0) {
			try {
				gitDaemon = new GitDaemon(gitblit);
				gitDaemon.start();
			} catch (IOException e) {
				gitDaemon = null;
				logger.error(MessageFormat.format("Failed to start Git Daemon on {0}:{1,number,0}", bindInterface, port), e);
			}
		} else {
			logger.info("Git Daemon is disabled.");
		}
	}

	protected void configureSshDaemon() {
		int port = settings.getInteger(Keys.git.sshPort, 0);
		String bindInterface = settings.getString(Keys.git.sshBindInterface, "localhost");
		if (port > 0) {
			try {
				sshDaemon = new SshDaemon(gitblit, workQueueProvider.get());
				sshDaemon.start();
			} catch (IOException e) {
				sshDaemon = null;
				logger.error(MessageFormat.format("Failed to start SSH daemon on {0}:{1,number,0}", bindInterface, port), e);
			}
		}
	}

	protected void configureFanout() {
		// startup Fanout PubSub service
		if (settings.getInteger(Keys.fanout.port, 0) > 0) {
			String bindInterface = settings.getString(Keys.fanout.bindInterface, null);
			int port = settings.getInteger(Keys.fanout.port, FanoutService.DEFAULT_PORT);
			boolean useNio = settings.getBoolean(Keys.fanout.useNio, true);
			int limit = settings.getInteger(Keys.fanout.connectionLimit, 0);

			if (useNio) {
				if (StringUtils.isEmpty(bindInterface)) {
					fanoutService = new FanoutNioService(port);
				} else {
					fanoutService = new FanoutNioService(bindInterface, port);
				}
			} else {
				if (StringUtils.isEmpty(bindInterface)) {
					fanoutService = new FanoutSocketService(port);
				} else {
					fanoutService = new FanoutSocketService(bindInterface, port);
				}
			}

			fanoutService.setConcurrentConnectionLimit(limit);
			fanoutService.setAllowAllChannelAnnouncements(false);
			fanoutService.start();
		} else {
			logger.info("Fanout PubSub service is disabled.");
		}
	}

	public String getGitDaemonUrl(HttpServletRequest request, UserModel user, RepositoryModel repository) {
		if (gitDaemon != null) {
			String bindInterface = settings.getString(Keys.git.daemonBindInterface, "localhost");
			if (bindInterface.equals("localhost")
					&& (!request.getServerName().equals("localhost") && !request.getServerName().equals("127.0.0.1"))) {
				// git daemon is bound to localhost and the request is from elsewhere
				return null;
			}
			if (user.canClone(repository)) {
				String hostname = getHostname(request);
				String url = gitDaemon.formatUrl(hostname, repository.name);
				return url;
			}
		}
		return null;
	}

	public AccessPermission getGitDaemonAccessPermission(UserModel user, RepositoryModel repository) {
		if (gitDaemon != null && user.canClone(repository)) {
			AccessPermission gitDaemonPermission = user.getRepositoryPermission(repository).permission;
			if (gitDaemonPermission.atLeast(AccessPermission.CLONE)) {
				if (repository.accessRestriction.atLeast(AccessRestrictionType.CLONE)) {
					// can not authenticate clone via anonymous git protocol
					gitDaemonPermission = AccessPermission.NONE;
				} else if (repository.accessRestriction.atLeast(AccessRestrictionType.PUSH)) {
					// can not authenticate push via anonymous git protocol
					gitDaemonPermission = AccessPermission.CLONE;
				} else {
					// normal user permission
				}
			}
			return gitDaemonPermission;
		}
		return AccessPermission.NONE;
	}

	public String getSshDaemonUrl(HttpServletRequest request, UserModel user, RepositoryModel repository) {
		if (user == null || UserModel.ANONYMOUS.equals(user)) {
			// SSH always requires authentication - anonymous access prohibited
			return null;
		}
		if (sshDaemon != null) {
			String bindInterface = settings.getString(Keys.git.sshBindInterface, "localhost");
			if (bindInterface.equals("localhost")
					&& (!request.getServerName().equals("localhost") && !request.getServerName().equals("127.0.0.1"))) {
				// ssh daemon is bound to localhost and the request is from elsewhere
				return null;
			}
			if (user.canClone(repository)) {
				String hostname = getHostname(request);
				String url = sshDaemon.formatUrl(user.username, hostname, repository.name);
				return url;
			}
		}
		return null;
	}


	/**
	 * Extract the hostname from the canonical url or return the
	 * hostname from the servlet request.
	 *
	 * @param request
	 * @return
	 */
	protected String getHostname(HttpServletRequest request) {
		String hostname = request.getServerName();
		String canonicalUrl = settings.getString(Keys.web.canonicalUrl, null);
		if (!StringUtils.isEmpty(canonicalUrl)) {
			try {
				URI uri = new URI(canonicalUrl);
				String host = uri.getHost();
				if (!StringUtils.isEmpty(host) && !"localhost".equals(host)) {
					hostname = host;
				}
			} catch (Exception e) {
			}
		}
		return hostname;
	}

	private class FederationPuller extends FederationPullService {

		public FederationPuller(FederationModel registration) {
			super(gitblit, Arrays.asList(registration));
		}

		public FederationPuller(List<FederationModel> registrations) {
			super(gitblit, registrations);
		}

		@Override
		public void reschedule(FederationModel registration) {
			// schedule the next pull
			int mins = TimeUtils.convertFrequencyToMinutes(registration.frequency);
			registration.nextPull = new Date(System.currentTimeMillis() + (mins * 60 * 1000L));
			scheduledExecutor.schedule(new FederationPuller(registration), mins, TimeUnit.MINUTES);
			logger.info(MessageFormat.format(
					"Next pull of {0} @ {1} scheduled for {2,date,yyyy-MM-dd HH:mm}",
					registration.name, registration.url, registration.nextPull));
		}
	}
}
