/*
 * $RCSfile: CopyRestoreFragmentMarshaler.java,v $
 * $Date: 2006/01/26 14:48:59 $
 * $Revision: 1.1.2.3 $
 * $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.
 */
 
/*
 * CopyRestoreFragmentModelMarshaler.java Add description 
 * 
 * @author Prawee Sriplakich
 * @version $Revision: 1.1.2.3 $ $Date: 2006/01/13 16:57:1org.eclipse.mddi.modelbus.adapter.infrastructure.transport.marshal.ws references
 */
package org.eclipse.mddi.modelbus.adapter.infrastructure.transport.marshal.ws;

import java.io.IOException;
import java.util.Collection;
import java.util.Iterator;
import java.util.Properties;
import java.util.StringTokenizer;
import java.util.Vector;

import javax.xml.soap.SOAPElement;
import javax.xml.soap.SOAPException;

import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.xmi.XMIException;
import org.eclipse.mddi.modelbus.adapter.infrastructure.model_manipulation.ModelUtil;
import org.eclipse.mddi.modelbus.adapter.infrastructure.model_manipulation.ModelWrapper;
import org.eclipse.mddi.modelbus.adapter.infrastructure.serialize.modelbus_xmi.ModelManager;
import org.eclipse.mddi.modelbus.adapter.user.AdapterStub;
import org.eclipse.mddi.modelbus.description.abstract_.DirectionKind;
import org.eclipse.mddi.modelbus.description.abstract_.Parameter;
import org.xml.sax.SAXException;

public class CopyRestoreFragmentMarshaler extends AbstractMarshaler {

    public static final String INOUT_SCOPE  = "MODELBUS_INOUT_SCOPE";
    public static final String OUT_SCOPE = "MODELBUS_OUT_SCOPE";
    public static final String IN_SCOPE  = "MODELBUS_IN_SCOPE";    
    
    boolean recursivelyIncludeSubelements = false;
    boolean doRestore = false;    
    boolean useScope = false;
    
    Collection inScope=null, outScope=null, inoutScope=null;
    
    //private IdTable idTable = new IdTable();
    private ModelManager modelManager = new ModelManager();

    
    public CopyRestoreFragmentMarshaler(Properties p) {
        recursivelyIncludeSubelements = p.getProperty(AdapterStub.PROP_recursivelyIncludeSubelements, "false").equals("true");
        doRestore = p.getProperty(AdapterStub.PROP_doRestore, "false").equals("true");
        useScope = p.getProperty(AdapterStub.PROP_useScope, "false").equals("true");
    }
    
    public void marshallScope(String scopeDirection, Collection model, SOAPElement topElem ) throws SOAPException {
        
        Collection wrappedModel = wrap(model, recursivelyIncludeSubelements);         
        if(scopeDirection.equals(INOUT_SCOPE)) {
            inoutScope = wrappedModel;
        } else if(scopeDirection.equals(IN_SCOPE)) {
            inScope = wrappedModel;
        } else if(scopeDirection.equals(OUT_SCOPE)) {
            outScope = wrappedModel;
        }
        
        String content;
        modelManager.getManagedModel().addAll(wrappedModel);
        content = modelManager.exportFragmentToXMI(wrappedModel);        
        
//        ModelSerializer ser = new ModelSerializer(idTable);
//        ser.option_encode_cross_resource_ref = false;
//        content = ser.serializeFragment(wrappedModel);

        
//        try {
//            XmiUtil.writeToFile(scopeDirection  +System.currentTimeMillis() +".xml", content);
//            System.out.println(scopeDirection + "\n" +content);
//        } catch (IOException e) {
//            e.printStackTrace();
//        }
        
        SOAPElement paramSoapElem = topElem.addChildElement(scopeDirection);        
        paramSoapElem.addTextNode(content);
    }
    
    public void unmarshallScope(SOAPElement topElem ) throws IOException, SOAPException {
        SOAPElement inScopeElem = SoapUtil.getChildByLocalName(topElem, IN_SCOPE);
        if(inScopeElem!=null) {
            unmarshallScope(IN_SCOPE, inScopeElem);
        }
        SOAPElement outScopeElem = SoapUtil.getChildByLocalName(topElem, OUT_SCOPE);
        if(outScopeElem!=null) {
            unmarshallScope(OUT_SCOPE, outScopeElem);
        }
        SOAPElement inoutScopeElem = SoapUtil.getChildByLocalName(topElem, INOUT_SCOPE);
        if(inoutScopeElem!=null) {
            unmarshallScope(INOUT_SCOPE, inoutScopeElem);
        }        
    }
    
    private void unmarshallScope(String scopeDirection, SOAPElement elem) throws  IOException, SOAPException {
        String content = elem.getValue();
        if(  scopeDirection.equals(IN_SCOPE) 
                || scopeDirection.equals(OUT_SCOPE)
                || (scopeDirection.equals(INOUT_SCOPE) && !doRestore)  ) {
            try {
                 // unmarshal only
                 Collection resultModel;
                 resultModel = modelManager.loadXMI(content);   
                 
//                 MBXmiResource r = new MBXmiResource(URI.createURI("scope"), idTable);
//                 ModelDeserializer deser = new ModelDeserializer(r);                 
//                 deser.deserialize(content);
//                 resultModel = deser.getCreatedModelElements();
                         
                 if(scopeDirection.equals(INOUT_SCOPE)) {
                     inoutScope = resultModel;
                 } else if(scopeDirection.equals(IN_SCOPE)) {
                     inScope = resultModel;
                 } else if(scopeDirection.equals(OUT_SCOPE)) {
                     outScope = resultModel;
                 }                 
                 
            } catch (SAXException e) {
                throw new SOAPException(e);
            } catch (XMIException e) {
                throw new SOAPException(e);
            }              
         } else {              
            try {
                // unmarshal and propagate update
                modelManager.mergeWithXMI(inoutScope, content);
                 
//                MBXmiResource r = new MBXmiResource(URI.createURI("scope"));
//                ModelDeserializer deser = new ModelDeserializer(r);               
//                deser.deserialize(content);
//                UpdaterByCopy u = new UpdaterByCopy(idTable, inoutScope
//                        , r.getIdTable(), deser.getCreatedModelElements());
//                u.update();
                
            } catch (SAXException e) {
                throw new SOAPException(e);
            } catch (XMIException e) {
                throw new SOAPException(e);
            }                     
         }               
    }
    
    
    /* (non-Javadoc)
     * @see org.eclipse.mddi.modelbus.adapter.infrastructure.transport.ws.marshal.ModelMarshaler#marshallModel(org.eclipse.mddi.modelbus.description.abstract_.Parameter, java.lang.Object, javax.xml.soap.SOAPElement)
     */
    public void marshalModel(Parameter p, Object value, SOAPElement elem) throws SOAPException, IOException {    
        String content = null;    
        Collection model = (Collection) value;
        
        if(useScope) {
            Collection wrappedModel = wrap(model, false);
            elem.setAttribute("xsi:type", "modelbus:ModelRef");   
            for(Iterator it = wrappedModel.iterator(); it.hasNext();) {
               EObject o = (EObject) it.next();
               String id = modelManager.getIdTable().getId(o);
               if(id==null) {
                   if(o==null) throw new RuntimeException("Parameter must be in scope. " + o);    
               }
               if(content==null) {
                 content = id;
               } else {
                 content = content +" " + id;
               }
            }
        } else {
            Collection wrappedModel = wrap(model, recursivelyIncludeSubelements);
            elem.setAttribute("xsi:type", "modelbus:Model");    
//            ModelSerializer ser = new ModelSerializer(idTable);
//            ser.option_encode_cross_resource_ref = false;
//            content = ser.serializeFragment(wrappedModel);
            
            modelManager.getManagedModel().addAll(wrappedModel);
            content = modelManager.exportFragmentToXMI(wrappedModel);            
        }
        
        elem.addTextNode(content);
    }   
    
    /* (non-Javadoc)
     * @see org.eclipse.mddi.modelbus.adapter.infrastructure.transport.ws.marshal.ModelMarshaler#unmarshallModel(org.eclipse.mddi.modelbus.description.abstract_.Parameter, javax.xml.soap.SOAPElement)
     */
    public Object unmarshalModel(Parameter p, SOAPElement elem) throws SOAPException, IOException {
        String content = elem.getValue();
        
        DirectionKind dir = p.getDirection();       
       
        if(useScope) {
            Collection resultModel = new Vector();
            // look up elements in the context
            StringTokenizer st = new StringTokenizer(content);
            while(st.hasMoreTokens()) {
              String id = st.nextToken();
              EObject o = modelManager.getIdTable().getModelElement(id);
              if(o==null) 
                  throw new RuntimeException("No element found id=" +id);
              resultModel.add(o);             
            }
            return unwrap(resultModel, false);
        } if(          dir.equals(DirectionKind.IN_LITERAL)
                    ||   dir.equals(DirectionKind.OUT_LITERAL)
                    || ( dir.equals(DirectionKind.INOUT_LITERAL) && !doRestore) ) {
             // unmarshal only
             try {
                 Collection resultModel;
                 resultModel = modelManager.loadXMI(content);
                 
//                 MBXmiResource r = new MBXmiResource(URI.createURI("scope"), idTable);
//                 ModelDeserializer deser = new ModelDeserializer(r);                 
//                 deser.deserialize(content);
//                 resultModel = deser.getCreatedElements();                
                    
                 
                 return unwrap(resultModel, recursivelyIncludeSubelements);
             } catch(XMIException e) {
                throw new SOAPException(e);  
             } catch(SAXException e) {
                throw new SOAPException(e);  
             }         
             
        } else {               
              // unmarshal and propagate update
              throw new RuntimeException("does not support now");

        }       
    }   
    
//    /**
//     * @return Returns the updateManager.
//     */
//    public ModelManager getModelManager() {
//        return modelManager;
//    }
//    
//    /**
//     * @param updateManager The updateManager to set.
//     */
//    public void setModelManager(ModelManager modelManager) {
//        this.modelManager = modelManager;
//    }


    
    /**
     * @return Returns the usesScope.
     */
    public boolean isUseScope() {
        return useScope;
    }
    /**
     * @return Returns the inoutScope.
     */
    public Collection getInoutScope() {
        return unwrap(inoutScope, recursivelyIncludeSubelements);  
    }
    /**
     * @return Returns the inScope.
     */
    public Collection getInScope() {
        return unwrap(inScope, recursivelyIncludeSubelements);         
    }
    /**
     * @return Returns the outScope.
     */
    public Collection getOutScope() {
        return unwrap(outScope, recursivelyIncludeSubelements);        
    }
    
    static Collection wrap(Collection src, boolean includesChildren) {
        if(src==null) return null;
        Collection result = ModelWrapper.wrap(src);
        if(includesChildren) {
           result = ModelUtil.flattenHirachicalCollection(result);
        }
        return result;         
    }
    
    
    static Collection unwrap(Collection src, boolean onlyTopElems) {
        if(src==null) return null;
        Collection result;
        if(onlyTopElems) {
          result = ModelUtil.getTopElemsInFragment(src);
        } else {
          result = src;
        }
        return  ModelWrapper.unwrap(result);        
    }

    

}
