/*
 * $RCSfile: ModelManager.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.
 */
 
/*
 * ModelSerManager.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.serialize.modelbus_xmi;

import java.io.IOException;
import java.util.Collection;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.Map;


import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.EAttribute;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EReference;
import org.eclipse.emf.ecore.xmi.XMIException;
import org.eclipse.mddi.modelbus.adapter.infrastructure.model_manipulation.ModelWrapper;
import org.eclipse.mddi.modelbus.adapter.infrastructure.model_manipulation.wrapper.emf.EmfModelWrapper;
import org.xml.sax.SAXException;

/**
 * @author P. Sriplakich
 *
 *
 */
public class ModelManager {
    
    static {
        ModelWrapper.addRegistry("EMF", new EmfModelWrapper());              
    }
    
    
	String format = "EMF";
	
	/**
     * A flatten collection containing elements that are managed by this ModelManager
	 */
    Collection model = new HashSet();
    
    IdTable idTable = new IdTable();
       
//    State previousState = null;
    
    
    public ModelManager() {
        setFormat("EMF");
    }
    
    public void clear() {
        model.clear();
        idTable.clear();
    }

    
//    /**
//     * Set the content to the specified model.
//     * 
//     * If the table is not empty, 
//     * the table's elements that do not exist in "model" are dropped.
//     * the "model"'s elements that do not exist in this table are assigned a new id.
//     * 
//     * @param model
//     * @return
//     * 
//     */
//    public void setContent(Collection model) {
//        this.model = model;  
//    }
    
//    /**
//     * Set the content by deserializing the specified model.
//     * If the table is not empty, it is cleared first.
//     * 
//     * @param serializedModel
//     * @return
//     * @throws XMIException
//     * @throws IOException
//     * @throws SAXException
//     * 
//     */
//    public void setContent(String serializedModel) throws SAXException, IOException, XMIException {
//        idTable.clear();
//        addContent(serializedModel);
//    }    
    
    
//    public void addContent(Collection model) {
//        idTable.addAll(model);
//    }
    
    /**
     * 
     * add content by deserializing the specified string.
     * 
     * @param serializedModel
     * @return a collection of created model elements
     * 
     * @throws SAXException
     * @throws IOException
     * @throws XMIException
     * 
     *
     */
    public Collection loadXMI(String serializedModel) throws SAXException, IOException, XMIException {
        MBXmiResource r = new MBXmiResource(URI.createURI("uri1"), idTable);
        ModelDeserializer deser = new ModelDeserializer(r);
        deser.setFormat(format);
        deser.deserialize(serializedModel);   
        model.addAll(deser.getCreatedModelElements());
        return deser.getCreatedModelElements();
    }
    
    
    /**
     * Obtain the model managed by this manager
     * 
     */    
    public Collection getManagedModel() {
        return model;
    }
    
    /**
     * Used for debugging
     * 
     */    
    public void printIds() {
      System.out.println(idTable.getIdSet());    
    }
    
    
//    /**
//     * Apply the XML diff to this model.
//     * 
//     */    
//    public void updateContentByDiff(String diff) throws SAXException, IOException, XMIException {
//        UpdaterByXmiDiff updater = new UpdaterByXmiDiff(idTable);
//        updater.update(diff);
//        Collection removedElements = idTable.getFragmentFromIds(updater.getRemovedElementIds());
//        removeElements(removedElements);
//    }
    
    
    /**
     * Update the specified fragment
     * with the new version (specified as XML string).
     * 
     * @param originalFragment the original fragment to be updated. 
     * The members of this collection will be modified (added/deleted elements)
     */    
    public void mergeWithXMI(Collection originalFragment, String xmi) throws SAXException, IOException, XMIException {
        //IdTable updatedCopyIdTable = new IdTable();
        MBXmiResource r = new MBXmiResource(URI.createURI("uri1"));
        ModelDeserializer deser = new ModelDeserializer(r);
        deser.setFormat(format);
        deser.deserialize(xmi);
        UpdaterByCopy updater = new UpdaterByCopy(idTable, originalFragment, 
                r.getIdTable(), deser.getCreatedModelElements());
        updater.update();
        
        // delete elements and the links to those elements        
        Collection removedElements = idTable.getFragmentFromIds(updater.getRemovedElementIds());
        removeElements(removedElements);    
        
        // change the member of collection
        originalFragment.clear();
        originalFragment.addAll(updater.getResultFragment());
    }    
    
    /**
     * TODO 
     * Delete the inbound links to the removed elements 
     * 
     * @param elements
     * 
     *
     */
    public void removeElements(Collection elements) {
        model.removeAll(elements);
        Map m = new Hashtable();       
        for(Iterator it = elements.iterator(); it.hasNext();) {
            
        }
    }
    
    
    
    /**
     * Exports the content in the serialized form
     * 
     */    
    public String exportToXMI() {
        return exportFragmentToXMI(model);
    }
    
    /**
     * Export the specified sub model as XML
     * 
     */
    public String exportFragmentToXMI(Collection fragment) {
        ModelSerializer ser = new ModelSerializer(idTable);
        return ser.serializeFragment(fragment);        
    }
    
   
    
//    /**
//     * Save the copy of the current model.
//     * It enables XML difference to be produced by comparing 
//     * the saved model with the modified model
//     * 
//     */
//    public void saveCurrentContent() {
//        saveCurrentContent(idTable.getModel());        
//    }
    
//    /**
//     * Save the copy of the specified sub model.
//     * Later, the modification made to sub model can be extracted
//     */    
//    public void saveCurrentContent(Collection fragment) {
//        IdTable t = copyIdTable(idTable, fragment);
//        Collection unmodifiableElements = idTable.getModel();
//        unmodifiableElements.removeAll(fragment);
//        previousState = new State(t, unmodifiableElements);
//    }
    
//    /**
//     * remove the saved content
//     * 
//     */    
//    public void clearPreviousContent() {
//        previousState = null;    
//    }
    
    
//    /**
//     * Compares the content with the given model.
//     * Then write the difference in the return value
//     * 
//     * @param model
//     * @param encodeRemovedElements
//     * @return
//     * 
//     */
//    public String exportAsDiff() {
//      if(previousState==null) {
//        throw new RuntimeException("No previous content");    
//      }
//      Collection updatedSubmodel = idTable.getModel();
//      updatedSubmodel.removeAll(previousState.unmodifiableFragment);
//      
//      ModelDiffSerializer ser = new ModelDiffSerializer(
//              previousState.fragmentTable ,previousState.fragmentTable.getModel()
//              ,idTable , updatedSubmodel ); 
//      return ser.serializeDiff();
//    }
    
//    /**
//     * Used for saveCurrentContent
//     * 
//     */
//    IdTable copyIdTable(IdTable srcTable, Collection fragment) {
//        IdTable resultTable = new IdTable();
//        Collection unresolvedLinks = new Vector();
//        for(Iterator it = fragment.iterator(); it.hasNext(); ) {
//            EObject srcElem = (EObject) it.next();
//            String id = srcTable.getId(srcElem);
//            EObject targetElem = copyModelElement(srcElem, srcTable, fragment, unresolvedLinks );
//            resultTable.assignId(id, targetElem);
//        } 
//        ModelDeserializer.UnresolvedLink.resolveLinks(unresolvedLinks, resultTable);
//        return resultTable;
//    }
    
//    /**
//     * Used for saveCurrentContent
//     * 
//     */
//    EObject copyModelElement(EObject src, IdTable idTable, Collection fragment, Collection unresolvedLinks) {
//        EClass c = src.eClass();
//        
//        ModelWrapper w = ModelWrapper.getRegistry(format);
//        if(w==null) throw new RuntimeException("no factory found " +format);        
//        EObject result = w.create(c);
//        // --------- for all attributes ----------------
//        for(Iterator it = src.eClass().getEAllAttributes().iterator(); it.hasNext(); ) {
//          EAttribute a = (EAttribute) it.next();
//          if(a.isDerived() || a.isTransient() || !a.isChangeable()) {
//            // do nothing
//          } else {              
//            Object v = src.eGet(a);
//            result.eSet(a, v);
//          }
//        }
//        // --------- for all references --------------------
//        for(Iterator it = src.eClass().getEAllReferences().iterator(); it.hasNext(); ) {
//          EReference r = (EReference) it.next();  
//          if(r.isDerived() || r.isTransient() || !r.isChangeable()) {
//              // do nothing          
//          } else  {
//              Object v = src.eGet(r);
//              if(! r.isMany()) {
//                  if(v!=null && fragment.contains(v)) {
//                     ModelDeserializer.Link l = new ModelDeserializer.Link(
//                        r, result,  idTable.getId((EObject) v)    
//                     );
//                     unresolvedLinks.add(l);
//                  }
//              } else {
//                  for(Iterator it2 = ((List)v).iterator(); it2.hasNext(); ) {
//                      EObject member = (EObject) it2.next();
//                      if(fragment.contains(member)) {
//                          ModelDeserializer.Link l = new ModelDeserializer.Link(
//                              r, result,  idTable.getId(member)    
//                           );
//                          unresolvedLinks.add(l);
//                      }
//                  }
//              }
//          }
//        } //--------- end for --------------        
//        return result;
//    }
//    
//    /**
//     * Store a copy of a sub model (or the whole model).
//     * Enables the production of XML diff.
//     */
//    static class State {
//        IdTable fragmentTable;
//        Collection unmodifiableFragment;
//        State(IdTable _fragmentTable, Collection _unmodifiableFragment) {
//            fragmentTable = _fragmentTable;  
//            unmodifiableFragment = _unmodifiableFragment;
//        }
//        
//    }



    
    /**
     * @return Returns the idTable.
     */
    public IdTable getIdTable() {
        return idTable;
    }
    
    
    
    /**
     * @return Returns the format.
     */
    public String getFormat() {
        return format;
    }
    /**
     * @param format The format to set.
     */
    public void setFormat(String format) {
        this.format = format;    
    }



}
