/*
 * Copyright (c) 2002-2003 IST-2004-2006-511731 ModelWare - ModelBus.
 * All rights reserved.
 *
 * This software is published under the terms of the ModelBus Software License
 * 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.
 * A copy of ModelBus Software License is provided with this distribution in
 * doc/LICENSE.txt file.
 */

/*
 * Created on 16 juin 2005
 *
 */
package org.eclipse.mddi.modelbus.adapter.infrastructure.model_manipulation;

import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;

import org.activemq.ws.xmlbeans.servicegroup.AddDocument.Add;
import org.eclipse.emf.common.notify.Adapter;
import org.eclipse.emf.common.notify.Notifier;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EStructuralFeature;




/**
 * @author Prawee Sriplakich (LIP6)
 *
 *
 */
public class ModelUtil {
    
    
    /**
     * Returns a set of elements that are direct instances of the specified metaclass.
     * The sybclass relation is not considerred.
     * 
     * @param emfobjs a collection of EObjects
     * @param typeName the name of the metaclass
     * @return
     * 
     * @see Add references
     *
     * TODO Add description
     */
    public static Collection findElementByType(Collection emfobjs, String typeName) {
       Collection set = new HashSet();     
       Iterator it = emfobjs.iterator();       
       while(it.hasNext()) {       
         EObject o =(EObject) it.next();
         if(o.eClass().getName().equals(typeName)) {
             set.add(o);    
           }     
       }
       return set;
    }
    
    
    
    
    
    public static Collection findElementByType_considerSubtypes(Collection emfobjs, EClass type) {
        Collection set = new HashSet();     
        Iterator it = emfobjs.iterator();       
        while(it.hasNext()) {       
          EObject o =(EObject) it.next();
          if(isInstanceOf(o, type)) {
              set.add(o);    
          }     
        }
        return set;        
    }
    
    public static boolean isInstanceOf(EObject o, EClass c) {
       EClass subc = o.eClass();
       if(subc.equals(c)) return true;
       if(subc.getEAllSuperTypes().contains(c)) return true;
       return false;
    }
    
    public static EObject findElementByName(Collection model, String name) {
        for(Iterator it=model.iterator(); it.hasNext(); ) {
            EObject o = (EObject) it.next();
            EStructuralFeature f = o.eClass().getEStructuralFeature("name"); 
            //findStructuralFeature(o.eClass(), "name");
            if(f!=null) {
              Object _name = o.eGet(f);    
              if(_name!=null && _name.equals(name)) {
                return o;    
              }
            }
        }
        return null;
    }    
    
    /**
     * 
     * findStructuralFeature
     * 
     * @param c
     * @param featureName
     * @return
     * @deprecated use EClass.getEStructuralFeature(String name) instead
     *
     */
    public static EStructuralFeature findStructuralFeature(EClass c, String featureName) {
        EStructuralFeature f = null;
        for(Iterator it=c.getEAllStructuralFeatures().iterator();it.hasNext(); ) {
            f = (EStructuralFeature) it.next();
            if(f.getName().equals(featureName)) {
              return f;    
            }
        }        
        return null;
    }	    
    
    
    
    /**
     * Returns a set containing elements in <code>emfobjs</code> 
     * and their subelements.
     * 
     * 
     * @param model
     * @return
     */
    public static Collection flattenHirachicalCollection(Collection model) {
        Collection target = new HashSet();
        Iterator it = model.iterator();       
        while(it.hasNext()) {       
          EObject o =(EObject) it.next();
          target.add(o);    
          Iterator it2 = o.eAllContents();
          while(it2.hasNext()) {
              EObject o2 =(EObject) it2.next();
              target.add(o2);   
          }       
        }
        return target;
    }

    
    
    /**
     * Find top-level elements in the <code>source</code> 
     * and put them in the return collection.
     * 
     * @param model
     * @return
     */    
    public static Collection getTopElements(Collection model) {
        Collection target = new HashSet();
	    Iterator it = model.iterator();
	    while(it.hasNext()) {
	        EObject o = (EObject) it.next();
	        EObject topElem = getTopElement(o);
	        if(!target.contains(topElem)) {
	          target.add(topElem);
	        }
	    }    
        return target;          
    }
    
    

    
    public static EObject getTopElement(EObject o) {
        EObject topElem = o;
        while(topElem.eContainer()!=null) {
            topElem = topElem.eContainer();
        }       
        return topElem;
    }
    
    
    
    
    /**
     * Check whether this collection contains only EObjects
     * 
     * @param c
     * @return false if there is one or more instances that are not EObjects
     * 		   true if all instances are EObjects or the collection is empty 
     */
    public static boolean isEObjectCollection(Collection c) {
	    Iterator it = c.iterator();
	    while(it.hasNext()) {
	        Object o = it.next();
	        if(!(o instanceof EObject)) {
	          return false;
	        }    
	    }
	    return true;        
    }




    public static Object getFeatureValue(EObject o, String featureName) {
      EStructuralFeature f = o.eClass().getEStructuralFeature(featureName); 
      //findStructuralFeature(o.eClass(), featureName);
      if(f==null) {
        return null;    
      }
      return o.eGet(f);    
    }




    public static Object createFromString(String primitiveType, String value) {
        if(primitiveType.equalsIgnoreCase("string")) {
          return value;   
        } else if (primitiveType.equalsIgnoreCase("boolean")) {
          return Boolean.valueOf(value);  
        } else if (primitiveType.equalsIgnoreCase("integer")) {
          return new Integer(Integer.parseInt(value));  
        } else if (primitiveType.equalsIgnoreCase("double")) {
          return new Double(Double.parseDouble(value));  
        }
        System.err.println("unknown primitive " + primitiveType);
        return null;
    }




    public static Collection getTopElemsInFragment(Collection fragment) {
      Collection result = new HashSet();
      for(Iterator it = fragment.iterator(); it.hasNext();) {
        EObject e = ModelUtil.getTopElemInFragment( (EObject)it.next() ,fragment);      
        result.add(e);
      }
      return result;
    }




    /**
     * Returns the top-most element that is included in this model.
     */
    public static EObject getTopElemInFragment(EObject currentElem, Collection fragment) {
        EObject topElem = currentElem;
        while(topElem.eContainer()!=null &&
                fragment.contains(topElem.eContainer()) ) {
              topElem = topElem.eContainer();    
        }
        return topElem;
    }





    /**
     * 
     * find an Adapter corresponding to a specified type
     * 
     * @param target
     * @param type
     * @return
     */
    public static Adapter findAdapter(Notifier target, Object type)
    {
      for (Iterator adapters = target.eAdapters().iterator(); adapters.hasNext(); )
      {
        Adapter adapter = (Adapter)adapters.next();
        if (adapter.isAdapterForType(type))
        {
          return adapter;
        }
      }
      return null;
    }

    
    
    
    

}
