/*
 * Copyright (c) 2009, Takeyuki Nagao
 * All rights reserved.
 * 
 * Redistribution and use in source and binary forms, with or
 * without modification, are permitted provided that the
 * following conditions are met:
 * 
 *  * Redistributions of source code must retain the above
 *    copyright notice, this list of conditions and the
 *    following disclaimer.
 *  * Redistributions in binary form must reproduce the above
 *    copyright notice, this list of conditions and the
 *    following disclaimer in the documentation and/or other
 *    materials provided with the distribution.
 *    
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
 * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
 * OF SUCH DAMAGE.
 */

package jp.sourceforge.dvibrowser.dvicore.util.progress;

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

import jp.sourceforge.dvibrowser.dvicore.DviException;
import jp.sourceforge.dvibrowser.dvicore.api.DviContextSupport;


public class ProgressRecorder
extends AbstractProgressModel
{
  private final ArrayList<ManagedProgressItem> list = new ArrayList<ManagedProgressItem>();
  public ProgressRecorder(DviContextSupport dcs)
  {
    super(dcs);
  }
  
  protected void addInternal(ManagedProgressItem newWrappedItem)
  {
    if (newWrappedItem == null) return;
    synchronized(list) {
      list.add(newWrappedItem);
      while (list.size() > 0) {
        ManagedProgressItem wrappedItem = list.get(0);
        boolean remove = removeEldestElement(wrappedItem);
        if (!remove) break;
        list.remove(0);
      }
    }
  }
  
  protected List<ManagedProgressItem> getProgressItems() { return Collections.unmodifiableList(list); }
  
  protected boolean removeEldestElement(ManagedProgressItem item)
  {
    return false;
  }
  
  public void append(ProgressItem item)
  throws DviException
  {
    if (item == null) return;
    ManagedProgressItem wrappedItem = (ManagedProgressItem) open(item, 0, 0);
    wrappedItem.close();
  }
  
  public void append(String msg)
  throws DviException
  {
    append(new ProgressMessage(this, msg));
  }
  
  public ProgressItem open(String msg, int start, int end)
  throws DviException
  {
    ProgressItem item = new ProgressBlock(this, msg);
    return open(item, start, end);
  }

  public ProgressItem open(String msg)
  throws DviException
  {
    return open(msg, 0, 1);
  }

  protected ProgressItem open(ProgressItem item, int start, int end)
  throws DviException
  {
    if (start > end)
      throw new IllegalArgumentException
        ("Invalid value range: start=" + start + " end=" + end);
    ManagedProgressItem wrappedItem = new ManagedProgressItem(this, item);
    wrappedItem.open(start, end);
    addInternal(wrappedItem);
    return wrappedItem;
  }
  
  public ProgressItem getMostRecentItem()
  {
    ManagedProgressItem managedItem = null;
    synchronized(list) {
      int size = list.size();
      if (size != 0) 
        managedItem = list.get(size - 1);
    }
    if (managedItem != null) {
      return managedItem.getOriginalItem();
    }
    return null;
  }

  public ProgressItem [] getOpenItems()
  {
    ArrayList<ProgressItem> items = new ArrayList<ProgressItem>();
    synchronized(list) {
      for (ManagedProgressItem wrappedItem : list) {
        if (wrappedItem.isOpen())
          items.add(wrappedItem.getOriginalItem());
      }
    }
    return items.toArray(new ProgressItem[items.size()]);
  }

  public ProgressItem [] getItems()
  {
    ArrayList<ProgressItem> items = new ArrayList<ProgressItem>();
    synchronized(list) {
      for (ManagedProgressItem wrappedItem : list) {
          items.add(wrappedItem.getOriginalItem());
      }
    }
    return items.toArray(new ProgressItem[items.size()]);
  }
}
