/*
 * Copyright (C) 2012 Issa Gorissen <issa-gorissen@usa.net>. All rights reserved.
 *
 * 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 org.jivesoftware.openfire.crowd;

import java.io.StringReader;
import java.util.concurrent.ConcurrentHashMap;

import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.jivesoftware.openfire.crowd.jaxb.User;
import org.jivesoftware.openfire.user.UserManager;
import org.jivesoftware.openfire.user.UserNotFoundException;
import org.jivesoftware.openfire.vcard.DefaultVCardProvider;
import org.jivesoftware.util.AlreadyExistsException;
import org.jivesoftware.util.NotFoundException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * VCard provider for Crowd.
 * 
 * <p>The name, email will be provided by crowd. All other information
 * can be managed by the XMPP client
 */
public class CrowdVCardProvider extends DefaultVCardProvider {
	private static final Logger LOG = LoggerFactory.getLogger(CrowdVCardProvider.class);
	
	private static final String VCARD_TEMPLATE
		= "<vCard xmlns=\"vcard-temp\"><FN>@displayname@</FN><N><FAMILY>@lastname@</FAMILY><GIVEN>@firstname@</GIVEN></N><NICKNAME>@nickname@</NICKNAME><EMAIL><USERID>@email@</USERID></EMAIL></vCard>";
	private static final ConcurrentHashMap<String, Object> MUTEX = new ConcurrentHashMap<>();

	/**
	 * @see org.jivesoftware.openfire.vcard.DefaultVCardProvider#loadVCard(java.lang.String)
	 */
	@Override
	public Element loadVCard(String username) {
		if (LOG.isDebugEnabled()) {
			LOG.debug("loadvcard:" + username);
		}
		
		if (MUTEX.containsKey(username)) {
			// preventing looping
			return null;
		}

		try {
			MUTEX.put(username, username);
			
			Element vcard = super.loadVCard(username);
			
			if (vcard == null) {
				CrowdUserProvider userProvider = (CrowdUserProvider) UserManager.getUserProvider();
				try {
					User user = userProvider.getCrowdUser(username);
					String str = VCARD_TEMPLATE.replace("@displayname@", user.displayName)
							.replace("@lastname@", user.lastName)
							.replace("@firstname@", user.firstName)
							.replace("@email@", user.email)
							.replace("@nickname@", username);
					
					SAXReader xmlReader = new SAXReader();
					xmlReader.setEncoding("UTF-8");
					
					vcard = xmlReader.read(new StringReader(str)).getRootElement();
					
				} catch (UserNotFoundException unfe) {
					LOG.error("Unable to find user:" + String.valueOf(username) + " for loading its vcard", unfe);
					return null;
				} catch (DocumentException de) {
					LOG.error("vcard parsing error", de);
					return null;
				}

				
				if (LOG.isDebugEnabled()) {
					LOG.debug(vcard != null ? vcard.asXML() : "vcard is null");
				}
				
				
				// store this new vcard
				if (vcard != null) {
					try {
						createVCard(username, vcard);
					} catch (AlreadyExistsException aee) {
						LOG.error("Unable to create and store a new vcard for user:" + username + "; one already exists", aee);
					}
				}
			}
			
			return vcard;

		} catch (RuntimeException re) {
			LOG.error("Failure occured when loading a vcard for user:" + username, re);
			throw re;
		} finally {
			MUTEX.remove(username);
		}
	}

	/**
	 * @see org.jivesoftware.openfire.vcard.DefaultVCardProvider#createVCard(java.lang.String, org.dom4j.Element)
	 */
	@Override
	public Element createVCard(String username, Element vCardElement) throws AlreadyExistsException {
		if (LOG.isDebugEnabled()) {
			LOG.debug("createvcard:" + vCardElement.asXML());
		}
		return super.createVCard(username, vCardElement);
	}

	/**
	 * @see org.jivesoftware.openfire.vcard.DefaultVCardProvider#updateVCard(java.lang.String, org.dom4j.Element)
	 */
	@Override
	public Element updateVCard(String username, Element vCard) throws NotFoundException {
		// make sure some properties have not been overridden
		Element nickNameNode = vCard.element("NICKNAME");
		Element displayNameNode = vCard.element("FN");
		
		Element nameNode = vCard.element("N");
		Element lastNameNode = nameNode.element("FAMILY");
		Element firstnameNode = nameNode.element("GIVEN");
		
		Element emailNode = vCard.element("EMAIL").element("USERID");
		
		CrowdUserProvider userProvider = (CrowdUserProvider) UserManager.getUserProvider();
		try {
			User user = userProvider.getCrowdUser(username);
			
			nickNameNode.setText(username);
			displayNameNode.setText(user.displayName);
			lastNameNode.setText(user.lastName);
			firstnameNode.setText(user.firstName);
			emailNode.setText(user.email);
			
		} catch (UserNotFoundException unfe) {
			LOG.error("Unable to find user:" + String.valueOf(username) + " for updating its vcard", unfe);
		}

		if (LOG.isDebugEnabled()) {
			LOG.debug("updatevcard:" + vCard.asXML());
		}

		return super.updateVCard(username, vCard);
	}
	
}
