/*******************************************************************************
 * Copyright (c) 2002, 2008 IBM Corporation and others.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 * Rational Software - Initial API and implementation
 *******************************************************************************/
package org.eclipse.cdt.internal.core.model;

import java.util.HashMap;
import java.util.Map;

import org.eclipse.cdt.core.model.ICElement;
import org.eclipse.cdt.core.model.IOpenable;
import org.eclipse.cdt.internal.core.util.OverflowingLRUCache;

/**
 * The cache of C elements to their respective info.
 *
 * This class is similar to the JDT CModelCache class.
 */
public class CModelCache {
	public static final int PROJ_CACHE_SIZE = 50;
	public static final int FOLDER_CACHE_SIZE = 500;
	public static final int FILE_CACHE_SIZE = 2000;
	public static final int CHILDREN_CACHE_SIZE = FILE_CACHE_SIZE * 20;

	/**
	 * Cache of open projects and roots.
	 */
	protected Map<ICElement, Object> projectAndRootCache;

	/**
	 * Cache of open containers
	 */
	protected Map<ICElement, Object> folderCache;

	/**
	 * Cache of open translation unit files
	 */
	protected OverflowingLRUCache<IOpenable, Object> fileCache;

	/**
	 * Cache of children of C elements
	 */
	protected Map<ICElement, Object> childrenCache;

	public CModelCache() {
		this.projectAndRootCache = new HashMap<ICElement, Object>(PROJ_CACHE_SIZE);
		this.folderCache = new HashMap<ICElement, Object>(FOLDER_CACHE_SIZE);
		this.fileCache = new ElementCache<Object>(FILE_CACHE_SIZE);
		this.childrenCache = new HashMap<ICElement, Object>(CHILDREN_CACHE_SIZE); // average 20 children per openable
	}

	public double openableFillingRatio() {
		return this.fileCache.fillingRatio();
	}

	/**
	 *  Returns the info for the element.
	 */
	public Object getInfo(ICElement element) {
		switch (element.getElementType()) {
		case ICElement.C_MODEL:
		case ICElement.C_PROJECT:
			return this.projectAndRootCache.get(element);
		case ICElement.C_CCONTAINER:
			return this.folderCache.get(element);
		case ICElement.C_ARCHIVE:
		case ICElement.C_BINARY:
		case ICElement.C_UNIT:
			return this.fileCache.get(element);
		default:
			return this.childrenCache.get(element);
		}
	}

	/**
	 *  Returns the info for this element without
	 *  disturbing the cache ordering.
	 */
	protected Object peekAtInfo(ICElement element) {
		switch (element.getElementType()) {
		case ICElement.C_MODEL:
		case ICElement.C_PROJECT:
			return this.projectAndRootCache.get(element);
		case ICElement.C_CCONTAINER:
			return this.folderCache.get(element);
		case ICElement.C_ARCHIVE:
		case ICElement.C_BINARY:
		case ICElement.C_UNIT:
			return this.fileCache.peek((IOpenable) element);
		default:
			return this.childrenCache.get(element);
		}
	}

	/**
	 * Remember the info for the element.
	 */
	protected void putInfo(ICElement element, Object info) {
		switch (element.getElementType()) {
		case ICElement.C_MODEL:
		case ICElement.C_PROJECT:
			this.projectAndRootCache.put(element, info);
			break;
		case ICElement.C_CCONTAINER:
			this.folderCache.put(element, info);
			break;
		case ICElement.C_ARCHIVE:
		case ICElement.C_BINARY:
		case ICElement.C_UNIT:
			this.fileCache.put((IOpenable)element, info);
			break;
		default:
			this.childrenCache.put(element, info);
		}
	}

	/**
	 * Removes the info of the element from the cache.
	 */
	protected void removeInfo(ICElement element) {
		switch (element.getElementType()) {
		case ICElement.C_MODEL:
		case ICElement.C_PROJECT:
			this.projectAndRootCache.remove(element);
			break;
		case ICElement.C_CCONTAINER:
			this.folderCache.remove(element);
			break;
		case ICElement.C_ARCHIVE:
		case ICElement.C_BINARY:
		case ICElement.C_UNIT:
			this.fileCache.remove((IOpenable)element);
			break;
		default:
			this.childrenCache.remove(element);
		}
	}
}
