/**
 * Copyright (c) 2000-2013 Liferay, Inc. All rights reserved.
 *
 * The contents of this file are subject to the terms of the Liferay Enterprise
 * Subscription License ("License"). You may not use this file except in
 * compliance with the License. You can obtain a copy of the License by
 * contacting Liferay, Inc. See the License for the specific language governing
 * permissions and limitations under the License, including but not limited to
 * distribution rights of the Software.
 *
 *
 *
 */

package com.liferay.portal.template;

import com.liferay.portal.kernel.log.Log;
import com.liferay.portal.kernel.log.LogFactoryUtil;
import com.liferay.portal.kernel.template.TemplateConstants;
import com.liferay.portal.kernel.template.TemplateException;
import com.liferay.portal.kernel.template.TemplateResource;
import com.liferay.portal.kernel.template.URLTemplateResource;
import com.liferay.portal.kernel.util.ArrayUtil;
import com.liferay.portal.kernel.util.CharPool;
import com.liferay.portal.kernel.util.FileUtil;
import com.liferay.portal.kernel.util.StringPool;
import com.liferay.portal.kernel.util.StringUtil;
import com.liferay.portal.kernel.util.Validator;

import java.io.IOException;

import java.net.URL;

import java.util.ArrayList;
import java.util.List;

/**
 * @author Tina Tian
 */
public abstract class URLResourceParser implements TemplateResourceParser {

	@Override
	public TemplateResource getTemplateResource(String templateId)
		throws TemplateException {

		templateId = normalizePath(templateId);

		try {
			URL url = getURL(templateId);

			if (url == null) {
				return null;
			}

			return new URLTemplateResource(templateId, url);
		}
		catch (IOException ioe) {
			throw new TemplateException(ioe);
		}
	}

	public abstract URL getURL(String templateId) throws IOException;

	@Override
	public boolean isTemplateResourceValid(String templateId, String langType) {
		if (Validator.isBlank(templateId)) {
			return true;
		}

		char[] chars = templateId.toCharArray();

		for (int i = 0; i < chars.length; i++) {
			char c = chars[i];

			if ((c == CharPool.PERCENT) || (c == CharPool.POUND) ||
				(c == CharPool.QUESTION) || (c == CharPool.SEMICOLON)) {

				if (_log.isWarnEnabled()) {
					_log.warn(
						"Unable to load template " + templateId +
							" because the template name contains one or more " +
								"special characters: %, #, ?, or ;");
				}

				return false;
			}

			if (c == CharPool.BACK_SLASH) {
				if (_log.isWarnEnabled()) {
					_log.warn(
						"Unable to load template " + templateId +
							" because the template name contains a backslash");
				}

				return false;
			}
		}

		String extension = FileUtil.getExtension(templateId);

		if (!extension.equals(langType) &&
			!ArrayUtil.contains(
					TemplateConstants.ALLOWED_LANG_TYPES, extension)) {

			return false;
		}

		return true;
	}

	protected static String normalizePath(String path) {
		List<String> elements = new ArrayList<String>();

		boolean absolutePath = false;

		int previousIndex = -1;

		for (int index;
			(index = path.indexOf(CharPool.SLASH, previousIndex + 1)) != -1;
			previousIndex = index) {

			if ((previousIndex + 1) == index) {

				// Starts with "/"

				if (previousIndex == -1) {
					absolutePath = true;

					continue;
				}

				// "//" is illegal

				throw new IllegalArgumentException(
					"Unable to parse path " + path);
			}

			String pathElement = path.substring(previousIndex + 1, index);

			// "." needs no handling

			if (pathElement.equals(StringPool.PERIOD)) {
				continue;
			}

			// ".." pops up stack

			if (pathElement.equals(StringPool.DOUBLE_PERIOD)) {
				if (elements.isEmpty()) {
					throw new IllegalArgumentException(
						"Unable to parse path " + path);
				}

				elements.remove(elements.size() - 1);

				continue;
			}

			// Others push down stack

			elements.add(pathElement);
		}

		if (previousIndex == -1) {
			elements.add(path);
		}
		else if ((previousIndex + 1) < path.length()) {
			elements.add(path.substring(previousIndex + 1));
		}

		String normalizedPath = StringUtil.merge(elements, StringPool.SLASH);

		if (absolutePath) {
			normalizedPath = StringPool.SLASH.concat(normalizedPath);
		}

		return normalizedPath;
	}

	private static Log _log = LogFactoryUtil.getLog(URLResourceParser.class);
}