package com.beem.project.beem.otr;

import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.util.HashMap;
import java.util.Map;

import net.java.otr4j.OtrEngine;
import net.java.otr4j.OtrEngineHost;
import net.java.otr4j.OtrEngineImpl;
import net.java.otr4j.OtrEngineListener;
import net.java.otr4j.OtrPolicy;
import net.java.otr4j.OtrPolicyImpl;
import net.java.otr4j.session.SessionID;
import android.util.Log;

import com.beem.project.beem.service.ChatAdapter;

public class BeemOtrManager implements OtrEngineHost {

    private static final String TAG = "BeemOtrEngineHostImpl";
    private static final BeemOtrManager INSTANCE = new BeemOtrManager();
    
    private OtrEngine mOtrEngine = new OtrEngineImpl(INSTANCE);;

    //Map of chat, needed because of the message injection
    private final Map<SessionID, ChatAdapter> mChats = new HashMap<SessionID, ChatAdapter>();

    //We will have a global policy for Beem as long as we won't need to modify the policy per chat.
    private final OtrPolicy mGlobalPolicy = new OtrPolicyImpl(OtrPolicy.ALLOW_V2 | OtrPolicy.ERROR_START_AKE);

    private final OtrEngineListener mOtrListener = new BeemOtrListener();

    private Map<SessionID, KeyPair> mKeys = new HashMap<SessionID, KeyPair>();

    public OtrEngine getOtrManager() {
	return mOtrEngine;
    }

    // Private constructor prevents instantiation from other classes
    private BeemOtrManager() { 
	mOtrEngine.addOtrEngineListener(mOtrListener);
    }

    public static BeemOtrManager getInstance() {
	return INSTANCE;
    }

    /*
     * We must call addChat before stating a new otr session because we will need the chat instance for message injection
     */
    public void addChat(final SessionID sessionID, final ChatAdapter chat) {
	mChats.put(sessionID, chat);
    }

    /*
     * We must remove the chat from the map after we ended the corresponding otr session.
     */
    public void removeChat(final SessionID sessionID) {
	mChats.remove(sessionID);
    }

    @Override
    public void injectMessage(SessionID sessionID, String msg) {
	ChatAdapter chat = mChats.get(sessionID);
	chat.sendMessage(msg);		
    }

    @Override
    public void showWarning(SessionID sessionID, String warning) {
	Log.d(TAG, "Warning for "+sessionID + " : "+warning);
    }

    @Override
    public void showError(SessionID sessionID, String error) {
	Log.d(TAG, "Error for "+sessionID + " : "+error);
    }

    @Override
    public OtrPolicy getSessionPolicy(SessionID sessionID) {
	return mGlobalPolicy;
    }

    @Override
    public KeyPair getKeyPair(SessionID sessionID) {	
	KeyPair key = mKeys.get(sessionID);

	if (key == null) {
	    KeyPairGenerator kg;
	    try {
		kg = KeyPairGenerator.getInstance("DSA");
		key = kg.genKeyPair();
		mKeys.put(sessionID, key);
	    } catch (NoSuchAlgorithmException e) {
		e.printStackTrace();
		return null;
	    }
	}

	return key;
    }

    private class BeemOtrListener implements OtrEngineListener {

	@Override
	public void sessionStatusChanged(final SessionID sessionID) {
	    Log.d(TAG, "OTR Status changed for " + sessionID + " : " + mOtrEngine.getSessionStatus(sessionID));

	}
    }
}
