/*
 * The contents of this file are subject to the Mozilla Public License
 * Version 1.1 (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.mozilla.org/MPL/
 *
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
 * the specific language governing rights and limitations under the License.
 *
 * The Original Code is Protege-2000.
 *
 * The Initial Developer of the Original Code is Stanford University. Portions
 * created by Stanford University are Copyright (C) 2007.  All Rights Reserved.
 *
 * Protege was developed by Stanford Medical Informatics
 * (http://www.smi.stanford.edu) at the Stanford University School of Medicine
 * with support from the National Library of Medicine, the National Science
 * Foundation, and the Defense Advanced Research Projects Agency.  Current
 * information about Protege can be obtained at http://protege.stanford.edu.
 *
 */

package edu.stanford.smi.protege.server.framestore.background;

import java.util.HashSet;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;

import edu.stanford.smi.protege.model.Frame;
import edu.stanford.smi.protege.server.RemoteSession;
import edu.stanford.smi.protege.server.framestore.RemoteServerFrameStore;
import edu.stanford.smi.protege.util.Log;

public class ClientCacheRequestor {
  Logger log = Log.getLogger(ClientCacheRequestor.class);
  
  public enum ThreadStatus {
    IDLE, RUNNING, SHUTDOWN
  }
  private Set<Frame> frames  = new HashSet<Frame>();
  private Set<Frame> framesWithDirectInstances = new HashSet<Frame>();
  private Object lock = new Object();
  private RequestorThread th = null;
  private RemoteServerFrameStore delegate;
  private RemoteSession session;
  
  public ClientCacheRequestor(RemoteServerFrameStore delegate, RemoteSession session) {
    this.delegate = delegate;
    this.session = session;
  }
  
  public void requestFrameValues(Set<Frame> frames, boolean skipDirectInstances) {
    synchronized (lock) {
      if (skipDirectInstances)  {
        this.frames.addAll(frames);
      } else {
        framesWithDirectInstances.addAll(frames);
      }
      if (th == null || th.getStatus() == ThreadStatus.SHUTDOWN) {
        th = new RequestorThread();
        th.start();
      }
    }
  }
  
  public class RequestorThread extends Thread {
    private ThreadStatus status = ThreadStatus.IDLE;
    
    public void run() {
      synchronized (lock) {
        status = ThreadStatus.RUNNING;
      }
      while (true) {
        Set<Frame> workingFrames = null;
        Set<Frame> workingFramesWithDirectInstances = null;
        synchronized(lock) {
          if (frames.isEmpty() && framesWithDirectInstances.isEmpty()) {
            status = ThreadStatus.SHUTDOWN;
            return;
          } 
          if (!frames.isEmpty()) {
            workingFrames = frames;
            frames = new HashSet<Frame>();
          }
          if (!framesWithDirectInstances.isEmpty()) {
            workingFramesWithDirectInstances = framesWithDirectInstances;
            framesWithDirectInstances = new HashSet<Frame>();
          }
        }
        try {
          if (log.isLoggable(Level.FINE)) {
            log.fine("Sending frames " + workingFrames + " / " + workingFramesWithDirectInstances);
          }
          if (workingFrames != null) {
            delegate.requestValueCache(workingFrames, true, session);
          }
          if (workingFramesWithDirectInstances != null) {
            delegate.requestValueCache(workingFramesWithDirectInstances, false, session);
          }
          
        } catch (Exception e) {
          Log.emptyCatchBlock(e);
        }
      }   
    }
    
    public ThreadStatus getStatus() {
      synchronized (lock) {
        return status;
      }
    }
  }

}
