/*
 * $Header: /home/cvspublic/jakarta-slide/proposals/tamino/src/store/org/apache/slide/store/tamino/tools/repairer/NamespaceConsistencyCheck.java,v 1.5 2004/12/15 16:56:02 pnever Exp $
 * $Revision: 1.5 $
 * $Date: 2004/12/15 16:56:02 $
 *
 * ====================================================================
 *
 * Copyright 1999-2004 The Apache Software Foundation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */


package org.apache.slide.store.tamino.tools.repairer;

import java.util.Enumeration;
import java.util.Iterator;
import java.util.Map;
import org.apache.slide.store.tamino.common.XDatastoreException;
import org.apache.slide.store.tamino.datastore.XPathFactory;
import org.apache.slide.store.tamino.jdomobjects.XDescriptors;
import org.apache.slide.store.tamino.jdomobjects.XDescriptorsUtil;
import org.apache.slide.store.tamino.jdomobjects.XUuri;
import org.apache.slide.structure.ObjectNode;
import org.apache.slide.util.XException;


/**
 ** @author    Hardy.Kiefer@softwareag.com
 ** @author    Peter.Nevermann@softwareag.com
 ** @version   $Revision: 1.5 $
 **/
public class NamespaceConsistencyCheck extends AbstractCheck implements RepairConstants {
    protected NamespaceConsistencyCheck(XTaminoClient taminoClient) throws XException {
        super(taminoClient, MSG_START_DIR_INCONSISTENCIES, MSG_DESCR_DIR_INCONSISTENCIES);
    }
    
    public void check() throws XException {
        Map allUuris;
        Iterator iter;
        XDescriptors desc;
        Map.Entry entry;
        String currentUuri;
        
        allUuris = taminoClient.getDescriptorsAccessor().getUurisMap(XPathFactory.uuris( taminoCollection )); // inoId -> uuri
        iter = allUuris.entrySet().iterator();
        while( iter.hasNext() ) {
            entry = (Map.Entry)iter.next();
            currentUuri = (String)entry.getValue();
            desc = taminoClient.getDescriptorsAccessor().readOneRwDescriptorsByUuri(currentUuri);
            checkReferences(desc, true);
            checkReferences(desc, false);
        }
    }
    
    /**
     * Method checkReferences
     *
     * @param    desc                a  XDescriptors
     * @param    parent              a  boolean
     *
     * @throws   XException
     *
     */
    private void checkReferences(XDescriptors desc, boolean parent) throws XException {
        Enumeration bindings;
        ObjectNode.Binding binding;
        String refUuri;
        XDescriptors ref;
        String backSegment;
        
        if (parent && XUuri.isStoreUuri(desc.getUuri())) {
            return;
        }
        
        bindings = XDescriptorsUtil.getBindings(desc, parent);
        while( bindings.hasMoreElements() ) {
            binding = (ObjectNode.Binding) bindings.nextElement();
            refUuri = binding.getUuri();
            try {
                ref = taminoClient.getDescriptorsAccessor().readOneRwDescriptorsByUuri(refUuri);
            } catch (XDatastoreException e) {
                // invalid uuri
                logAndApplyPatch(new RemoveReference(desc, refUuri, parent));
                continue;
            }
            backSegment = XDescriptorsUtil.refersTo(ref, desc.getUuri(), !parent);
            if (backSegment == null) {
                // TODO: what if the binding name is already used
                logAndApplyPatch(new AddReference(ref, desc, binding.getName(), !parent));
            } else if (!backSegment.equals(binding.getName())) {
                logAndApplyPatch(new FixNameMismatch(desc, binding.getName(), ref, backSegment, parent));
            }
        }
    }
    
    public static class FixNameMismatch extends Patch {
        XDescriptors desc;
        String segment;
        XDescriptors refDesc;
        String backSegment;
        boolean parent;
        
        public FixNameMismatch(XDescriptors desc, String segment, XDescriptors refDesc, String backSegment, boolean parent) {
            this.desc = desc;
            this.segment = segment;
            this.refDesc = refDesc;
            this.backSegment = backSegment;
            this.parent = parent;
        }
        
        public void log(XRepairLogWriter logWriter) {
            logWriter.println(TC_CHECK_DETAILS, MSG_FOUND_BINDING_NAME_MISSMATCH, new Object[]{desc.getUuri(), segment, refDesc.getUuri(), backSegment});
        }
        
        public void apply(XTaminoClient taminoClient) throws XException {
            XDescriptorsUtil.removeReference(desc, refDesc.getUuri(), parent);
            XDescriptorsUtil.removeReference(refDesc, desc.getUuri(), !parent);
            if (parent) {
                XDescriptorsUtil.addParentBinding(desc, refDesc, segment);
                XDescriptorsUtil.addChildBinding(refDesc, desc, segment);
            }
            else {
                XDescriptorsUtil.addChildBinding(desc, refDesc, segment);
                XDescriptorsUtil.addParentBinding(refDesc, desc, segment);
            }
            taminoClient.getDescriptorsAccessor().update(desc);
            taminoClient.getDescriptorsAccessor().update(refDesc);
        }
    }
    
    public static class AddReference extends Patch {
        private final XDescriptors desc;
        private final XDescriptors refDesc;
        private final String segment;
        private final boolean parent;
        
        public AddReference(XDescriptors desc, XDescriptors refDesc, String segment, boolean parent) {
            this.desc = desc;
            this.refDesc = refDesc;
            this.segment = segment;
            this.parent = parent;
        }
        
        public void apply(XTaminoClient taminoClient) throws XException {
            if (parent) {
                XDescriptorsUtil.addParentBinding(desc, refDesc, segment);
            } else {
                XDescriptorsUtil.addChildBinding(desc, refDesc, segment);
            }
            taminoClient.getDescriptorsAccessor().update(desc);
        }
        
        public void log(XRepairLogWriter logWriter) {
            logWriter.println(TC_CHECK_DETAILS, MSG_FOUND_UNREACHABLE_NODE, refDesc.getUuri());
        }
    }
    
    public static class RemoveReference extends Patch {
        private final XDescriptors desc;
        private final String refUuri;
        private final boolean parent;
        
        public RemoveReference(XDescriptors desc, String refUuri, boolean parent) {
            this.desc = desc;
            this.refUuri = refUuri;
            this.parent = parent;
        }
        
        public void apply(XTaminoClient taminoClient) throws XException {
            XDescriptorsUtil.removeReference(desc, refUuri, parent);
            taminoClient.getDescriptorsAccessor().update(desc);
        }
        
        public void log(XRepairLogWriter logWriter) {
            logWriter.println(TC_CHECK_DETAILS, MSG_FOUND_INVALID_REF, new String[]{ desc.getUuri(), refUuri });
        }
    }
}

