/**
 * Copyright (c) 2000-present 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.json.jabsorb.serializer;

import com.liferay.portal.kernel.util.ClassLoaderPool;
import com.liferay.portal.kernel.util.StringPool;
import com.liferay.portal.kernel.log.Log;
import com.liferay.portal.kernel.log.LogFactoryUtil;
import com.liferay.portal.kernel.util.StringBundler;

import java.util.HashMap;

import org.jabsorb.JSONSerializer;
import org.jabsorb.serializer.Serializer;
import org.jabsorb.serializer.UnmarshallException;

import org.json.JSONObject;

/**
 * @author Tomas Polesovsky
 */
public class LiferayJSONSerializer extends JSONSerializer {

	public LiferayJSONSerializer(LiferayJSONDeserializationWhitelist
		liferayJSONDeserializationWhitelist) {

		_liferayJSONDeserializationWhitelist =
			liferayJSONDeserializationWhitelist;
	}

	@Override
	public void registerSerializer(Serializer serializer) {
		if (serializer != null) {
			_liferayJSONDeserializationWhitelist.register(
				_toClassNames(serializer.getSerializableClasses()));
		}

		super.registerSerializer(serializer);
	}

	@Override
	protected Class getClassFromHint(Object object) throws UnmarshallException {
		if (object == null) {
			return null;
		}

		if (object instanceof JSONObject) {
			String className = StringPool.BLANK;

			try {
				JSONObject jsonObject = (JSONObject)object;

				className = jsonObject.getString("javaClass");

				if (!_liferayJSONDeserializationWhitelist.isWhitelisted(
						className)) {

					if (jsonObject.has("serializable")) {
						jsonObject.put(
							"map", jsonObject.remove("serializable"));
					}
					else {
						jsonObject.put("map", new JSONObject());
					}

					jsonObject.put("javaClass", "java.util.HashMap");

					return HashMap.class;
				}

				if (jsonObject.has("contextName")) {
					String contextName = jsonObject.getString("contextName");

					ClassLoader classLoader = ClassLoaderPool.getClassLoader(
						contextName);

					if (classLoader != null) {
						return Class.forName(className, true, classLoader);
					}

					if (_log.isWarnEnabled()) {
						_log.warn("Unable to get class loader for class " +
								className + " in context " + contextName);
					}
				}
			}
			catch (Exception e) {
				throw new UnmarshallException(
					"Unable to get class " + className, e);
			}
		}

		return super.getClassFromHint(object);
	}

	private static String[] _toClassNames(Class<?>[] classes) {
		String[] classNames = new String[classes.length];

		for (int i = 0; i < classes.length; i++) {
			classNames[i] = classes[i].getName();
		}

		return classNames;
	}

	private static final Log _log = LogFactoryUtil.getLog(
		LiferayJSONSerializer.class);

	private final LiferayJSONDeserializationWhitelist
		_liferayJSONDeserializationWhitelist;

}