/*
 * 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) &&
			settings.getBoolean(Keys.web.showHttpServletUrls, true)) {
			AccessPermission permission = user.getRepositoryPermission(repository).permission;
			if (permission.exceeds(AccessPermission.NONE)) {
				String repoUrl = getRepositoryUrl(request, username, repository);
				Transport transport = Transport.fromUrl(repoUrl);
				if (permission.atLeast(AccessPermission.PUSH) && !acceptsPush(transport)) {
					// downgrade the repo permission for this transport
					// because it is not an acceptable PUSH transport
					permission = AccessPermission.CLONE;
				}
				list.add(new RepositoryUrl(repoUrl, permission));
			}
		}

		// ssh daemon url
		String sshDaemonUrl = getSshDaemonUrl(request, user, repository);
		if (!StringUtils.isEmpty(sshDaemonUrl) &&
			settings.getBoolean(Keys.web.showSshDaemonUrls, true)) {
			AccessPermission permission = user.getRepositoryPermission(repository).permission;
			if (permission.exceeds(AccessPermission.NONE)) {
				if (permission.atLeast(AccessPermission.PUSH) && !acceptsPush(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) &&
				settings.getBoolean(Keys.web.showGitDaemonUrls, true)) {
			AccessPermission permission = getGitDaemonAccessPermission(user, repository);
			if (permission.exceeds(AccessPermission.NONE)) {
				if (permission.atLeast(AccessPermission.PUSH) && !acceptsPush(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
		boolean advertisePermsForOther = settings.getBoolean(Keys.web.advertiseAccessPermissionForOtherUrls, false);
		for (String url : settings.getStrings(Keys.web.otherUrls)) {
			String externalUrl = null;

			if (url.contains("{1}")) {
				// external url requires username, only add url IF we have one
				if (StringUtils.isEmpty(username)) {
					continue;
				} else {
					externalUrl = MessageFormat.format(url, repository.name, username);
				}
			} else {
				// external url does not require username, just do repo name formatting
				externalUrl = MessageFormat.format(url, repository.name);
			}

			AccessPermission permission = null;
			if (advertisePermsForOther) {
				permission = user.getRepositoryPermission(repository).permission;
				if (permission.exceeds(AccessPermission.NONE)) {
					Transport transport = Transport.fromUrl(externalUrl);
					if (permission.atLeast(AccessPermission.PUSH) && !acceptsPush(transport)) {
						// downgrade the repo permission for this transport
						// because it is not an acceptable PUSH transport
						permission = AccessPermission.CLONE;
					}
				}
			}
			list.add(new RepositoryUrl(externalUrl, permission));
		}

		// 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.hasPermission() && !o2.hasPermission()) {
					// prefer known permission items over unknown
					return -1;
				} else if (!o1.hasPermission() && o2.hasPermission()) {
					// prefer known permission items over unknown
					return 1;
				} else if (!o1.hasPermission() && !o2.hasPermission()) {
					// 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 isServingHTTPS()
				|| isServingHTTP()
				|| isServingGIT()
				|| isServingSSH();
	}

	/* (non-Javadoc)
	 * @see com.gitblit.manager.IServicesManager#isServingHTTP()
	 */
	@Override
	public boolean isServingHTTP() {
		return settings.getBoolean(Keys.git.enableGitServlet, true)
				&& ((gitblit.getStatus().isGO && settings.getInteger(Keys.server.httpPort, 0) > 0)
						|| !gitblit.getStatus().isGO);
	}

	/* (non-Javadoc)
	 * @see com.gitblit.manager.IServicesManager#isServingHTTPS()
	 */
	@Override
	public boolean isServingHTTPS() {
		return settings.getBoolean(Keys.git.enableGitServlet, true)
				&& ((gitblit.getStatus().isGO && settings.getInteger(Keys.server.httpsPort, 0) > 0)
						|| !gitblit.getStatus().isGO);
	}

	/* (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);
		}
	}

	@Override
	public boolean acceptsPush(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, 5);
			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));
		}
	}
}
