/******************************************************************************
 * Product: ADempiere ERP & CRM Smart Business Solution                       *
 * Copyright (C) 2009 www.metas.de                                            *
 * This program is free software; you can redistribute it and/or modify it    *
 * under the terms version 2 of the GNU General Public License as published   *
 * by the Free Software Foundation. This program is distributed in the hope   *
 * that it will be useful, but WITHOUT ANY WARRANTY; without even the implied *
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.           *
 * See the GNU General Public License for more details.                       *
 * You should have received a copy of the GNU General Public License along    *
 * with this program; if not, write to the Free Software Foundation, Inc.,    *
 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.                     *
 *****************************************************************************/
package org.adempiere.model;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.logging.Level;

import org.compiere.model.MQuery;
import org.compiere.model.PO;
import org.compiere.util.CLogger;

/**
 * Static factory methods for zoom info
 * @author Tobias Schoeneberg, www.metas.de - FR [ 2897194 ] Advanced Zoom and
 *         RelationTypes
 */
public class ZoomInfoFactory {

	/**
	 * Simple class that contains zoom information. Currently used by
	 * {@link org.adempiere.webui.WZoomAcross}.
	 * 
	 * @author ts
	 * 
	 */
	public static final class ZoomInfo {

		public final String destinationDisplay;
		public final MQuery query;
		public final int windowId;

		public ZoomInfo(int windowId, MQuery query, String destinationDisplay) {
			this.windowId = windowId;
			this.query = query;
			this.destinationDisplay = destinationDisplay;
		}

		@Override
		public String toString() {

			final StringBuilder sb = new StringBuilder();
			sb.append("ZoomInfo[");
			sb.append("Display=");
			sb.append(destinationDisplay);
			sb.append(", AD_Window_ID=").append(windowId);
			sb.append(", RecordCount=").append(
					query == null ? "<no query>" : query.getRecordCount());
			sb.append("]");
			return sb.toString();
		}
	}

	private static final CLogger logger = CLogger
			.getCLogger(ZoomInfoFactory.class);

	/**
	 * Adds {@link ZoomInfo} instances from {@link MRelationType}s and
	 * {@link GenericZoomProvider}.
	 * <p>
	 * First it looks for matching {@link MRelationType} instances and adds
	 * their {@link MRelationType#retrieveZoomInfos(PO)} results. Then it adds
	 * the {@link GenericZoomProvider}'s results unless there is already one
	 * from a MRelationType that has an quals
	 * {@link ZoomInfo#destinationDisplay} value.
	 * 
	 * @param po
	 * @param windowID
	 * @return matching zoom info records
	 */
	public static List<ZoomInfoFactory.ZoomInfo> retrieveZoomInfos(final PO po,
			final int windowID) {

		if (logger.isLoggable(Level.CONFIG)) logger.config("PO=" + po + " - AD_Window_ID=" + windowID);

		final List<ZoomInfoFactory.ZoomInfo> result = new ArrayList<ZoomInfoFactory.ZoomInfo>();

		final Set<String> alreadySeen = new HashSet<String>();

		for (final ZoomInfo zoomInfo : MRelationType.retrieveZoomInfos(po,
				windowID)) {
			
			if (alreadySeen.add(zoomInfo.destinationDisplay + "|" + zoomInfo.windowId)) {
				
				if (logger.isLoggable(Level.FINE)) logger.fine("Adding zoomInfo " + zoomInfo);
				result.add(zoomInfo);
			}
		}

		final GenericZoomProvider genericZoomProvider = new GenericZoomProvider();

		for (final ZoomInfo zoomInfo : genericZoomProvider
				.retrieveZoomInfos(po)) {

			if (alreadySeen.add(zoomInfo.destinationDisplay + "|" + zoomInfo.windowId)) {

				if (logger.isLoggable(Level.FINE)) logger.fine("Adding zoomInfo " + zoomInfo + " from "
						+ GenericZoomProvider.class.getSimpleName());
				result.add(zoomInfo);

			} else {

				if (logger.isLoggable(Level.FINE)) logger.fine("Skipping zoomInfo " + zoomInfo + " from "
						+ GenericZoomProvider.class.getSimpleName()
						+ " because there is already one for destination '"
						+ zoomInfo.destinationDisplay + "'");
			}
		}

		return result;
	}
}
