/*
 * $RCSfile: Uml2ModelUtil.java,v $
 * $Date: 2006/01/26 14:48:59 $
 * $Revision: 1.1.2.2 $
 * $Author: andreys $
 */
 
/*
 * 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.
 */
 
/*
 * Uml2ProfileManager.java Add description 
 * 
 * @author Prawee Sriplakich
 * @version $Revision: 1.1.2.2 $ $Date: 2006/01/26 14:48:59 $
 * @see Add references
 *
 * TODO Add description
 * TODO Add references
 */
package org.eclipse.mddi.modelbus.adapter.infrastructure.model_manipulation.uml2;

import java.io.IOException;
import java.util.Iterator;

import org.apache.log4j.Logger;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.EAnnotation;
import org.eclipse.emf.ecore.EPackage;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.resource.ResourceSet;
import org.eclipse.emf.ecore.resource.URIConverter;
import org.eclipse.mddi.modelbus.adapter.infrastructure.model_manipulation.ModelBusResourceSet;
import org.eclipse.mddi.modelbus.adapter.infrastructure.model_manipulation.ModelUtil;
import org.eclipse.mddi.modelbus.adapter.infrastructure.model_manipulation.ModelBusResourceSet.GlobalResourceException;
import org.eclipse.uml2.Model;
import org.eclipse.uml2.Profile;
import org.eclipse.uml2.impl.UML2PackageImpl;
import org.eclipse.uml2.util.UML2Resource;


/**
 * @author P. Sriplakich
 *
 *
 */
public class Uml2ModelUtil {
    
   static Logger logger = Logger.getLogger("Uml2ModelUtil");

   public static String PREFIX_UML_PROFILE = "pathmap://ModelBus/UML2Profile/";
    
   /**
    * Set the URI for loading UML2 resources such as 
    * UML metamodel, UML basic profile, UML primitive types
    * <br>
    * Example of umlResourceURI is 
    * "jar:file:/D:/eclipse3.1.1/plugins/org.eclipse.uml2.resources_1.1.0.jar!/"
    * where this jar comes from UML2 plugin
    * 
    */
   public static void init(URI umlResourceURI) {
       registerPathmaps(umlResourceURI);
   }
 
   /**
    * Mapping logical URIs to the UML resource files (in the jar file)
    * For example, 
    * pathmap://UML2_METAMODELS/
    *    -> jar:file:/D:/eclipse3.1.1/plugins/org.eclipse.uml2.resources_1.1.0.jar!/metamodels/
    *    
    * Copied from the "Introduction to UML2 Profile" article
    */
   static void registerPathmaps(URI umlResourceURI) {
        URIConverter.URI_MAP.put(URI.createURI(UML2Resource.LIBRARIES_PATHMAP),
            umlResourceURI.appendSegment("libraries").appendSegment(""));

        URIConverter.URI_MAP.put(
            URI.createURI(UML2Resource.METAMODELS_PATHMAP), umlResourceURI.appendSegment(
                "metamodels").appendSegment(""));

        URIConverter.URI_MAP.put(URI.createURI(UML2Resource.PROFILES_PATHMAP),
            umlResourceURI.appendSegment("profiles").appendSegment(""));
    }   
   
   static {
       UML2PackageImpl.init();	

	   Resource.Factory.Registry.INSTANCE.getExtensionToFactoryMap().put(
				UML2Resource.FILE_EXTENSION, UML2Resource.Factory.INSTANCE);   
       
   
   }

   // this method is currently unused.
   public static Profile getRegisteredProfile(String profileName) {
       URI uri = createProfileGlobalURI(profileName);       
       Resource r = ModelBusResourceSet.getGlobalResourceRegistry().getResource( uri );
       Profile prof = (Profile) ModelUtil.findElementByName(r.getContents(), profileName);
       return prof;    
   }   
   
   /**
    * 
    * Convenient method for loading a profile definition from an XMI file.
    * There should be only one profile per XMI file.
    * 
    * @param uri the URI referencing the XMI file to be loaded
    * @return the registerred profile
    * @throws IOException
    * 
    *
    */
   public static Profile registerProfile(URI uri) throws IOException {
       ResourceSet rs = new ModelBusResourceSet();
       Resource r = rs.createResource(uri);
       r.load(null);
       for(Iterator it = r.getContents().iterator(); it.hasNext();) {
          Object o = it.next();
          if(o instanceof Profile) {
            Profile prof = (Profile)o;
            registerProfile(prof);
            return prof;
          }
       }
       return null;
   }
   

   
   /**
    * 
    * Declare the profile to be managed by ModelBus.
    * When the profiles are managed by ModelBus, 
    * the models that uses those profiles will be transmitted correctly.
    * (No lost of information about profile)
    * 
    * @param prof
    * 
    */
   public static void registerProfile(Profile prof) {
       URI uri = createProfileGlobalURI(prof.getName());
       Resource r = prof.eResource();
       if(r==null) {
         r = createContainerResource(prof);
       }
       try {
          ModelBusResourceSet.getGlobalResourceRegistry().registerResource(uri, r);
       } catch (GlobalResourceException e) {
          logger.error("registerProfile", e);
       }
       registerEcorePackagesOfProfile(prof);
   } 
   
   /**
    * Register the Ecore packages that are used for instanciating Profile stereotypes (tag values) 
    * in the UML instance models. 
    * <br>
    * This method is called through registerProfile(...).
    * No need to call it directly.
    * 
    * @param prof A profile
    * 
    */
   public static void registerEcorePackagesOfProfile(Profile prof) {
       EAnnotation anno = null;
       for(Iterator it=prof.getEAnnotations().iterator(); it.hasNext();) {
         anno =(EAnnotation) it.next();
         if("ePackages".equals(anno.getSource())) {
           break;
         }
       }        
       for(Iterator it=anno.getContents().iterator(); it.hasNext();) {        
         EPackage ep = (EPackage)it.next();
         EPackage.Registry.INSTANCE.put(ep.getNsURI(), ep);
       }   
   }
   
   
   /**
    * This operation is used for facilitating the loading of a UML model with profiles from XMI.
    * Generally, The XMI files of UML models reference profiles with file URIs.
    * However, the UML profiles can be saved in multiple copies (multiple file names).
    * 
    * For example, the XMI file of model M1 references profile Prof1 with the file URI "File1".
    * The XMI file of model M2 also references another copy of Prof1 with the file URI "File2".
    * You should set aliases File1->Prof1 and File2->Prof1.
    * Consequently, when you ask ModelBus to load M1 and M2 (using ModelBusResourceSet),
    * ModelBus will resolve the references (M1->Prof1) (M2->Prof1) to the same profile object.
    * Note that, without aliasing, Prof1 will be loaded twice 
    * (once for resolving the reference from M1 and another time for M2) 
    * 
    *
    */
   public static void setAliasURIToProfile(URI aliasURI, Profile prof) {
       ModelBusResourceSet
       .getGlobalResourceRegistry()
       .getURIConverter().getURIMap().put(aliasURI, prof.eResource().getURI());
   
   }
      
   
//   /**
//    * 
//    * Assigne a normalized URI to each profile in the model to be transmitted, 
//    * so that the profiles can be easily identified at the receiver side.
//    * This URI will be used for locating the Profile objects (in memory) at the receiver side 
//    * and linking those objects with the transmitted model 
//    * 
//    * @param umlModel a UML Package that uses profiles
//    * 
//    */
//   static void normalizeProfileURI(Package umlModel) {
//      for(Iterator it=umlModel.getAllAppliedProfiles().iterator(); it.hasNext();) {
//          Profile prof = (Profile) it.next();
//          Resource r = prof.eResource();
//          if(r==null) {
//             r = createContainerResource(prof);              
//          } else {
//             r.setURI(URI.createURI( PREFIX_UML_PROFILE + prof.getName() ));    
//          }
//      }
//   }
   
   
   static Resource createContainerResource(Profile prof) {
       ResourceSet rs = new ModelBusResourceSet();
       Resource r = rs.createResource( createProfileGlobalURI(prof.getName()) );
       r.getContents().add(prof);    
       return r;
   }
   
   static URI createProfileGlobalURI(String profileName) {
       return URI.createURI(PREFIX_UML_PROFILE + profileName +".profile.uml2");
   }

public static boolean hasLink(Model umlModel, Profile profile) {
    for (Iterator it = umlModel.getAllAppliedProfiles().iterator(); it
            .hasNext();) {
        Profile prof1 = (Profile) it.next();
        if (prof1.equals(profile)) {
            System.out.println("OK: model is linked to " + profile);
            return true;
        }
    }
    System.out.println("Not ok: model is not linked to " + profile);
    return false;
}
 
   
   
    
    
}
