/* ===================================================================
 * JAXBDomainObjectFactoryImpl.java
 * 
 * Created Sep 16, 2004 2:56:35 PM
 * 
 * Copyright (c) 2004 Matt Magoffin (spamsqr@msqr.us)
 * 
 * This program is free software; you can redistribute it and/or 
 * modify it under the terms of the GNU General Public License as 
 * published by the Free Software Foundation; either version 2 of 
 * the License, or (at your option) any later version.
 * 
 * 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
 * ===================================================================
 * $Id: JAXBDomainObjectFactoryImpl.java 74 2009-05-15 04:44:37Z msqr $
 * ===================================================================
 */

package magoffin.matt.ieat.biz.impl;

import java.util.Iterator;

import javax.xml.bind.JAXBException;

import magoffin.matt.ieat.biz.DomainObjectFactory;
import magoffin.matt.ieat.domain.AdvancedSearchCriteria;
import magoffin.matt.ieat.domain.Base;
import magoffin.matt.ieat.domain.Course;
import magoffin.matt.ieat.domain.Difficulty;
import magoffin.matt.ieat.domain.Ethnicity;
import magoffin.matt.ieat.domain.Ingredient;
import magoffin.matt.ieat.domain.Meal;
import magoffin.matt.ieat.domain.MealRecipe;
import magoffin.matt.ieat.domain.ObjectFactory;
import magoffin.matt.ieat.domain.PrepTime;
import magoffin.matt.ieat.domain.Recipe;
import magoffin.matt.ieat.domain.RecipeComment;
import magoffin.matt.ieat.domain.RecipeIngredient;
import magoffin.matt.ieat.domain.RecipeRating;
import magoffin.matt.ieat.domain.RecipeSearchCriteria;
import magoffin.matt.ieat.domain.RecipeStep;
import magoffin.matt.ieat.domain.System;
import magoffin.matt.ieat.domain.UiData;
import magoffin.matt.ieat.domain.UiEdit;
import magoffin.matt.ieat.domain.UiIndex;
import magoffin.matt.ieat.domain.UiIngredientMatch;
import magoffin.matt.ieat.domain.UiMetaSupport;
import magoffin.matt.ieat.domain.UiPaginationSupport;
import magoffin.matt.ieat.domain.UiParameter;
import magoffin.matt.ieat.domain.UiRecipeMatch;
import magoffin.matt.ieat.domain.UiSearchResults;
import magoffin.matt.ieat.domain.UiSessionData;
import magoffin.matt.ieat.domain.UiUserMatch;
import magoffin.matt.ieat.domain.Unit;
import magoffin.matt.ieat.domain.User;
import magoffin.matt.ieat.domain.UiIndex.IndexSectionType;
import magoffin.matt.ieat.domain.impl.BaseImpl;
import magoffin.matt.ieat.domain.impl.CourseImpl;
import magoffin.matt.ieat.domain.impl.DifficultyImpl;
import magoffin.matt.ieat.domain.impl.EditImpl;
import magoffin.matt.ieat.domain.impl.EthnicityImpl;
import magoffin.matt.ieat.domain.impl.IngredientImpl;
import magoffin.matt.ieat.domain.impl.MealImpl;
import magoffin.matt.ieat.domain.impl.MealRecipeImpl;
import magoffin.matt.ieat.domain.impl.PrepTimeImpl;
import magoffin.matt.ieat.domain.impl.RecipeCommentImpl;
import magoffin.matt.ieat.domain.impl.RecipeImpl;
import magoffin.matt.ieat.domain.impl.RecipeIngredientImpl;
import magoffin.matt.ieat.domain.impl.RecipeRatingImpl;
import magoffin.matt.ieat.domain.impl.RecipeSearchCriteriaImpl;
import magoffin.matt.ieat.domain.impl.RecipeStepImpl;
import magoffin.matt.ieat.domain.impl.SearchResultsImpl;
import magoffin.matt.ieat.domain.impl.SessionDataImpl;
import magoffin.matt.ieat.domain.impl.SystemImpl;
import magoffin.matt.ieat.domain.impl.UiImpl;
import magoffin.matt.ieat.domain.impl.UiIndexImpl;
import magoffin.matt.ieat.domain.impl.UiIngredientMatchImpl;
import magoffin.matt.ieat.domain.impl.UiMetaSupportImpl;
import magoffin.matt.ieat.domain.impl.UiPaginationSupportImpl;
import magoffin.matt.ieat.domain.impl.UiParameterImpl;
import magoffin.matt.ieat.domain.impl.UiRecipeMatchImpl;
import magoffin.matt.ieat.domain.impl.UiSearchResultsImpl;
import magoffin.matt.ieat.domain.impl.UiUserMatchImpl;
import magoffin.matt.ieat.domain.impl.UnitImpl;
import magoffin.matt.ieat.domain.impl.UserImpl;
import magoffin.matt.xweb.XAppContext;
import magoffin.matt.xweb.XwebParameter;

import org.springframework.beans.BeanUtils;

/**
 * Domain object factory implementation using JAXB domain objects.
 * 
 * @author Matt Magoffin (spamsqr@msqr.us)
 * @version $Revision: 74 $ $Date: 2009-05-15 16:44:37 +1200 (Fri, 15 May 2009) $
 */

public final class JAXBDomainObjectFactoryImpl implements DomainObjectFactory {
	
	/** List of Recipe property names not to copy during cloning. */
	private static final String[] RECIPE_DO_NOT_COPY_PROPERTIES = new String[] {
		"ingredientInternal","relatedRecipeInternal","stepInternal"
	};
	
	private static final ObjectFactory IEAT_OBJECT_FACTORY = new ObjectFactory();
	private static final magoffin.matt.xweb.ObjectFactory XWEB_OBJECT_FACTORY = 
		new magoffin.matt.xweb.ObjectFactory();
	
	public Object clone(Object original) {
	    if ( original == null ) {
	        return null;
	    }
	    Class<?> clazz = original.getClass();
		if ( Recipe.class.isAssignableFrom(clazz) ) {
		    return clone((Recipe)original);
		} else if ( Ingredient.class.isAssignableFrom(clazz) ) {
		    return clone((Ingredient)original);
		} else if ( RecipeStep.class.isAssignableFrom(clazz) ) {
		    return clone((RecipeStep)original);
		}
		
		throw new IllegalArgumentException("The object " +original.getClass() 
		        +" is not supported for cloneing.");
	}
	
	@SuppressWarnings("unchecked")
	private Recipe clone(Recipe original) {
		Recipe cloned = getRecipeInstance();

		// we can't copy the 'internal' lists created by HyperJAXB because
		// this will make both instances share the same List object
		BeanUtils.copyProperties(original,cloned,RECIPE_DO_NOT_COPY_PROPERTIES);
		
		for ( Iterator itr = original.getIngredient().iterator(); itr.hasNext(); ) {
			cloned.getIngredient().add(clone((RecipeIngredient)itr.next()));
		}
		for ( Iterator itr = original.getRelatedRecipe().iterator(); itr.hasNext(); ) {
			cloned.getRelatedRecipe().add(itr.next()); // not cloned
		}
		for ( Iterator itr = original.getStep().iterator(); itr.hasNext(); ) {
			cloned.getStep().add(clone((RecipeStep)itr.next()));
		}
		return cloned;
	}
	
	private RecipeIngredient clone(RecipeIngredient original) {
	    RecipeIngredient cloned = getRecipeIngredientInstance();
	    BeanUtils.copyProperties(original,cloned);
	    
	    // also clone nested ingredient if that's available
	    if ( original.getIngredient() != null ) {
	        cloned.setIngredient(clone(original.getIngredient()));
	    }
	    return cloned;
	}
	
	private Ingredient clone(Ingredient original) {
	    Ingredient cloned = getIngredientInstance();
	    BeanUtils.copyProperties(original,cloned);
	    return cloned;
	}
	
	private RecipeStep clone(RecipeStep original) {
	    RecipeStep cloned = getRecipeStepInstance();
	    BeanUtils.copyProperties(original,cloned);
	    return cloned;
	}
	
	public Recipe getRecipeInstance() {
		return new RecipeImpl();
	}
	public Base getBaseInstance() {
		return new BaseImpl();
	}
	public Course getCourseInstance() {
		return new CourseImpl();
	}
	public Difficulty getDifficultyInstance() {
		return new DifficultyImpl();
	}
	public Ethnicity getEthnicityInstance() {
		return new EthnicityImpl();
	}
	public PrepTime getPrepTimeInstance() {
		return new PrepTimeImpl();
	}
	public System getSystemInstance() {
		return new SystemImpl();
	}
	public User getUserInstance() {
		return new UserImpl();
	}
	public UiSearchResults getSearchResultsInstance() {
		return new SearchResultsImpl();
	}
	public UiIndex getIndexInstance() {
		return new UiIndexImpl();
	}
	public IndexSectionType getIndexSelectionTypeInstance() {
		return new UiIndexImpl.IndexSectionTypeImpl();
	}
	public UiData getUiDataInstance() {
		return new UiImpl();
	}
	public UiEdit getUiEditInstance() {
		return new EditImpl();
	}
	public Ingredient getIngredientInstance() {
		return new IngredientImpl();
	}
	public UiIngredientMatch getIngredientMatchInstance() {
		return new UiIngredientMatchImpl();
	}
	public RecipeSearchCriteria getRecipeCriteriaInstance() {
		return new RecipeSearchCriteriaImpl();
	}
	public UiRecipeMatch getRecipeMatchInstance() {
		return new UiRecipeMatchImpl();
	}
	public UiSessionData getUiSessionDataInstance() {
		return new SessionDataImpl();
	}
	public UiSearchResults getEmbeddedSearchResultsInstance() {
		return new UiSearchResultsImpl();
	}
	public Unit getUnitInstance() {
		return new UnitImpl();
	}
	public Meal getMealInstance() {
		return new MealImpl();
	}
	public MealRecipe getMealRecipeInstance() {
		return new MealRecipeImpl();
	}
	public RecipeIngredient getRecipeIngredientInstance() {
		return new RecipeIngredientImpl();
	}
	public RecipeStep getRecipeStepInstance() {
		return new RecipeStepImpl();
	}
	public RecipeComment getRecipeCommentInstance() {
		return new RecipeCommentImpl();
	}
	public RecipeRating getRecipeRatingInstance() {
		return new RecipeRatingImpl();
	}
	public UiUserMatch getUserMatchInstance() {
		return new UiUserMatchImpl();
	}
	public UiPaginationSupport getPaginationSupportInstance() {
		return new UiPaginationSupportImpl();
	}
	public UiMetaSupport getMetaSupportInstance() {
		return new UiMetaSupportImpl();
	}
	public UiParameter getParameterInstance() {
		return new UiParameterImpl();
	}
	public AdvancedSearchCriteria getAdvancedSearchCriteriaInstance() {
		try {
			return IEAT_OBJECT_FACTORY.createAdvancedSearchCriteria();
		} catch (JAXBException e) {
			throw new RuntimeException("Unable to create new object instance",e);
		}
	}
	
	public XAppContext newXAppContextInstance() {
		try {
			return XWEB_OBJECT_FACTORY.createXAppContext();
		} catch ( JAXBException e ) {
			throw new RuntimeException(e);
		}
	}

	public XwebParameter newXwebParameterInstance() {
		try {
			return XWEB_OBJECT_FACTORY.createXwebParameter();
		} catch ( JAXBException e ) {
			throw new RuntimeException(e);
		}
	}

}
