package com.beem.project.beem.service;

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

import org.jivesoftware.smack.PrivacyList;
import org.jivesoftware.smack.PrivacyListListener;
import org.jivesoftware.smack.PrivacyListManager;
import org.jivesoftware.smack.XMPPConnection;
import org.jivesoftware.smack.XMPPException;
import org.jivesoftware.smack.packet.PrivacyItem;

import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.util.Log;

import com.beem.project.beem.service.aidl.IPrivacyListListener;
import com.beem.project.beem.service.aidl.IPrivacyListManager;

/**
 * An adapter for the Smack's PrivacyListManager.
 * @author Jean-Manuel Da Silva <dasilvj at beem-project dot com>
 */
public class PrivacyListManagerAdapter extends IPrivacyListManager.Stub {

    /**
     * Class's Tag.
     */
    public static final String TAG = "PrivacyListManagerAdapter";

    private final XMPPConnection mXmppConnection;
    private final PrivacyListManager mPrivacyListManager;

    private final RemoteCallbackList<IPrivacyListListener> mPrivacyListListeners = new RemoteCallbackList<IPrivacyListListener>();
    private final PrivacyListListenerAdapter mPrivacyListListener = new PrivacyListListenerAdapter();

    /**
     * Constructor.
     * @param connection The XMPP connection that will be used by the PrivacyListManagerAdapter.
     */
    public PrivacyListManagerAdapter(final XMPPConnection connection) {
	mXmppConnection = connection;
	mPrivacyListManager = PrivacyListManager.getInstanceFor(mXmppConnection);
	mPrivacyListManager.addListener(mPrivacyListListener);
    }

    @Override
    public void blockUser(String listName, String jid) throws RemoteException {
    }

    @Override
    public void createPrivacyList(String listName, List<PrivacyListItem> items) throws RemoteException {
	try {
	    mPrivacyListManager.createPrivacyList(listName, tranformPrivacyListItemsToPrivacyItems(items));
	} catch (XMPPException e) {
	    Log.e(TAG, e.getMessage());
	}
    }

    @Override
    public void declineActivePrivacyList() throws RemoteException {
	try {
	    mPrivacyListManager.declineActiveList();
	} catch (XMPPException e) {
	    Log.e(TAG, e.getMessage());
	}
    }

    @Override
    public void declineDefaultPrivacyList() throws RemoteException {
	try {
	    mPrivacyListManager.declineDefaultList();
	} catch (XMPPException e) {
	    Log.e(TAG, e.getMessage());
	}
    }

    @Override
    public void editPrivacyList(String listName, List<PrivacyListItem> items) throws RemoteException {
	try {
	    mPrivacyListManager.updatePrivacyList(listName, tranformPrivacyListItemsToPrivacyItems(items));
	} catch (XMPPException e) {
	    Log.e(TAG, e.getMessage());
	}
    }

    @Override
    public String getActivePrivacyList() throws RemoteException {
	try {
	    PrivacyList activePrivacyList = mPrivacyListManager.getActiveList();
	    return activePrivacyList.toString();
	} catch (XMPPException e) {
	    Log.e(TAG, e.getMessage());
	}
	return null;
    }

    @Override
    public List<String> getBlockedGroupsByList(String listName) throws RemoteException {
	List<String> blockedGroups = new ArrayList<String>();
	try {
	    PrivacyList pL = mPrivacyListManager.getPrivacyList(listName);
	    for (PrivacyItem pI : pL.getItems()) {
		if (pI.getType().equals(PrivacyItem.Type.group) && !pI.isAllow())
		    blockedGroups.add(pI.getValue());
	    }
	} catch (XMPPException e) {
	    Log.e(TAG, e.getMessage());
	}
	return blockedGroups;
    }

    @Override
    public List<String> getBlockedUsersByList(String listName) throws RemoteException {
	List<String> blockedUsers = new ArrayList<String>();
	try {
	    PrivacyList pL = mPrivacyListManager.getPrivacyList(listName);
	    for (PrivacyItem pI : pL.getItems()) {
		if (pI.getType().equals(PrivacyItem.Type.jid) && !pI.isAllow())
		    blockedUsers.add(pI.getValue());
	    }
	} catch (XMPPException e) {
	    Log.e(TAG, e.getMessage());
	}
	return blockedUsers;
    }

    @Override
    public String getDefaultPrivacyList() throws RemoteException {
	try {
	    PrivacyList defaultPrivacyList = mPrivacyListManager.getDefaultList();
	    return defaultPrivacyList.toString();
	} catch (XMPPException e) {
	    Log.e(TAG, e.getMessage());
	}
	return null;
    }

    @Override
    public void removePrivacyList(String listName) throws RemoteException {
	try {
	    mPrivacyListManager.deletePrivacyList(listName);
	} catch (XMPPException e) {
	    Log.e(TAG, e.getMessage());
	}
    }

    @Override
    public void setActivePrivacyList(String listName) throws RemoteException {
	try {
	    mPrivacyListManager.setActiveListName(listName);
	} catch (XMPPException e) {
	    Log.e(TAG, e.getMessage());
	}
    }

    @Override
    public void setDefaultPrivacyList(String listName) throws RemoteException {
	try {
	    mPrivacyListManager.setDefaultListName(listName);
	} catch (XMPPException e) {
	    e.getMessage();
	}
    }

    /**
     * From a List of PrivacyListItem get a List of PrivacyItem.
     * @param items The List of PrivacyListItem.
     * @return A list of PrivacyItem.
     */
    private List<PrivacyItem> tranformPrivacyListItemsToPrivacyItems(List<PrivacyListItem> items) {
	List<PrivacyItem> rItems = new ArrayList<PrivacyItem>();
	PrivacyItem.Type[] itemTypes = PrivacyItem.Type.values();

	for (int i = 0; i < items.size(); i++) {
	    rItems.add(new PrivacyItem(itemTypes[items.get(i).getType()].name(), false, i));
	}

	return rItems;
    }

    /**
     * From a List of PrivacyItem get a List of PrivacyListItem.
     * @param items The List of PrivacyItem.
     * @return A list of PrivacyListItem.
     */
    private List<PrivacyListItem> tranformPrivacyItemsToPrivacyListItems(List<PrivacyItem> items) {
	List<PrivacyListItem> rItems = new ArrayList<PrivacyListItem>();
	PrivacyItem.Type[] itemTypes = PrivacyItem.Type.values();

	for (int i = 0; i < items.size(); i++) {
	    rItems.add(new PrivacyListItem(items.get(i).getType().ordinal(), items.get(i).getValue()));
	}
	return rItems;
    }

    /**
     * An adapter for the Smack's PrivacyListListener.
     * @author Jean-Manuel Da Silva <dasilvj at beem-project dot com>
     */
    private class PrivacyListListenerAdapter implements PrivacyListListener {

	@Override
	public void setPrivacyList(String listName, List<PrivacyItem> listItem) {
	    final int n = mPrivacyListListeners.beginBroadcast();
	    for (int i = 0; i < n; i++) {
		IPrivacyListListener listener = mPrivacyListListeners.getBroadcastItem(i);
		try {
		    listener.setPrivacyList(listName, tranformPrivacyItemsToPrivacyListItems(listItem));
		} catch (RemoteException e) {
		    Log.w(TAG, e.getMessage());
		}
	    }
	    mPrivacyListListeners.finishBroadcast();
	}

	@Override
	public void updatedPrivacyList(String listName) {
	    final int n = mPrivacyListListeners.beginBroadcast();
	    for (int i = 0; i < n; i++) {
		IPrivacyListListener listener = mPrivacyListListeners.getBroadcastItem(i);
		try {
		    listener.updatedPrivacyList(listName);
		} catch (RemoteException e) {
		    Log.w(TAG, e.getMessage());
		}
	    }
	    mPrivacyListListeners.finishBroadcast();
	}
    }

    @Override
    public void addPrivacyListListener(IPrivacyListListener listener) throws RemoteException {
	if (listener != null)
	    mPrivacyListListeners.register(listener);
    }

    @Override
    public void removePrivacyListListener(IPrivacyListListener listener) throws RemoteException {
	if (listener != null)
	    mPrivacyListListeners.unregister(listener);
    }

    @Override
    public List<String> getPrivacyLists() throws RemoteException {
	List<String> res = new ArrayList<String>();
	try {
	    PrivacyList[] serverPrivacyLists = mPrivacyListManager.getPrivacyLists();
	    if (serverPrivacyLists.length > 0) {
		for (int i = 0; i < serverPrivacyLists.length; i++)
		    res.add(serverPrivacyLists[i].toString());
	    }
	} catch (XMPPException e) {
	    Log.e(TAG, e.getMessage());
	}
	return res;
    }
}
