/*
 * Copyright 2013 - 2013 Cole Wen
 *
 * 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.maodian.flyingcat.xmpp.state;

import java.lang.invoke.MethodHandles;
import java.util.Collection;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.Semaphore;

import org.maodian.flyingcat.xmpp.entity.JabberID;
import org.maodian.flyingcat.xmpp.entity.PersistedVisitee;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;


/**
 * @author Cole Wen
 *
 */
public class DefaultXmppContextManager extends AbstractXmppContextListener implements XmppContextManager {
  private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
  private final ConcurrentMap<String, ConcurrentMap<JabberID, XmppContext>> pool = new ConcurrentHashMap<>();
  private final Semaphore lock = new Semaphore(1);
  
  /* (non-Javadoc)
   * @see org.maodian.flyingcat.xmpp.state.XmppContextManager#getXmppContext(org.maodian.flyingcat.xmpp.entity.JabberID)
   */
  @Override
  public XmppContext getXmppContext(JabberID jid) {
    return pool.get(jid.getUid()).get(jid);
  }

  /* (non-Javadoc)
   * @see org.maodian.flyingcat.xmpp.state.XmppContextManager#getXmppContexts(java.lang.String)
   */
  @Override
  public Collection<XmppContext> getXmppContexts(String uid) {
    return pool.get(uid).values();
  }

  /* (non-Javadoc)
   * @see org.maodian.flyingcat.xmpp.state.XmppContextListener#onPostDestroy(org.maodian.flyingcat.xmpp.state.XmppContext)
   */
  @Override
  public void onPostDestroy(XmppContext ctx) {
    JabberID jid = ctx.getJabberID();
    log.debug("Post destroy of XmppContext for {}", jid);
    try {
      lock.acquire();
      ConcurrentMap<JabberID, XmppContext> m = pool.get(jid.getUid());
      m.remove(jid);
      if (m.size() == 0) {
        log.debug("No active XmppContext for uid {} anymore", jid.getUid());
        pool.remove(jid.getUid());
      }
    } catch (InterruptedException e) {
      throw new RuntimeException();
    } finally {
      lock.release();
    }
  }

  /* (non-Javadoc)
   * @see org.maodian.flyingcat.xmpp.state.XmppContextListener#onPostLogin(org.maodian.flyingcat.xmpp.state.XmppContext)
   */
  /*@Override
  public void onPostLogin(XmppContext ctx) {
    JabberID jid = ctx.getJabberID();
    log.debug("Post login of XmppContext for {}", jid);
    try {
      lock.acquire();
      ConcurrentMap<JabberID, XmppContext> m = pool.get(jid.getUid());
      if (m == null) {
        log.debug("No active XmppContext found for uid {}", jid.getUid());
        m = new ConcurrentHashMap<>();
        pool.put(jid.getUid(), m);
      }
      m.put(jid, ctx);
      log.debug("Complete post login of XmppContext");
    } catch (InterruptedException e) {
      throw new RuntimeException();
    } finally {
      lock.release();
    }
  }*/
  
  /* (non-Javadoc)
   * @see org.maodian.flyingcat.xmpp.state.AbstractXmppContextListener#onPostBind(org.maodian.flyingcat.xmpp.state.XmppContext)
   */
  @Override
  public void onPostBind(XmppContext ctx) {
    JabberID jid = ctx.getJabberID();
    log.debug("Post bind of XmppContext for {}", jid);
    try {
      lock.acquire();
      ConcurrentMap<JabberID, XmppContext> m = pool.get(jid.getUid());
      if (m == null) {
        log.debug("No connected XmppContext found for uid {}", jid.getUid());
        m = new ConcurrentHashMap<>();
        pool.put(jid.getUid(), m);
      }
      m.put(jid, ctx);
      log.debug("Complete post bind of XmppContext");
    } catch (InterruptedException e) {
      throw new RuntimeException();
    } finally {
      lock.release();
    }
  }

  /* (non-Javadoc)
   * @see org.maodian.flyingcat.xmpp.state.XmppContextManager#transfer(org.maodian.flyingcat.xmpp.entity.JabberID, org.maodian.flyingcat.xmpp.entity.JabberID, java.lang.Object)
   */
  @Override
  public void transfer(JabberID from, JabberID to, Object payload) {
    ConcurrentMap<JabberID, XmppContext> m = pool.get(to.getUid());
    log.info("Transfer payload {} from {} to {}", new Object[] {payload.getClass().getSimpleName(), from, to});
    if (m == null || m.size() == 0) {
      log.info("{} is not online", to);
      if (payload instanceof PersistedVisitee) {
        PersistedVisitee pv = (PersistedVisitee) payload;
        DefaultElementVisitor visitor = new DefaultElementVisitor();
        XmppContext ctx = getXmppContext(from);
        pv.acceptPersistedVisitor(ctx, visitor);
      } else {
        log.info("{} is not persistable", payload.getClass().getSimpleName());
      }
    } else {
      Collection<XmppContext> ctxs = m.values();
      for (XmppContext ctx : ctxs) {
        ctx.receive(from, payload);
      }
    }
    
  }
}

@@ -2600,796 +2600,8 @@
  %7D%0A%0A
-  /* (non-Javadoc)%0A   * @see org.maodian.flyingcat.xmpp.state.XmppContextListener#onPostLogin(org.maodian.flyingcat.xmpp.state.XmppContext)%0A   */%0A  /*@Override%0A  public void onPostLogin(XmppContext ctx) %7B%0A    JabberID jid = ctx.getJabberID();%0A    log.debug(%22Post login of XmppContext for %7B%7D%22, jid);%0A    try %7B%0A      lock.acquire();%0A      ConcurrentMap%3CJabberID, XmppContext%3E m = pool.get(jid.getUid());%0A      if (m == null) %7B%0A        log.debug(%22No active XmppContext found for uid %7B%7D%22, jid.getUid());%0A        m = new ConcurrentHashMap%3C%3E();%0A        pool.put(jid.getUid(), m);%0A      %7D%0A      m.put(jid, ctx);%0A      log.debug(%22Complete post login of XmppContext%22);%0A    %7D catch (InterruptedException e) %7B%0A      throw new RuntimeException();%0A    %7D finally %7B%0A      lock.release();%0A    %7D%0A  %7D*/%0A  %0A
   /*

remove the commented code